Reputation: 439
I have a question about extending my own Models eloquent.
In the project I am currently working on is table called modules
and it contains list of project modules, number of elements of that module, add date etc.
For example:
id = 1; name = 'users'; count = 120; date_add = '2007-05-05';
and this entity called users
corresponds to model User
(Table - users
) so that "count" it's number of Users
and to update count
we use script running every day (I know that it's not good way but... u know).
In that script is loop and inside that loop a lot of if statement (1 per module) and inside the if a single query with count. According to example it's similar to:
foreach($modules as $module) {
if($module['name'] == 'users') {
$count = old_and_bad_method_to_count('users', "state = 'on'");
}
}
function old_and_bad_method_to_count($table, $sql_cond) {}
So its look terrible.
I need to refactor that code a little bit, because it's use a dangerous function instead of Query/Builder or Eloquent/Model and looks bad.
I came up with an idea that I will use a Models and create Interface ElementsCountable
and all models that do not have an interface will use the Model::all()->count()
, and those with an interface will use the interface method:
foreach ($modules as $module) {
$className = $module->getModelName();
if($className) {
$modelInterfaces = class_implements($className);
if(isset($modelInterfaces[ElementsCountable::class])) {
/** @var ElementsCountable $className */
$count = $className::countModuleElements();
} else {
/** @var Model $className */
$count = $className::all()->count();
}
}
}
in method getModelName()
i use a const map array (table -> model) which I created, because a lot of models have custom table name.
But then I realize that will be a good way, but there is a few records in Modules
that use the same table, for example users_off
which use the same table as users
, but use other condition - state = 'off'
So it complicated things a little bit, and there is a right question: There is a good way to extends User
and add scope with condition on boot?
class UserOff extends User
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(function (Builder $builder) {
$builder->where('state', '=', 'off');
});
}
}
Because I have some concerns if this is a good solution. Because all method of that class NEED always that scope and how to prevent from method withoutGlobalScope()
and what about other complications?
Upvotes: 1
Views: 294
Reputation: 148
I think it's a good solution to create the UserOff
model with the additional global scope for this purpose.
I also think the solution I would want to implement would allow me to do something like
$count = $modules->sum(function ($module) {
$className = $module->getModelName();
return $className::modulesCount();
}
I would create an interface ModulesCountable
that mandates a modulesCount()
method on each of the models. The modulesCount()
method would return either the default count or whatever current implementation you have in countModuleElements()
.
If there are a lot of models I would probably use a trait DefaultModulesCount
for the default count, and maybe the custom version too eg. ElementsModuleCount
if that is consistent.
Upvotes: 1