Адаптер для 3 моделей с одинаковой структурой

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

Добрый день всем.

Не хватает знаний для решения вопроса.
И даже не знаю куда копать, но чувствую, что существует решение.

Есть 3 модели для трёх таблиц.
Пусть будут t1,t2,t3

Таблицы содержат поля:
t1.t1_name, t1.t1_something
t2.t2_name, t2.t2_something
t3.t3_name, t3.t3_something

И формат и структура данных в таблицах одинаковы.
Отличия лишь в префиксах имён полей.

Написал create,update логику для t1.
Тоже самое нужно сделать для двух других.
Но дублировать код не хочется. Да и корректировки потом придётся в носить во все методы всех контроллеров, моделей и т.п.
Ясно, что нужен некий адаптер/проводник для работы с моделями.

Как это сделать не знаю.

Какие существуют решения на этот счёт?
Даже не знаю в каком направлении двигаться.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение unknownby »

В этом случае вроде всё просто.
Пишешь базовый контроллер назовем его T

Код: Выделить всё

class T extends Controller
Описываешь всё внутри базового контроллера
определяешь protected метод для поиска модели findModel
Создаются потом контроллеры под три таблицы, которые наследуют всё от базового контроллера

Код: Выделить всё

class T1 extends T
Внутри каждого пишется свой метод по поиску модели

Код: Выделить всё

protected function findModel($id)
    {
        if (($model = T1::findOne($id)) !== null) {
            return $model;
        } else {
            throw new HttpException(404, 'The requested page does not exist.');
        }
    }
Внутри базового контроллера действия, которые используют метод поиска модели

Код: Выделить всё

public function actionUpdate($id)
    {
	$model = $this->findModel($id);

	if ($model->load(\Yii::$app->getRequest()->post()) && $model->save())
        {
            \Yii::$app->session->setFlash($this->flashClass, \Yii::t('main', 'flash.updateSuccess'));
	}

        return $this->render('update', [
            'model' => $model,
        ]);
    }
Если будут добавлены данные внутри модели, контроллеры не придется трогать. Однако если вдруг какая-то модель затребует что-то ещё, например, какое-нибудь действие, то придется писать внутри контроллера под конкретную модель.

Для actionIndex, когда используется T1Search, нужно добавлять protected переменную.
Внутри базового контроллера

Код: Выделить всё

protected $searchClassName;

public function init()
    {
        parent::init();

        if (empty($this->searchClassName)) {
            throw new \yii\web\BadRequestHttpException();
        }
    }
Вызов внутри базового контроллера в actionIndex

Код: Выделить всё

$searchModel  = new $this->searchClassName();
Внутри T1 контроллера

Код: Выделить всё

protected $searchClassName = 'app\\models\\T1Search';
Краткая инструкция :)
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение skynin »

-- Ясно, что нужен некий адаптер/проводник для работы с моделями.
-- Да и корректировки потом придётся в носить во все методы всех контроллеров, моделей и т.п.
если вы везде ссылаетесь
$model->t1_something

то чем поможет адаптер?
вам уже придется вносить изменения во все методы всех контроллеров, моделей и т.п. где вы ссылаетесь на конкретные атрибуты таблиц

Вам надо скорее делать обощенную модель, к которой можно ссылаться
$model->tn_something, во всех методах контролеров, моделей, вьюхах

тогда придется у нее переписать работы с атрибутами, заполнение из БД, и прочее
Для этого надо не бояться лезть в код фреймворка, чтобы понять его работу с моделями, и он не заметил таких подмен

либо, делается базовая модель, у которой __get, __set, __isset перекрыт
а от нее наследуются 3 модели с реальными
t1_name, t1.t1_something
копипасты моделей в этом случае не избежать.
хотя... можно косвенно обращаться внтури методов модели
$model->$tn_something
надо смотреть.
но, и в этом случае - в контролерах, вьюхах - $model->t1_something? ну все - переделывать придется :)

кстати из-за статических методов типа tableName() все равно придется наследоваться от обобщенной модели.

Еще способ вынести бизнес логику модели в поведения или трейты.
Но тоже, надо смотреть сколько и какой у вас
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

unknownby писал(а): 2020.08.27, 11:10 В этом случае вроде всё просто.
Пишешь базовый контроллер назовем его T

Код: Выделить всё

class T extends Controller
Описываешь всё внутри базового контроллера
определяешь protected метод для поиска модели findModel
Создаются потом контроллеры под три таблицы, которые наследуют всё от базового контроллера

Код: Выделить всё

class T1 extends T
Внутри каждого пишется свой метод по поиску модели

Код: Выделить всё

protected function findModel($id)
    {
        if (($model = T1::findOne($id)) !== null) {
            return $model;
        } else {
            throw new HttpException(404, 'The requested page does not exist.');
        }
    }
Внутри базового контроллера действия, которые используют метод поиска модели

Код: Выделить всё

public function actionUpdate($id)
    {
	$model = $this->findModel($id);

	if ($model->load(\Yii::$app->getRequest()->post()) && $model->save())
        {
            \Yii::$app->session->setFlash($this->flashClass, \Yii::t('main', 'flash.updateSuccess'));
	}

        return $this->render('update', [
            'model' => $model,
        ]);
    }
Если будут добавлены данные внутри модели, контроллеры не придется трогать. Однако если вдруг какая-то модель затребует что-то ещё, например, какое-нибудь действие, то придется писать внутри контроллера под конкретную модель.

Для actionIndex, когда используется T1Search, нужно добавлять protected переменную.
Внутри базового контроллера

Код: Выделить всё

protected $searchClassName;

public function init()
    {
        parent::init();

        if (empty($this->searchClassName)) {
            throw new \yii\web\BadRequestHttpException();
        }
    }
Вызов внутри базового контроллера в actionIndex

Код: Выделить всё

$searchModel  = new $this->searchClassName();
Внутри T1 контроллера

Код: Выделить всё

protected $searchClassName = 'app\\models\\T1Search';
Краткая инструкция :)
Спасибо за развёрнутость.
А как быть с моделями?
3 модели для таблиц есть.
И нужно также реализовать модель tableForm для заполнения данных в соответствующую таблицу.

Больше в этом проблема.
То есть tableForm модель должна принимать объект модели (например для t1) и
работать с полями этой самой t1 таблицы. Может быть есть какой-то паттерн, который принимает объект модели таблицы бд и работает с ней, используя универсальные методы?
Может методы в Yii есть, вроде classField(), которые динамически получают список полей модели таблицы в виде массива, и работают уже не с именами таблицы(читай свойствами модели), а с порядковыми элементами массива?
Ох и запутанно же я похоже написал :)
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

skynin писал(а): 2020.08.27, 11:59 -- Ясно, что нужен некий адаптер/проводник для работы с моделями.
-- Да и корректировки потом придётся в носить во все методы всех контроллеров, моделей и т.п.
если вы везде ссылаетесь
$model->t1_something

то чем поможет адаптер?
вам уже придется вносить изменения во все методы всех контроллеров, моделей и т.п. где вы ссылаетесь на конкретные атрибуты таблиц

Вам надо скорее делать обощенную модель, к которой можно ссылаться
$model->tn_something, во всех методах контролеров, моделей, вьюхах

тогда придется у нее переписать работы с атрибутами, заполнение из БД, и прочее
Для этого надо не бояться лезть в код фреймворка, чтобы понять его работу с моделями, и он не заметил таких подмен

либо, делается базовая модель, у которой __get, __set, __isset перекрыт
а от нее наследуются 3 модели с реальными
t1_name, t1.t1_something
копипасты моделей в этом случае не избежать.
хотя... можно косвенно обращаться внтури методов модели
$model->$tn_something
надо смотреть.
но, и в этом случае - в контролерах, вьюхах - $model->t1_something? ну все - переделывать придется :)

кстати из-за статических методов типа tableName() все равно придется наследоваться от обобщенной модели.

Еще способ вынести бизнес логику модели в поведения или трейты.
Но тоже, надо смотреть сколько и какой у вас
Проблема именно с логикой в модели.
В повторном использовании кода, из-за различий в префиксах полей таблиц.
Выше описал.
Пока на ум приходит лишь, задать одинаковые имена полям в во всех трёх таблицах. И в модель передавать объект любой таблицы.
Контроллеры придётся делать отдельные.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение skynin »

-- Пока на ум приходит лишь, задать одинаковые имена полям в во всех трёх таблицах
самое правильное решение :)
но мало ли, сколько на этой схеме основано другого кода

- И в модель передавать объект любой таблицы.
объект любой таблицы - это и есть модель.

Если у таблиц разница только в именах
то отличие будет только в том что возвращает метод tableName()
он статический.

Вы не сможете его перекрыть с уровня объекта.
Значит, делаете общую модель
и наследуютесь ради перекрытия одного этого метода.

Но еще интересней, если вы можете переименовать поля
и все одинаково, то зачем вам - 3 таблицы?
почему бы тогда не сделать - одну?
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

skynin писал(а): 2020.08.27, 14:01 Но еще интересней, если вы можете переименовать поля
и все одинаково, то зачем вам - 3 таблицы?
почему бы тогда не сделать - одну?
Это свойства статьи. Такие как категория, раздел и.т.п.
Я и сделал сначала их хранение в одной таблице. Nested sets.
Но в итоге посчитал, что лучше разделить, т.к. это путь к трудностям в будущем.
skynin писал(а): 2020.08.27, 14:01 объект любой таблицы - это и есть модель.
Конечно. Но я имел ввиду модель формы, общую для всех моделей таблиц.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение unknownby »

Drugpunker писал(а): 2020.08.27, 14:10
skynin писал(а): 2020.08.27, 14:01 Но еще интересней, если вы можете переименовать поля
и все одинаково, то зачем вам - 3 таблицы?
почему бы тогда не сделать - одну?
Это свойства статьи. Такие как категория, раздел и.т.п.
Я и сделал сначала их хранение в одной таблице. Nested sets.
Но в итоге посчитал, что лучше разделить, т.к. это путь к трудностям в будущем.
Можно ли узнать по подробнее про это? :)
Возможно тут всё намного проще, чем кажется ;)
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение skynin »

-- Это свойства статьи. Такие как категория, раздел и.т.п.
а зачем три таблицы для статей?

-- т.к. это путь к трудностям в будущем.
ну пока вам предстоит преодолеть трудности сейчас :)

конструкция то странная - три таблицы, с одинаковыми полями, с одинаковой логикой обработки, с одинаковой логикой отображения...

такое делают конечно, когда очень много данных например, вручную партиционируют, или какие-то архивы, где таблица - "за единцу времени"
и то, вопрос.

-- Nested sets.
то есть? у данных в таблицах вложенная зависимость?

-- Но я имел ввиду модель формы, общую для всех моделей таблиц.
которую вам надо тогда - обобщить.
выше написал

что нужно для разных названий колонок

но если можно и названия поменять, тогда наверняка и три таблицы не нужны.
и не нужен тогда этот головняк :)

Откуда Nested sets взялись, это да, непонятно
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

unknownby писал(а): 2020.08.27, 14:17
Drugpunker писал(а): 2020.08.27, 14:10
skynin писал(а): 2020.08.27, 14:01 Но еще интересней, если вы можете переименовать поля
и все одинаково, то зачем вам - 3 таблицы?
почему бы тогда не сделать - одну?
Это свойства статьи. Такие как категория, раздел и.т.п.
Я и сделал сначала их хранение в одной таблице. Nested sets.
Но в итоге посчитал, что лучше разделить, т.к. это путь к трудностям в будущем.
Можно ли узнать по подробнее про это? :)
Возможно тут всё намного проще, чем кажется ;)
Может быть.

Пишется статейка.
У неё есть свойства.
Свойство1
Свойство2
Свойство3.
Эти свойства выбираются в выпадающих списках формы, в соответствующих полях.
Старо как мир.
Сначала решил хранить их (свойства) деревом.
Да, удобно.
Но предвижу кучу лишнего кода, при фильтрации по этим свойствам, да и вобще при любых манипуляциях. Т.к. nested sets.

Вот и решил разбить их по таблицам.
В итоге пришёл к дублированию кода при создании и апдейте любого из этих свойств.
Общую модель формы для них сделал таки. Вроде работает.

Может действительно велосипед изобретаю...
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение unknownby »

Drugpunker писал(а): 2020.08.27, 15:36 Может быть.

Пишется статейка.
У неё есть свойства.
Свойство1
Свойство2
Свойство3.
Эти свойства выбираются в выпадающих списках формы, в соответствующих полях.
Старо как мир.
Сначала решил хранить их (свойства) деревом.
Да, удобно.
Но предвижу кучу лишнего кода, при фильтрации по этим свойствам, да и вобще при любых манипуляциях. Т.к. nested sets.

Вот и решил разбить их по таблицам.
В итоге пришёл к дублированию кода при создании и апдейте любого из этих свойств.
Общую модель формы для них сделал таки. Вроде работает.

Может действительно велосипед изобретаю...
омг, что же ты делаешь :D
Каким образом это решается:
1. Есть таблица со статьями (она уже есть у тебя)
2. Создается таблица со всеми свойствами (обычный справочник, ну или простыми словами будет выпадающий список составляться там)
3. Создается таблица, которая будет соединять в себе таблицу статьи с её свойствами.
Получается таблица вида

Код: Выделить всё

id news_id property_id
1       1        1
2       1        2
3       1        3
Сохранять в смежную таблицу при помощи связи manyToMany
Если не сталкивался, можешь посмотреть ТУТ
Или любой другой вариант

P.S.
Посмотри как выглядит это в бэке http://prntscr.com/u6un6r
А вот на фронте http://prntscr.com/u6uo1g
На сколько хватило моей фантазии :D
Последний раз редактировалось unknownby 2020.08.27, 15:46, всего редактировалось 2 раза.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

skynin писал(а): 2020.08.27, 14:20 -- Это свойства статьи. Такие как категория, раздел и.т.п.
а зачем три таблицы для статей?

но если можно и названия поменять, тогда наверняка и три таблицы не нужны.
и не нужен тогда этот головняк :)

Откуда Nested sets взялись, это да, непонятно
А как хранить свойства статей?
Выше написал.
Откуда Nested sets взялись?
Это ж удобно. Одна таблица. Несколько свойств в ней как деревья. И потомки этих деревьев хранятся как подкатегории.
Удобно вставлять, перемещать между собой, ну и хранить.
Но необъяснимо разонравился такой подход, потому что лишний код при чтении из бд появляется.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

unknownby писал(а): 2020.08.27, 15:43
Drugpunker писал(а): 2020.08.27, 15:36 Может быть.

Пишется статейка.
У неё есть свойства.
Свойство1
Свойство2
Свойство3.
Эти свойства выбираются в выпадающих списках формы, в соответствующих полях.
Старо как мир.
Сначала решил хранить их (свойства) деревом.
Да, удобно.
Но предвижу кучу лишнего кода, при фильтрации по этим свойствам, да и вобще при любых манипуляциях. Т.к. nested sets.

Вот и решил разбить их по таблицам.
В итоге пришёл к дублированию кода при создании и апдейте любого из этих свойств.
Общую модель формы для них сделал таки. Вроде работает.

Может действительно велосипед изобретаю...
омг, что же ты делаешь :D
Каким образом это решается:
1. Есть таблица со статьями (она уже есть у тебя)
2. Создается таблица со всеми свойствами (обычный справочник, ну или простыми словами будет выпадающий список составляться там)
3. Создается таблица, которая будет соединять в себе таблицу статьи с её свойствами.
Получается таблица вида

Код: Выделить всё

id news_id property_id
1       1        1
2       1        2
3       1        3
Сохранять в смежную таблицу при помощи связи manyToMany
Если не сталкивался, можешь посмотреть ТУТ
Или любой другой вариант

P.S.
Посмотри как выглядит это в бэке http://prntscr.com/u6un6r
А вот на фронте http://prntscr.com/u6uo1g
На сколько хватило моей фантазии :D
:D
У меня ж не связи хранить не получается.
А сами свойства.
К примеру, статья - это краски.
При написании статьи нужно выбрать свойства в выпадающих списках.
Свойства такие например:
Цвет (одна таблица)
Тип красок (акварель, гуашь) (другая таблица)
Не знаю там, вкус, (солёный, горький, невкусный) (третья таблица). :)

Хранить все эти свойства в одной таблице неправильно.
Вооот.

И при этом у этих таблиц структура и поля одинаковые.
И нужен некий адаптер, чтобы не дублировать код моделей формы.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение unknownby »

Drugpunker писал(а): 2020.08.27, 15:53 :D
У меня ж не связи хранить не получается.
А сами свойства.
К примеру, статья - это краски.
При написании статьи нужно выбрать свойства в выпадающих списках.
Свойства такие например:
Цвет (одна таблица)
Тип красок (акварель, гуашь) (другая таблица)
Не знаю там, вкус, (солёный, горький, невкусный) (третья таблица). :)

Хранить все эти свойства в одной таблице неправильно.
Вооот.
Если бы в этом был вопрос :D
Посмотри вот крутой табуляр, который тебе точно подойдет ;)
Нажимаем плюс. Выбираем слева свойство, а справа значение для него.
Вообще это уже реализуется чуток по другому :)
Я делал такое, может можно было и проще, но как есть.
Смотри скриншоты.
1. Тут характеристика http://prntscr.com/u6v2rm
2. Показатель http://prntscr.com/u6v35w при этом общий список выглядит так http://prntscr.com/u6v3gr
3. Страница товара, где идут характеристики с показателями http://prntscr.com/u6v422
:D
Ну и вот само применение этих вещей в фильтрах http://prntscr.com/u6v4zs

P.S.
Сама суть в том, чтобы использовать зависимость одного списка от другого. Выбрал слева плотность и тебе выдало пару значений, как на скриншоте на странице товара (пункт 3)
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение skynin »

Drugpunker писал(а): 2020.08.27, 15:45 Это ж удобно. Одна таблица. Несколько свойств в ней как деревья.
Drugpunker писал(а): 2020.08.27, 15:45 Но необъяснимо разонравился такой подход
но это ж удобно :D

Вобщем вам стоит почитать что-то про проектирование схемы БД, нормализацию и т.д.

Но, пока вам квадратные колеса удобны, а когда неудобны то вы их меняете на треугольные... то конечно не надо ничего читать и никого не слушайте!
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

Короче.
Пока сделал так.
Общая модель формы.
Создал в ней свойтво:

Код: Выделить всё

public $class_model;
При объявлении экземпляра модели, передаю в ней слаг.

Код: Выделить всё

$model = new MenuForm(['class_model' => MenuForm::COLORS_CLASS]);
В конструкторе модели определяю префикс.

Код: Выделить всё

public function __construct($config = [])
    {
        parent::__construct($config);

        switch ($this->class_model) {
            case self::COLORS_CLASS:
                $this->prefix = self::COLORS_PREFIX;
                break;
            case self::FORMAT_CLASS:
                $this->prefix = self::FORMAT_PREFIX;
                break;
            case self::ZHOPA_CLASS:
                $this->prefix = self::ZHOPA_PREFIX;
                break;
        }
В методах create/update модели
С данными объекта модели бд работаю так:

Код: Выделить всё

$model = new $this->class_model;
$model[$this->prefix.'name'] = $this->name;
$q = $this->class_model::find()->all();
$model->save();
Вроде прикольно получилось.
Одна форма ввода для трёх таблиц.
unknownby
Сообщения: 749
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение unknownby »

Drugpunker писал(а): 2020.08.27, 16:11 Вроде прикольно получилось.
Одна форма ввода для трёх таблиц.
Завтра появится еще три свойства, ещё три таблицы?
А через 10 лет еще появится 100 свойств, еще 100 таблиц?
Посмотри выше, я с картинками показал :D
Drugpunker
Сообщения: 187
Зарегистрирован: 2014.08.13, 19:44

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение Drugpunker »

skynin писал(а): 2020.08.27, 16:09 но это ж удобно :D

Вобщем вам стоит почитать что-то про проектирование схемы БД, нормализацию и т.д.

Но, пока вам квадратные колеса удобны, а когда неудобны то вы их меняете на треугольные... то конечно не надо ничего читать и никого не слушайте!
Вот даже интересно стало.
Раз уж Вы читали про нормализацию бд.

Нужно заполнить форму по данным о каком-то регионе планеты Земля.
Выбрать из списка
1.Море
2.Тигра
3 Яблоко

Как хранить в бд данные для вывода в список этих трёх пунктов?
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Адаптер для 3 моделей с одинаковой структурой

Сообщение skynin »

unknownby писал(а): 2020.08.27, 16:13 Завтра появится еще три свойства, ещё три таблицы?
Так человек же написал - он по приколу пишет.
Ему кажется прикольным - ну вот и пишет.

Как наприкалывается, так и займется делом :)
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
Ответить