Skip to content

(feature-request) Missing function to get all models by given setting #61

@wize-wiz

Description

@wize-wiz

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;
        });
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions