-
Notifications
You must be signed in to change notification settings - Fork 61
Description
Great work on this package.
I'm just missing a feature here to retrieve all models by given setting. Of all settings packages, this was one of the cleanest, so I implemented more or less a prototype version using a facade.
I believe the code below can be optimised, but it's enough to get the general idea. If you are interested I could start a PR.
I'm using a Facade (Settings) and implemented a single static method into the HasModelSettings trait.
Use case
I need to extract all models with a certain settings value, e.g. database version or revision. I wanted something simple as Settings::findAll('database.revision', '1.1') and retrieve all models with this value, filter the models I need e.g. Settings::findAll([User::class, Document::class], 'database.revision', '1.1').
This also includes for specific models as in User::findSetting('database.revision', '1.1') using the static method in the HasModelSettings trait.
<?php
/**
* Helper class for Facade
*/
namespace App\Helpers;
use Illuminate\Database\Eloquent\Relations\Relation;
use Glorand\Model\Settings\Models\ModelSettings;
class ModelSettingsHelper {
const CHUNK_RESULTS = 50;
/**
* Translate dot notation to arrow notation.
*
* @param $key
* @return string
*/
protected function keyDotToArrow($key) {
return str_replace('.', '->', $key);
}
/**
* Find models by setting.
*
* @param string $model
* @param string $key
* @param mixed $value
* @param bool $use_cursor
* @return Illuminate\Support\Collection
*/
public function find(string $model, string $key, $value, bool $use_cursor = false) {
$settings_table = app(ModelSettings::class)->getTable();
$key = $this->keyDotToArrow($key);
return $model
::join($settings_table, function($join) use($settings_table) {
$join
->on("{$settings_table}.model_id", '=', "users.id")
->where("{$settings_table}.model_type", '=', "user");
})
->where("{$settings_table}.settings->{$key}", $value)
->{$use_cursor ? 'cursor' : 'get'}();
}
/**
* Find all models by setting.
*
* @param array $models Optional
* @param string $key Key to search for.
* @param string $value Value to search for.
* @return Illuminate\Support\Collection
*/
public function findAll(...$spread) {
$models = null;
if(count($spread) === 3) {
$models = (array)array_shift($spread);
}
$key = $this->keyDotToArrow($spread[0]);
$query = ($SettingsModel = app(ModelSettings::class))
::where("{$SettingsModel->getTable()}.settings->{$key}", $spread[1]);
$mapped = [];
$query->chunk(static::CHUNK_RESULTS, function($settings) use (&$mapped, $models) {
foreach($settings as $setting) {
$model = Relation::getMorphedModel($setting->model_type);
if($models && !in_array($model, $models)) {
continue;
}
$mapped[$model][] = $setting->model_id;
}
});
return collect($mapped)->flatMap(function($ids, $model) {
return $model::findMany($ids);
});
}
}
/**
* Static method for HasModelSettings.
*/
public static function findSetting($key, $value) {
return Settings::find(self::class, $key, $value);
}
<?php
/**
* Regular simple facade.
*/
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class ModelSettings extends Facade {
public static function getFacadeAccessor() {
return 'settings';
}
}
And this should be registered in any available provider and in the config/app.php in aliases
// config/app.php
'aliases' => [
...
'Settings' => App\Facades\ModelSettings::class
];
/**
* In any register method of a provider, e.g. AppServiceProvider
*/
public function register() {
$this->app->bind('settings', function() {
return new ModelSettingsHelper;
});
}