Сохранить тэги из select2

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Закрыто
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Сохранить тэги из select2

Сообщение hollanditkzn »

Не получается сохранить тэги. Использую виджет kartik/select2. Сначало реализация, потом напишу что приходит.
Создал модель Tag.php

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

<?php
namespace app\models;

/**
 * This is the model class for table "tag".
 *
 * @property integer $id
 * @property string $name
 */
class Tag extends \yii\db\ActiveRecord
{

    public static function tableName()
    {
        return 'tag';
    }

    public function rules()
    {
        return [
            [['name'], 'required'],
            [['name'], 'string', 'max' => 50],
        ];
    }

    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'name' => 'Наименование',
        ];
    }
}
И к нему сделал crud. Затем создал модель ZakazTag.php

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

<?php

namespace app\models;

use Yii;

/**
 * This is the model class for table "zakaz_tag".
 *
 * @property integer $id
 * @property integer $zakaz_id
 * @property integer $tag_id
 */
class ZakazTag extends \yii\db\ActiveRecord
{

    public static function tableName()
    {
        return 'zakaz_tag';
    }
    public function rules()
    {
        return [
            [['zakaz_id', 'tag_id'], 'required'],
            [['zakaz_id', 'tag_id'], 'integer'],
        ];
    }

    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'zakaz_id' => 'Zakaz ID',
            'tag_id' => 'Tag ID',
        ];
    }

    public function getTag()
    {
        return $this->hasOne(Tag::className(), ['id' => 'tag_id']);
    }
}
И основная модель заказы Zakaz.php

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

namespace app\models;

use Yii;
use yii\helpers\ArrayHelper;
use yii\db\ActiveRecord;

class Zakaz extends ActiveRecord
{
...
    public $tags_array;

    public static function tableName()
    {
        return 'zakaz';
    }

    public function rules()
    {
        return [
          ...
          [['id_zakaz', ..], 'integer'],
            [['tags_array'], 'safe'],
           ...
        ];
    }

    public function attributeLabels()
    {
        return [
            'id_zakaz' => '№',
           ...
            'tags_array' => 'Тэги',
        ];
    }
    public function getZakazTag()
    {
        return $this->hasMany(ZakazTag::className(), ['zakaz_id' => 'id_zakaz']);
    }

    public function getTags()
    {
        return $this->hasMany(Tag::className(), ['id' => 'tag_id'])->via('zakazTag');
    }

    public function afterFind()
    {
        return $this->tags_array = $this->tags;//делаем чтобы в полях select2 отображался value, без него не будет отображаться 
    }
    public function afterSave($insert, $changedAttributes)
    {
        parent::afterSave($insert, $changedAttributes);

        $arr = ArrayHelper::map($this->tags, 'id', 'id');//Получаем данные тэга
        foreach ($this->tags_array as $one){
            if (!in_array($one, $arr)){//указываем присутствует в массиве данное значение
                $model = new ZakazTag();//если присутствует то мы его сохраняем его в моделе ZakazTag
                $model->zakaz_id = $this->id_zakaz;//Присваиваем id_zakaz
                $model->tag_id = $one;//Присваиваем id тэга который пришел
                $model->save();
            }
            if (isset($arr[$one])){//если присутствует данное значение в массиве то мы его перезапиываем
                unset($arr[$one]);
            }
        }
    }
}
И во вьюшке

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

<?= $form->field($model, 'tags_array')->widget(Select2::className(), [
                    'data' => ArrayHelper::map(Tag::find()->all(), 'id', 'name'),
                    'language' => 'ru',
                    'options' => [
                        'placeholder' => 'Выберите тэг',
                        'multiple' => true
                    ],
                    'pluginOptions' => [
                        'allowClear' => true,
                        'tags' => true,
                        'maximumInputLength' => 10,
                    ],
                ]);
        ?>
И у меня не сохраняет только реагирует ошибка вот на этот код

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

if (isset($arr[$one])){
и пишет llegal offset type in isset or empty
В post запросе приходит следующие данные в дебаге
'Zakaz' => [
'description' => 'тестовые кружки'
'number' => '50'
'information' => 'ааи'
'name' => 'Иван'
'phone' => '89503164233'
'email' => ''
'oplata' => '1 500'
'fact_oplata' => '25'
'srok' => '2017-07-26 12:10:00'
'status' => ''
'prioritet' => ''
'tags_array' => [
0 => '3'
1 => '1'
]
]
Если вар дампить то в переменной $one вот значение что отображается
object(app\models\Tag)[213]
private '_attributes' (yii\db\BaseActiveRecord) =>
array (size=2)
'id' => int 1
'name' => string 'Не берет номер' (length=26)
private '_oldAttributes' (yii\db\BaseActiveRecord) =>
array (size=2)
'id' => int 1
'name' => string 'Не берет номер' (length=26)
private '_related' (yii\db\BaseActiveRecord) =>
array (size=0)
empty
private '_errors' (yii\base\Model) => null
private '_validators' (yii\base\Model) => null
private '_scenario' (yii\base\Model) => string 'default' (length=7)
private '_events' (yii\base\Component) =>
array (size=0)
empty
private '_behaviors' (yii\base\Component) =>
array (size=0)
empty
Если $arr то вот array (size=1)
1 => int 1
Если $arr[$one], то там выходит ошибка Illegal offset type. Слишком много написал, но думаю что скорее всего это достаточно чтобы понять как сохранить тэги для профессионала. Я встал только на этом вопросе, потому что не могу сохранить это тэги
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Сохранить тэги из select2

Сообщение slo_nik »

Добрый день.
В документации сказано так:
Массивы (тип array) и объекты (тип object) не могут использоваться в качестве ключей. При подобном использовании будет генерироваться предупреждение: Недопустимый тип смещения (Illegal offset type).
У Вас, как я понимаю, в качестве ключа используется именно объект.
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

$one да это объект. Как в данном случае поступать?
slo_nik
Сообщения: 344
Зарегистрирован: 2013.10.07, 19:08

Re: Сохранить тэги из select2

Сообщение slo_nik »

hollanditkzn писал(а): 2017.08.22, 12:26 $one да это объект. Как в данном случае поступать?
Не использовать его в качестве ключа. Или использовать что-то типа $one->???
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

Раньше я делал $this->tags_array->id Не помогало, сейчас как Вы сказали сделал. Пробовал вставить в этих местах

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

public function afterSave($insert, $changedAttributes)
    {
        parent::afterSave($insert, $changedAttributes);

        $arr = ArrayHelper::map($this->tags, 'id', 'id');
        foreach ($this->tags_array as $one){
            if (!in_array($one, $arr)){
                $model = new ZakazTag();
                $model->zakaz_id = $this->id_zakaz;
                $model->tag_id = $one->id;
                $model->save();
            }
            if (isset($arr[$one->id])){
                unset($arr[$one->id]);
            }
        }
    }
Проходит, ошибка исчезла, но не сохраняет в бд
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Сохранить тэги из select2

Сообщение Dominus »

Тут проходит?

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

if (!in_array($one, $arr)){
//...
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

нет, не приходит
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Сохранить тэги из select2

Сообщение Dominus »

hollanditkzn писал(а): 2017.08.22, 16:01 нет, не приходит
Поэтому и не сохраняется.
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Сохранить тэги из select2

Сообщение Dominus »

Пробуйте так:

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

if (!in_array($one->id, $arr)){
http://php.net/manual/ru/function.in-array.php
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

Попробовал но тоже ничего не сохраняет

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

if (!in_array($one->id, $arr)){
                $model = new ZakazTag();
                $model->zakaz_id = $this->id_zakaz;
                $model->tag_id = $one->id;
                $model->save();
                echo '123';
            }
Не вышло 123, Сохраняет другие значение, только теги не сохраняет
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

Если без проверки, то есть просто in_array без восклицательного знака, нажать на сохранить, то у меня значение которая есть в базе его сохраняет, допустим в бд
id=10 | zakaz_id = 1423 | tag_id = 1
То после сохранение идет post
'tags_array' => [
0 => '3'
1 => '1'
]
И в бд 2 запись появляется
id=11 | zakaz_id = 1423 | tag_id = 1
То есть сохраняет нынешнее значение
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

И пробовал в контроллере указывать Yii::$app->requuest->post('Zakaz')['tags_arrray], что-то тоже не получается
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Сохранить тэги из select2

Сообщение Dominus »

Задампите $arr и $one.

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

$arr = ArrayHelper::map($this->tags, 'id', 'id');
        foreach ($this->tags_array as $one){
        \yii\helpers\VarDumper::dump($arr, 10, 1);
        \yii\helpers\VarDumper::dump($one, 10, 1);
        die;
            if (!in_array($one, $arr)){
                $model = new ZakazTag();
                $model->zakaz_id = $this->id_zakaz;
                $model->tag_id = $one->id;
                $model->save();
            }
            if (isset($arr[$one->id])){
                unset($arr[$one->id]);
            }
        }
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

[
1 => 1
] app\models\Tag#1
(
[yii\db\BaseActiveRecord:_attributes] => [
'id' => 1
'name' => 'Не берет номер'
]
[yii\db\BaseActiveRecord:_oldAttributes] => [
'id' => 1
'name' => 'Не берет номер'
]
[yii\db\BaseActiveRecord:_related] => []
[yii\base\Model:_errors] => null
[yii\base\Model:_validators] => null
[yii\base\Model:_scenario] => 'default'
[yii\base\Component:_events] => []
[yii\base\Component:_behaviors] => []
)
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

Там постоянно эти значение которые в бд хранятся.
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Сохранить тэги из select2

Сообщение Dominus »

Пример добавления тегов к посту:

app\models\Post

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

/**
 * Список тэгов
 * @var array
 */
    protected $tags = [];

//...

/**
 * @inheritdoc
 */
    public function rules()
    {
        return [
           //...
            [['tags'], 'safe'],
        ];
    }
    
//...
 
/**
 * Действия после сохранения поста
 * @inheritdoc
 */
public function afterSave($insert, $changedAttributes)
    {
        if (is_array($this->tags) && !empty($this->tags)) {
            TagPost::deleteAll(['post_id' => $this->id]); // Удаляем все теги у поста
            $values = [];
            foreach ($this->tags as $id) {
                $values[] = [$this->id, $id];
            }
            // Добавляем новые теги к посту
            self::getDb()->createCommand()
                ->batchInsert(TagPost::tableName(), ['post_id', 'tag_id'], $values)->execute();
        }
        parent::afterSave($insert, $changedAttributes);
    }
миграция промежуточной таблицы (у вас zakaz_tag) должна выглядеть следующим образом.

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

/**
  * Table relations Tag Post
  */
  $this->createTable('{{%tag_post}}', [
     'tag_id' => $this->integer()->comment('ID Tag'),
     'post_id' => $this->integer()->comment('ID Post'),
  ], $tableOptions);

  $this->createIndex('idx_tag', '{{%tag_post}}', 'tag_id');
  $this->addForeignKey(
      'FK_tag_post', '{{%tag_post}}', 'tag_id', '{{%tags}}', 'id'
  );
  $this->createIndex('idx_post', '{{%tag_post}}', 'post_id');
  $this->addForeignKey(
      'FK_post_tag', '{{%tag_post}}', 'post_id', '{{%post}}', 'id'
   );
То есть id в промежуточной таблице zakaz_tag ненужно.
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Сохранить тэги из select2

Сообщение Dominus »

Модель промежуточной таблицы выглядит так:

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

/**
 * This is the model class for table "{{%tag_post}}".
 *
 * @property integer $tag_id
 * @property integer $post_id
 *
 * @property Post $post
 * @property Tags $tag
 */
class TagPost extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%tag_post}}';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['tag_id', 'post_id'], 'integer'],
            [['post_id'], 'exist', 'skipOnError' => true, 'targetClass' => Post::className(), 'targetAttribute' => ['post_id' => 'id']],
            [['tag_id'], 'exist', 'skipOnError' => true, 'targetClass' => Tags::className(), 'targetAttribute' => ['tag_id' => 'id']],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'tag_id' => 'ID Tag',
            'post_id' => 'ID Post',
        ];
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getPost()
    {
        return $this->hasOne(Post::className(), ['id' => 'post_id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTag()
    {
        return $this->hasOne(Tags::className(), ['id' => 'tag_id']);
    }
}
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
Аватара пользователя
Dominus
Сообщения: 892
Зарегистрирован: 2013.03.14, 21:27
Откуда: Россия, Иваново
Контактная информация:

Re: Сохранить тэги из select2

Сообщение Dominus »

Контроллер:

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

//...
public function actionCreate()
    {
        $model = new Post();

        if ($model->load(Yii::$app->request->post()) && $model->save()) {            
            return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('create', [
            'model' => $model,            
            'tags' => Tags::find()->all(),
        ]);
    }

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

        if ($model->load(Yii::$app->request->post()) && $model->save()) {
                return $this->redirect(['view', 'id' => $model->id]);
        }
        return $this->render('update', [
            'model' => $model,           
            'tags' => Tags::find()->all(),
        ]);
    }
//...    
Ну и вид формы до кучи:

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

//...
<?= $form->field($model, 'tags')->listBox(
        ArrayHelper::map($tags, 'id', 'title'),
        [
            'multiple' => true,
            'size' => 10,
            'encode' => false,
        ]
    ) ?>
//...
Вместо стандартного listBox подключаете свой, Select2
Не спорь с дураком, иначе окружающие не правильно поймут кто из вас дурак!
hollanditkzn
Сообщения: 95
Зарегистрирован: 2017.03.28, 17:37

Re: Сохранить тэги из select2

Сообщение hollanditkzn »

Спасибо, за помощь, я просто нашел более удобный для меня способов, когда понял что запросы идут так
Zakaz [
'tags_array' => [
0 => '3'
1 => '1'
2 => '2'
]
]
И в инете нашел как можно брать из поста такие значение

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

Yii::$app->request->post('Zakaz')['tags_array']
И снес afterSave и все в контроллер перенес и получился у меня в контроллере вот это

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

if ($model->load(Yii::$app->request->post()) && $client->load(Yii::$app->request->post())) {
$arr = ArrayHelper::map($model->tags, 'id', 'id');
                    foreach (Yii::$app->request->post('Zakaz')['tags_array'] as $one){
                        if (!in_array($one, $arr)){
                            $tag = new ZakazTag();
                            $tag->zakaz_id = $id;
                            $tag->tag_id = $one;
                            $tag->save();
                        }
                        if (isset($arr[$one])){
                            unset($arr[$one]);
                        }
                    }
                    ZakazTag::deleteAll(['tag_id' => $arr]);
;
}
Не описываю весь контроллер, но примерно логика понятна
А за помощь спасибо, просто этот вариант быстрее для моего восприятие и понятно, конечно контроллер громоздкий у меня, но все равно этот вариант работает, а другие варианты надо разбираться почему не сохраняется по данному массиву
Закрыто