На примере будет показано создание тегов для Shopaholic, но подобное можно повторить для поставщиков, серий продуктов и т.д. Можно использовать как угодно где списки нужно хранить в отдельных таблицах. Нужно только заменить название плагина и заголовков 🙂
1) Запускаем консоль и создаем плагин, модель и контроллер.
php artisan create:plugin Samata.Tags
php artisan create:model Samata.Tags Tag
php artisan create:controller Samata.Tags Tags
2) В файл миграции записываем:
public function up()
{
if (!Schema::hasTable('samata_tags_tags')) {
Schema::create('samata_tags_tags', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name');
$table->string('slug');
});
}
if (!Schema::hasTable('samata_tags_products')) {
Schema::create('samata_tags_products', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('product_id')->unsigned();
$table->integer('tag_id')->unsigned();
$table->primary(['product_id', 'tag_id']);
});
}
}
public function down()
{
Schema::dropIfExists('samata_tags_tags');
Schema::dropIfExists('samata_tags_products');
}
То есть мы создаем 2 таблицы, где:
samata_tags_tags будет хранить список значений наших тегов с колонкой slug чтобы потом создать страницу наших тегов.
samata_tags_products
мы будем записывать связь тега и товара через relation.
В version.yaml записываем новую версию и подключаем файл создания наших таблиц. Запускаем плагин
php artisan october:up
ОК. Плагин запустился, таблицы создались.
3) Давайте запишем ссылку на список с тегами в меню магазина.
В шапке плагина сразу допишем:
use Event;
use Lovata\Shopaholic\Models\Product;
use Lovata\Shopaholic\Controllers\Products;
use Samata\Tags\Models\Tag;
В boot() нашего плагина пишем:
Event::listen('backend.menu.extendItems', function($manager) {
$manager->addSideMenuItems('Lovata.Shopaholic', 'shopaholic-menu-main', [
'tags' => [
'code' => 'tags',
'label' => 'Материалы',
'icon' => 'icon-tags',
'url' => Backend::url('samata/tags/tags'),
'order' => 550,
],
]);
});
Пункт меня добавился в подменю магазина, но для того чтобы показать контроллеру его новое место редактируем его и заменяем строчку BackendMenu::setContext на
BackendMenu::setContext('Lovata.Shopaholic', 'shopaholic-menu-main', 'tags');
4) Оформляем внешний вид страницы тегов и формы добавления/редактирования (columns и fields) в папке модели. Хочу заметить что я в базу не вставлял timestamps, поэтому в модели добавляем строчку:
public $timestamps = false;
protected $fillable = ['name'];
Ну и пока мы в модели сразу же запишем (чтобы при импорте автоматически генерировался слаг):
public function beforeCreate()
{
$this->slug = Str::slug($this->name);
}
use Str; в шапку!
Отлично! Теперь мы можем создавать теги вручную.
5) Давайте добавим новое поле в форму товара. Для этого в boot плагина пишем:
Event::listen('backend.form.extendFields', function($widget) {
if (!$widget->getController() instanceof Products || $widget->isNested || $widget->alias != 'form') {
return;
}
if (!$widget->model instanceof Product) {
return;
}
$widget->addTabFields([
'tags' => [
'label' => 'Теги',
'type' => 'taglist',
'mode' => 'relation',
'tab' => 'Данные',
'span' => 'auto'
],
]);
});
Product::extend(function($model) {
$model->belongsToMany['tags'] = [
'Samata\Tags\Models\Tag',
'table' => 'samata_tags_products'
];
});
Супер! У товара появилось новое поле "Теги". Вручную все работает и можно пользоваться.
6) Нам вручную товары добавлять не хочется, поэтому допишем возможность импорта тегов через XML.
Здесь мы научились добавлять новые поля в импорт shopaholic.
Расширим список полей в настройках импорта указав новое поле "Теги".
Event::listen('shopaholic.product.extend_xml_import_fields', function() {
$fields = [
'tags' => 'Теги',
];
return $fields;
});
Так как в самой таблице товара у нас тегов нет, они в отдельной таблице, нам в boot плагина нужно еще дописать вот что:
Event::listen('model.afterImport', function($obModel, $arImportData) {
$product_external_id = $arImportData['external_id'];
$product = Product::where('external_id', $product_external_id)->first();
if(!empty($product)) {
$tags = array_get($arImportData, 'tags');
$tags = explode(', ', $tags);
foreach($tags as $tag) {
$item = Tag::firstOrCreate(['name' => $tag]);
$tag_ids[] = $item->id;
}
$product->tags()->sync($tag_ids);
}
});
В данном примере теги в XML должны приходить через запятую.
Здесь после импорта мы:
- проверяем существует ли уже тег, если нет, то создаем его
- записываем в таблицу samata_tags_products id товара и id тега.
А давайте в нашу модель еще запишем:
public $belongsToMany= [
'product' => [
'Lovata\Shopaholic\Models\Product',
'table' => 'samata_tags_products'
]
];
😉
Вообще функция sync очень крутая. Она добавляет, редактирует и удаляет записи автоматически. К примеру если мы удалим тег, то он удалит записи с этой таблицей где участвовал этот тег. И не будет мусора.
Идем в настройки xml, там уже лежит новое поле в настройках, импорт работает! 🙂
Мой блог об OctoberCMS