Laravel - Как динамически разрешить экземпляр модели с другим пространством имен? - PullRequest
0 голосов
/ 06 июня 2019

tldr:

Как вы динамически получаете экземпляр модели только по имени таблицы БД?

Что вы получите по запросу:

  • ID модели
  • имя таблицы модели (она постоянно меняется!)

Чего вы не знаете:

  • Пространство имен модели

Более подробное объяснение:

У меня есть система отчетности, которую пользователи могут использовать для сообщения чего-либо. Для каждого отчета отправляется идентификатор и имя таблицы.

До сих пор каждая модель находилась под пространством имен App\*. Однако, поскольку мой проект слишком большой, мне нужно было разбить некоторый код на Modules\*

Вот пример того, как отчет сохраняется в базе данных:

Пример:

Запрос содержит правила:

public function rules()
{
    return [
        'id' => 'required|string',
        'type' => 'required|in:users,comments,offer_reviews, ......',
        'reason' => 'required|string',
        'meta' => 'nullable|array',
        'meta.*' => 'string|max:300'
    ];
}

В базе данных мы сохраняем данные в:

id  reportable_type            ...
1   App\User                   ...
4   Modules\Review\OfferReview ...

Как бы вы динамически создали экземпляр модели, когда вы просто знаете имя таблицы базы данных, например offer_reviews?

Есть одно решение, которое приходит мне в голову, однако я не уверен, добавляет ли оно больше проблем безопасности. Что если пользователь отправит полное пространство имен + имя класса? При этом я сразу знаю, где разрешить экземпляр.

Посмотрите, что я сейчас делаю

(до перехода на модули)

// В моем контроллере

class ReportController extends Controller
{
    /**
     * Stores the report in DB.
     */
    public function store(StoreReportRequest $request)
    {
        $model = $request->getModel();

        $model->report([
            'reason' => $request->reason,
            'meta' => $request->meta
        ], auth()->user());

        return response()->json(['status' => 'Submitted'], 201);
    }
}

// в StoreReportRequest

/**
 * Gets the Model dynamically.
 * If not found we throw an error
 * @return \App\Model
 */
public function getModel()
{
    return get_model($this->type)
                ->findOrFail(\Hashids::decode($this->id)[0]);
}

// в помощниках

/**
 * Gets me the model of a table name.
 * @param  String $table Has to be the name of a table of Database
 * @return Eloquent       The model itself
 */
function get_model($table)
{
    if (Schema::hasTable(strtolower($table))) {
        return resolve('App\\' . Str::studly(Str::singular($table)));
    }
    throw new TableNotFound;
}

1 Ответ

0 голосов
/ 07 июня 2019

Я не знаю, есть ли лучшее решение, но вот, пожалуйста. Мой код ищет метод с пространством имен, когда он не найден, мы используем App\ в качестве пространства имен.

Может быть, этот код кому-нибудь поможет:)

class StoreReportRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'id' => 'required|string',
            'type' => 'required|in:mc_messages,profile_tweets,food,users,comments,offer_reviews,user_reviews',
            'reason' => 'required|string',
            'meta' => 'nullable|array',
            'meta.*' => 'string|max:300'
        ];
    }

    /**
     * Gets the Model dynamically.
     * If not found we throw an error
     * @return \App\Model
     */
    public function getModel()
    {
        $namespace = $this->getNamespace();

        return $this->resolveModel($namespace);
    }

    protected function getNamespace(): string
    {
        $method = $this->typeToMethod();

        if (method_exists($this, $method)) {
            return $this->$method();
        }
        return 'App\\';
    }

    protected function typeToMethod(): string
    {
        return  'get' . \Str::studly(\Str::singular($this->type)) . 'Namespace';
    }

    protected function resolveModel(string $namespace)
    {
        return get_model($this->type, $namespace)
            ->findOrFail(\Hashids::decode($this->id)[0]);
    }

    protected function getOfferReviewNamespace(): string
    {
        return 'Modules\Review\Entities\\';
    }

    protected function getUserReviewNamespace(): string
    {
        return 'Modules\Review\Entities\\';
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...