Open Xety opened 11 months ago
Not yet, but I think it'll be possible with version 11.
@Xety took another look at this, this is going to be considerably more difficult than I thought. I'll pen it for an 11.1 release and work on it in the background. I think I need to essentially create solutions for each type of relation, rather than eloquence feature.
Hey, I have tested some things about this and i found something interesting. I'm using a Model Pivot like this one :
<?php
namespace App\Models;
use Eloquence\Behaviours\CountCache\Countable;
use Illuminate\Database\Eloquent\Relations\Pivot;
class MaterialPart extends Pivot
{
use Countable;
/**
* Return the count cache configuration.
*
* @return array
*/
public function countCaches(): array
{
return [
[
'model' => Material::class,
'field' => 'part_count',
'foreignKey' => 'material_id',
'key' => 'id'
],
[
'model' => Part::class,
'field' => 'material_count',
'foreignKey' => 'part_id',
'key' => 'id'
]
];
}
}
So my Materials can have many Parts, and a Parts can have many Materials (belongsToMany). In Material model :
/**
* Get the parts for the material.
*
* @return BelongsToMany
*/
public function parts(): BelongsToMany
{
return $this->belongsToMany(Part::class)
->using(MaterialPart::class);
}
In Part Model :
/**
* Get the materials for the part.
*
* @return BelongsToMany
*/
public function materials(): BelongsToMany
{
return $this->belongsToMany(Material::class)
->using(MaterialPart::class);
}
With that config, it work pretty well when adding a row; when i create a Part, with 2 selected Materials, both Materials has 1 Part each, and the Part has 2 Materials. If I add another Part with the same materials the countcache work pretty well :
My Parts
My Materials
My Pivot Table
The problem come when you delete a Part or a Material, the countcache isn't updated.
Exemple, if I delete the Part test2
, the Part count of the material BMP1
won't be updated and will stay at 2 instead of 1. I think there's something wrong about the observer when deleting (event not triggered ?)
EDIT : I found the solution (maybe not the most optimized, but it work)
I have setup an Observer (and registered them) for each Model :
<?php
namespace App\Observers;
use Illuminate\Support\Facades\Auth;
use App\Models\Part;
class PartObserver
{
public function deleting(Part $part): void
{
$materials = $part->materials;
foreach ($materials as $material) {
$material->parts()->detach($part->getKey());
}
}
}
<?php
namespace App\Observers;
use Illuminate\Support\Facades\Auth;
use App\Models\Material;
class MaterialObserver
{
public function deleting(Material $material): void
{
$parts = $material->parts;
foreach ($parts as $part) {
$part->materials()->detach($material->getKey());
}
}
}
So each time you delete a Part, the event deleting
will be trrigered and for each material that was assigned to the Part, you detach them from the Part and it will trigger the countcache. Of course it work also when you delete a Material.
This is insane wtf.
@Xety I've just released v11 - did you want to test and see if it will work "out of the box"? V11 works directly with relationship objects, making it much easier to do aggregate counts.
@Xety - see comment above.
@Xety - see comment above.
Hey, sorry I was very busy in the last couple of weeks. I will try it soon.
@Xety - see comment above.
Hey, sorry I was very busy in the last couple of weeks. I will try it soon.
All good - did you get a chance?
@kirkbushell Hey, sorry for the late reply, I was busy IRL and needed to upgrade to Laravel11 too to test your package, so it required some work.
Well, I have tested it and it seems like I found an alternative to the old system. The only thing i changed was in the Pivot model.
In Pivot MaterialPart.php
<?php
namespace BDS\Models;
use Eloquence\Behaviours\CountCache\CountedBy;
use Eloquence\Behaviours\CountCache\HasCounts;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;
class MaterialPart extends Pivot
{
use HasCounts;
// BEFORE
/**
* Return the count cache configuration.
*
* @return array
*/
/*public function countCaches(): array
{
return [
[
'model' => Material::class,
'field' => 'part_count',
'foreignKey' => 'material_id',
'key' => 'id'
],
[
'model' => Part::class,
'field' => 'material_count',
'foreignKey' => 'part_id',
'key' => 'id'
]
];
}*/
// AFTER
#[CountedBy(as: 'part_count')]
public function material(): BelongsTo
{
return $this->belongsTo(Material::class);
}
#[CountedBy(as: 'material_count')]
public function part(): BelongsTo
{
return $this->belongsTo(Part::class);
}
}
In model Part.php
public function materials(): BelongsToMany
{
return $this->belongsToMany(Material::class)
->using(MaterialPart::class)
->withTimestamps();
}
In model Material.php
public function parts(): BelongsToMany
{
return $this->belongsToMany(Part::class)
->using(MaterialPart::class);
}
I still have my observers too :
MaterialObserver.php
<?php
namespace BDS\Observers;
use BDS\Models\Material;
class MaterialObserver
{
/**
* Handle the "deleting" event.
*/
public function deleting(Material $material): void
{
$parts = $material->parts;
foreach ($parts as $part) {
$part->materials()->detach($material->getKey());
}
}
}
MaterialObserver.php
<?php
namespace BDS\Observers;
use BDS\Models\Part;
class PartObserver
{
/**
* Handle the "deleting" event.
*/
public function deleting(Part $part): void
{
$materials = $part->materials;
foreach ($materials as $material) {
$material->parts()->detach($part->getKey());
}
}
}
Looks like everythings work well again, if you can make some more tests to confirm it.
@Xety Sorry, I require clarification - are you saying the count cache is working even with BelongsToMany relationships? Are changes required as part of Eloquence?
@kirkbushell With this setup, yes count cache is working with BelongsToMany relationships. No change required if you setup a Pivot model with 2 belongsTo relationships.
@kirkbushell With this setup, yes count cache is working with BelongsToMany relationships. No change required if you setup a Pivot model with 2 belongsTo relationships.
Ah, right okay - so yeah some work needs to be done on Eloquence to support that. Thanks :)
@kirkbushell Well yeah, the best way would be to have something like that without Pivot model :
#[CountedBy(as: 'part_count')]
public function materials(): BelongsToMany
{
return $this->belongsToMany(Material::class);
}
#[CountedBy(as: 'material_count')]
public function parts(): BelongsToMany
{
return $this->belongsToMany(Part::class);
}
But at least i have something working until the official support.
Hello,
Is there a way to do a countcache with a
BelongsToMany
relationship with a pivot table ? There's no info in the doc