-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CountCache on BelongsToMany #106
Comments
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, <?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). /**
* 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 : The problem come when you delete a Part or a Material, the countcache isn't updated. 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 |
@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. |
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 <?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 public function materials(): BelongsToMany
{
return $this->belongsToMany(Material::class)
->using(MaterialPart::class)
->withTimestamps();
} In model public function parts(): BelongsToMany
{
return $this->belongsToMany(Part::class)
->using(MaterialPart::class);
} I still have my observers too :
<?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());
}
}
}
<?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. |
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 docThe text was updated successfully, but these errors were encountered: