Работа со связями моделей в Yii2 на примере каталога

Сначала хотел провести вебинар по связям ActiveRecord-моделей в Yii2 на основе урока о терии баз данных, осветив несколько тем из документации. Но получилась бы куча «воды» без практики. Так что решил показать на примере разработки каталога для интернет-магазина из реальной жизни:

Открыть на YouTube | Исходники примера

Приглашаю на следующие видеоуроки. Анонс и ссылку на эфир, как обычно, пришлю в отдельной рассылке по вебинарам:

И задавайте вопросы в комментариях. Заранее спасибо и до встречи в эфире!

Комментарии

 

Макс

Димон, готовь курс по Yii2, тебе удается всё грамотно и понятно объяснять, а те курсы которые существуют явно нет то, миру необходим курс от профи =)

Ответить

 

Алекс

Да, обсуждалось это на вебинаре. Дмитрий высказал мысль, что прологом к такому курсу будет ликбез по ООП. Считаю это неправильным. Такой подход превратит (ну может не превратит, но приблизит) к уже существующим бездарным. Не нужно тратить на это время. Тем, кому нужен Yii уже следовало бы изучить ООП. Если не изучили - материала как блох на собаке.

Ответить

 

Дмитрий Елисеев

> Тем, кому нужен Yii уже следовало бы изучить ООП.

А тем, кто изучил ООП, уже не пригодится курс ни по какому фреймворку.

Я под ООП имею в виду всю экосистему принципов, паттернов, антипаттернов, метрик технического и визуального качества кода. Применения принципов и паттернов по назначению именно как средств уменьшения сложности. То есть всех составляющих осознанного объектно-ориентированного мышления.

Это не просто ликбез про синтаксис, о котором говорите. Если напишете слово class и скинете в него свои процедуры (по требованию фреймворка или моды), то это никак не сделает вас ОО-программистом. А псевдоООПшного кода кругом ещё больше, чем упомянутых материалов.

Ответить

 

Алекс

И все же позволю себе не согласиться.

Что значит "изучить"? Год назад я начинал с c# (в отличии от PHP, си шарп чисто ООП язык). Кроме того, прочел пару книг по паттернам. В частности "Паттерны проектирования" Фрименов, и "PHP объекты, шаблоны и методики". И я как раз в той стадии, когда "уже Не, но еще и НЕ". Так вот, теория это одно, а практический разбор фреймворка, да еще и от такого хорошего специалиста и учителя - это совсем другое. Так что с фразой "кто изучил ООП, уже не пригодится курс ни по какому фреймворку" не согласен категорически.

Ответить

 

Сергей

Спасибо.
Как раз то что искал по поводу many-to-many связей. Делаю мультикатегории и не мог найти как это реорганизовывается на фреймворке, так что пример с тегами помог.

Добавлю что в миграциях, если выполняется более одного действия (создание таблицы и внешнего ключа или создание двух таблиц) в методе up() документация рекомендует использовать safeUp() для того чтобы если какое то действие зафейлится, то остальные действия откатятся. Может кому будет полезно.

И еще, Дмитрий, я не совсем понял за курсы. Вы проводите какие-то курсы по ООП, фреймворку или берете кого-то в ученики? Как можно попасть на обучение?

Ответить

 

Дмитрий Елисеев

MySQL поддерживает откат транзакций только для данных, так как автоматически коммитит транзакции при изменении таблиц или полей. Так что для неё safeUp бесполезен.

Ответить

 

Дмитрий Елисеев

Групповых курсов пока не веду. Только репетиторствую, когда просят. Напишите на почту или в Контакты.

Ответить

 

Денис

Было сказано: "А тем, кто изучил ООП, уже не пригодится курс ни по какому фреймворку"
Дмитрий, не слушаейте никого, делайте курсы для новичков с ликбезом по ООП !

Ответить

 

Яромир

Сразу видно психологию школоты - никого не слушайте, а только меня слушайте. Книги читай, школяр!

Ответить

 

Сергей

Привет. Подскажи плз какой дистрибутив linux лучше всего подходит для веб разработки по твоим предпочтениям?

Ответить

 

Дмитрий Елисеев

Стандартный стек Apache/Nginx, PHP и MySQL везде есть (а где нет - собирается из исходников), так что без разницы.

Ответить

 

Сергей

Я имел ввиду операционную систему на ядре линукс какую выбрать лучше (убунту, минт ....), может я не так выразился, вроде согласно википедии дистрибутив линукса и ОС это одни и те же вещи.

Спасибо за твои старания, изучении yii2 с твоими уроками стало намного проще!

Ответить

 

Дмитрий Елисеев

Ну я и говорю, что на любом Линуксе PHP есть, так что без разницы.

Ответить

 

Денис

Ubuntu desktop operating system powers millions of PCs and laptops around the world :)

Ответить

 

Сергей

Хотелось бы иметь последнии версии php7 и mysql 5.7, но я так понял в линуксе есть сборки lamp и xampp и они еще на старых версиях

Ответить

 

Денис

Для обучения тебе php>5.6 и mariadb 5.5 хватит надолго. А потом сам разберешься. Недорогого хостинга с поддержкой php 7 нужно ещё поискать). Сборки типа xamp проще ставятся, но для обучения я бы посоветовал ставить все отдельно, чтобы отличать хотябы что такое php от sql ))))

Ответить

 

Сергей

Не понял с чего ты взял, что я не отличаю php от sql?

Ответить

 

Aleksandr

Сергей, я так же как и Денис решил, что вы только собираетесь заняться обучением. Про линукс. На сервера чаще ставят серверный вариант Debian / Ubuntu / CentOS. В принципе, на начальном этапе линукс Вам не понадобится. Для разработки чаще используют виртуалку внутри виндоуса. Серверная и десктопная версия линукса отличается только набором программ для визуальной части, для серверов его вырезают. Самый популярный дистр на базе Убунту (та на базе Дэбиан) - Минт. В него установлено всё, что нужно пользователю без технических знаний. Мне приглянулся Elementary OS. Это дело вкуса. Если очень грубо - то чаще разные варианты линукса различаются "обоями да вариантами менюшек". Я про клонов на базе убунты. Научитесь работать с Bash, это то, что линукс делает линуксом для простого обывателя и пользователя.

Ответить

 

Денис

Дмитрий, подскажите, пожалуйста для особо понятливых. Честно, я посмотрел все 4 часа видео)
У меня есть форма для заполнения данных из двух моделей. Вопрос по экшену create.
Как сохранить данные одной модели, взять id первой сохраненной модели, и сохранить этот id в соответствующем поле второй модели? Приведенный код ниже у меня не сохраняет данные ни одной модели(

public function actionCreate()
{
    $model = new Dailyinfo();
    $info = new Information();

    if ($model->load(Yii::$app->request->post()) && $info->load(Yii::$app->request->post()) && $info->save()&& $model->info_id=$info->id && $model->save()) {
        return $this->redirect(['view', 'id' => $model->id]);
    } else {
        return $this->render('create', [
            'model' => $model,
            'info' => $info,
        ]);
    }
}
Ответить

 

Дмитрий Елисеев

Сначала $model->save(), потом $info->save().

Ответить

 

Денис

Поменял весь порядок, добавил ещё несколько переменных для заполнения required полей, теперь $info сохраняется, а $model нет.
Мне кажется при сохранении $model не получает $info->id.

Ответить

 

Дмитрий Елисеев

Сделайте print_r($info) и print_r($model), чтобы не казалось.

Ответить

 

Денис

С вашей помощью, Дмитрий, заработало) Есть ли у вас замечания по моему коду, все таки стремлюсь постепенно к феншую, хотя понимаю, что ещё далеко) И думаю начинающим будет полезно.

public function actionCreate()
{
    $model = new Dailyinfo();
    $model->dept_id=1;
    $model->insert_date=date('Y-m-d');

    $info = new Information();
    $info->period_id=7;
    $info->forma_type=12;

    if (  
        $info->load(Yii::$app->request->post())
        && $info->save()
        && $model->load(Yii::$app->request->post())
    ) {
        $model->info_id=$info->id;
        $model->save();
        return $this->redirect(['view', 'id' => $model->id]);
    } else {
        return $this->render('create', [
            'model' => $model,
            'info' => $info,
        ]);
    }
}
Ответить

 

Дмитрий Елисеев

Я бы либо установку первоначальных значений перенёс в методы loadDefaultValues моделей. И вообще бы отдельную модель формы использовал.

Ответить

 

Евгений

Подскажите пожалуйста как изучить ООП? Что читать и что смотреть? На что делать упор?

Ответить

 

Дмитрий Елисеев

Про кое-что расказывал здесь. А так, думаю, в YouTube что-нибудь уже есть.

А так может интенсив проведу в этом месяце по материалу, который ученикам рассказываю. Подпишитесь пока на рассылку. Если надумаю, то в ней сообщу.

Ответить

 

Дмитрий Елисеев

Уговорили :) Запускаю интенсив.

Ответить

 

Кабаченко Виктор

Отличный вебинар.
Маленькое уточнение. Чтобы поместить в гриде количество записей в нескольких связанных таблицах, надо немного изменить ваше решение, указав DISTINCT в COUNT. Примерно так:

$query = Category::find()
  ->select(['{{%category}}.*', 
         'products_count' => new Expression('COUNT(DISTINCT {{%product}}.id)')]),
         'materials_count' => new Expression('COUNT(DISTINCT {{%material}}.id)')]),
  ->joinWith(['products', 'materials'], false)
  ->groupBy('{{%category}}.id')
Ответить

 

Andrewkha

В коммите added product tabular attributes editor ошибка.
При таком коде в контроллере

        foreach (array_diff_key($attributes, $values) as $attribute) {
            $values[] = new Value(['attribute_id' => $attribute->id]);
        }

и таком выводе в представлении

<?= $form->field($value, '[' . $value->productAttribute->id . ']value')


все работает, если только id-шники атрибутов в соотв таблице идут подряд. Если же что-то вроде 1, 2, 5 то все поломается, loadMultiple не подберет значения там, где не совпадут индексы.
В контроллере надо

$values[$attribute->id] = new Value(['attribute_id' => $attribute->id]);
Ответить

 

Дмитрий Елисеев

Спасибо! Исправил.

Ответить

 

Сергей

Дмитрий, а можешь объяснить как в Yii2 сделать древовидные комментарии, без использования nested sets и т д? И чтобы можно было самому регулировать уровень максимальной вложенности.

Ответить

 

Дмитрий Елисеев

У меня обычным parent_id. С выборкой всех одним запросом и с рекурсивным выводом. Максимальный сдвиг для вложенности делается простым CSS:

.comment {
    margin-left: 40px;
}
.comment > .comment > .comment .comment {
    margin-left: 0;
}
Ответить

 

Andrewkha

Дмитрий, добрый день!

Слегка запутался в join, with и joinWith.
Скажи, пожалуйста, я правильно понимаю, что joinWith с параметром false - это аналог простого Join? или есть какие-то особенности?

Ответить

 

Дмитрий Елисеев

Да, аналог. Но join'у нужно вручную имя таблицы и колонок указать, а joinWith работает автоматически по имени связи.

Ответить

 

Иван Васильев

Спасибо за вебинар. Смотрел в записи. Очень много полезного для себя почерпнул из этого видео.

Ближе к концу видео, в CatalogController.php вы поменяли имя параметра действия с $tag на $name.
Тогда нужно поменять параметр при формировании массива ссылок на тэги в представлении _item.php.

$tagLinks[] = Html::a(Html::encode($tag->name), ['tag', 'name' => $tag->name]);

Еще раз спасибо. Теперь собираюсь пересмотреть ваши более ранние вебминары.

Ответить

 

Andrewkha

Дмитрий, приветствую. Нужна Ваша помощь :) Вопрос по работе с моделью и ActiveDataProvider.

Итак, имеется Junction table простого вида
id_user
it_tournament
points

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

Что я сделал.

        $query = [];
        foreach ($array as $one)
            $query[] = UsersTournaments::find()
                ->where(['id_tournament' => $one])
                ->orderBy(['points' => SORT_DESC])
                ->with('idTournament.country0')
                ->with('idUser')
                ->limit(1);

        $count = count($query);

        $toExecute = $query[0];
        for($i = 0; $i < $count - 1; $i++)
            $toExecute = $toExecute->union($query[$i + 1]);

        return $toExecute;

Если затем вызываю

$toExecute->all()

все работает хорошо, т.е. выбирает именно записи с максимальным значением points для каждого id_tournament.
Но если же я этот $toExecute скармливаю в качестве свойства query для ActiveDataProvider начинаются чудеса.
А именно, для первого id_tournament (и только для него) выдает все имеющиеся записи, не только с максимальным значением points. Т.е. limit(1) в запросе не срабатывает. Для всех последующих id_tournament все хорошо.
Через дебаггер посмотрел, какой выполняется запрос и очень удивился.
Для первого id_tournament выполняется limit(20), такое ощущение, что ActiveDataProvider подменяет мой limit(1) своим дефолтовым для пагинации. Что интересно, для всех последющих, которые цепляются через union все хорошо, там limit(1).

Есть идеи, как это можно пофиксить?

Ответить

 

Дмитрий Елисеев

Можно попробовать все UNION обернуть в подзапрос в скобках. А так точно не знаю.

Ответить

 

Денис

Подскажите, пожалуйста, как можно сделать так, чтобы при помещении в парку site\pages файла формата md (Markdown), он открывался как статическая страница?

Ответить

 

Дмитрий Елисеев

Открыть через file_get_contents и скормить парсеру:

$this->render('page', [
    'content' => yii\helpers\Markdown::process($md),
]);
Ответить

 

Sergey Aver

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

public function getIngredients()
{
    return $this->hasMany(Ingredients::className(), ['id' => 'ingredient_id']);
}

public function getReceptIngredient($id)
{
    return ReceptyIngredients::find()
        ->joinWith('ingredients')
        ->where(['recept_id'=>$id])
        ->all();	
    }
}

$items = ReceptyIngredients::getReceptIngredient(1);
foreach($items as $item) {
    print_r($item->ingredients);
}

выводит вот такой результат

Array
(
    [0] => frontend\models\Ingredients Object
        (
            ...
        )
)

А если обращаюсь к $item->ingredients->name

пишет что Trying to get property of non-object

Ответить

 

Дмитрий Елисеев

Потому что $item->ingredients - это тоже массив:

foreach ($item->ingredients as $ingredient) {
    echo $ingredient->name;
}
Ответить

 

Sergey Aver

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

SELECT `np_ingredients`.* FROM `np_ingredients` LEFT JOIN `np_recepty_ingredients` ON `np_ingredients`.`id` = `np_recepty_ingredients`.`ingredient_id` LEFT JOIN `np_measures` ON `np_recepty_ingredients`.`id_measure` = `np_measures`.`id` WHERE `recept_id`=485 

А хотелось бы такой

SELECT * FROM `np_ingredients` LEFT JOIN `np_recepty_ingredients` ON `np_ingredients`.`id` = `np_recepty_ingredients`.`ingredient_id` LEFT JOIN `np_measures` ON `np_recepty_ingredients`.`id_measure` = `np_measures`.`id` WHERE `recept_id`=485 
Ответить

 

Дмитрий Елисеев

C "SELECT * FROM ..." только вручную, так как ActiveRecord результаты JOIN-ов не парсит.

Ответить

 

Яромир

Дмитрий, во-первых, большое человеческое спасибо за Ваш труд и Вашу отзывчивость. Во-вторых, не поделитесь Вашими планами на будущие вебинары? Помнится на интенсиве по ООП много людей высказывало желание увидеть вебинары по устройству symfony. Собственно, это было бы прямым развитием темы ООП про правильное структуирование клиентского кода в фреймворке через введение сервисного слоя, иньекции и т.д.Прекрасно было бы и в виде платного интенсива, хотя я отдаю себе отчет сколько времени уходит на подготовку к подобному событию.
А может быть вы планируете еще какие то вебинары по Yii? Поделитесь плиз, чего можно ждать, или наоборот не ждать. Спасибо.

Ответить

 

Дмитрий Елисеев

Всё планирую, но не всё успеваю. Так что как повезёт :)

Ответить

 

Роман

Спасибо за ваши труды, лучшего сайта по YII не находил))
Было бы интересно узнать как правильно делать URL каталога, н-р
domain/catalog/categoryParent/categoryChild/categoryChild/name_product

Ответить

 

Вася

Дмитрий подскажите как в виджете категорий в каталоге, вывести рядом количество постов?

Ответить

 

Дмитрий Елисеев

Если без иерархии, то echo $category->getPosts()->count().

Ответить

 

Вася

Записал вот так:

'template' => '<a href="{url}" class="url-class">{label}</a>'.'<small class="badge">'.$category->getPosts()->count().'</small>,

И количество запросов к базе выросло в два раза, было 8 стало 14, я делал другим образом, как в модели поиска categorySearch.php в файл categoriesWidget добавил public $posts_count;
Потом

$categories = Category::find()
    ->select(['{{%category}}.*', 'courses_count' => new Expression('COUNT(DISTINCT {{%post}}.id)')])
    ->joinWith(['posts'], false)
    ->groupBy('{{%category}}.id')
    ->orderBy('name')->all();

и вот так:

$items[] = [
    'label' => $category->name,
    'template' => '<a href="{url}" class="url-class">{label}</a>'.'<small class="badge">'.$category->posts_count.'</small>',
    'url' => ['main/category', 'id' => $category->id],
    'active' => $this->category && $category->id == $this->category->id ? true : null,
    'items' => $this->getItemsRecursive($categories, $category->id, $current),
];

Выводиться нормально и запросов 8, так нормально или можно как то по другому?

Ответить

 

Дмитрий Елисеев

Нормально. Мы так и делали в админке в гриде категорий в этом вебинаре. Ещё учтите, что с древовидными категориями в виджете нужно считать суммарное число постов в подкатегориях.

Ответить

 

Вася

Подскажите пожалуйста как это сделать?

Ответить

 

Дмитрий Елисеев

Либо завести поле total_count и при каждом изменении постов его пересчитывать, либо каждый раз рекурсивно суммировать по parent_id, либо перевести базу на Nested Sets и считать COUNT по массивам id вложенных категорий.

Ответить

 

Александр

Дмитрий, спасибо за очередной качественный вебинар.
Для себя хочу уточнить один момент.
В миграциях вы создаете индексы так же для полей, на которых так же создаете FK на другое поле (или другое поле другой таблицы). Для postgres согласен. Но, ведь в mysql при создании FK автоматически создается и индекс.

Ответить

 

Дмитрий Елисеев

Просто стараюсь делать миграции, универсально работающие и на MySQL, и на PostgreSQL.

Ответить

 

Виталий Бахур

Здравствуйте Дмитрий. Хотел бы спросить а как сделать подгрузку атрубутов динамически и на лету, чтобы и валидация была. Т.е смысл такой заходишь создаешь товар, в нём указываешь категорию и у нас для каждой категории подгружает свои атрибуты. Как такое реализовать? я так понимаю в сторону behaviors надо смотреть?

Ответить

 

Дмитрий Елисеев

Либо возиться с $('#form').yiiActiveForm('add', ...), либо сделать форму двухшаговой, где на первой странице выбираем категорию, а на второй уже запоняем всё остальное.

Ответить

 

Виталий Бахур

Спасибо за совет. Ну двухшаговую делать не буду, а вот в сторону $('#form посмотрю')

Ответить

 

Олег

Здравствуйте, Дмитрий. Я переделываю на Yii2 свой интернет-магазин (хочу перейти с Джумлы), но возникла сложность с выбираемыми пользователем свойствами товара (цвет и размер). В карточке товара выводятся несколько размеров и несколько цветов, но в наличии есть, например: товар 48 размера - белый, а 50 размера - красный. Подскажите, пожалуйста, как сделать связанные свойства товара: размеры со своими цветами? Как правильно создать таблицы в БД и какие прописать связи между нами?

Ответить

 

Алекс

Никак не могу понять, как могу быть записи типа $category->parent->name или 'parent.name'. Что это вообще такое? В таблице категории у нас нет поля parent. Или 'parent.name' - что это? у нас нет ни таблицы parent, ни связи такой.

Ответить

 

Алекс

Посмотрел исходники. Понял в чем дело. Не знал что $this->hasOne() и $this->hasMany() можно на тот же класс модели делать.

Ответить

 

Андрей Кушнарев

Здравствуйте Дмитрий, нашел ошибку не проявляющуюся на присутствующем наборе данных, пишу тут потому как смог решить ее только частично:
В админке в просмотре продуктов при сортировке по имени категории по факту происходит сортировка по category_id.
Если в ProductSearch поменять

$query = Product::find()->with(['tags'])->joinWith(['category', 'productTags'], false);
 ...
$dataProvider->sort->attributes['category_id'] = [
    'asc' => ['{{%category}}.name' => SORT_ASC],
    'desc' => ['{{%category}}.name' => SORT_DESC],
];
 ...

Теперь сортировка работает правильно (по имени), но возникла проблема с фильтрацией по одноименным полям которые присутствуют в product и category(в частности id и name):

Error Info: Array
(
    [0] => 23000
    [1] => 1052
    [2] => Column 'name' in where clause is ambiguous
)


как можно решить эту проблему?

Ответить

 

Андрей Кушнарев

Решил таким способом.
В ProductSearch, то что было изменено выше так и осталось и еще поменял:

$query->andFilterWhere([
    '{{%product}}.id' => $this->id,
    'category_id' => $this->category_id,
    'price' => $this->price,
    'active' => $this->active,
    '{{%product_tag}}.tag_id' => $this->tag_id,
]);

$query->andFilterWhere(['like', '{{%product}}.name', $this->name])
    ->andFilterWhere(['like', 'content', $this->content]);

Вопрос - а можно ли сделать тоже самое, но при этом не использовать имена таблиц БД, а использовать связи прописанные в модели AR?

Ответить

 

Дмитрий Елисеев

Можно вручную указать псевдонимы для каждой таблицы. А сам фреймворк имена связей в запрос не подставляет.

Ответить

 

Андрей Кушнарев

А можно поподробнее и с примером? А то что-то не совсем понятно.

Ответить

 

Дмитрий Елисеев

Указать псевдонимы:

$query = Product::find()
    ->from(['product' => Product::tableName()])
    ->joinWith('category category');

И использовать псевдоним 'product.id' вместо имени таблицы '{{%product}}.id'.

Ответить

 

Андрей Кушнарев

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

Ответить

 

Shvarz

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

Таблица users связана с таблицей event, мне нужно чтобы при создании нового event я вручную не вбивал айдишник пользователся. скорее всего нужно в представлении _form, вместо

<?= $form->field($model, 'user_id')->textInput() ?>

сделать

'user_id'=> User::($model, 'id')

но у меня с синтаксисом беда помогите ....

Ответить

 

Дмитрий Елисеев

Если пользователей мало, то можно выпадающим списком:

<?= $form->field($model, 'user_id')->dropDownList(ArrayHelper::map(User::find()->asArray()->all(), 'id', 'username')) ?>
Ответить

 

Shvarz

Нет, Дмитрий вы не поняли меня, мне нужно чтобы он выбирал текущего залогиненного пользователя и сразу добавлял в поле user_id в таблице event.

т.е кто создал событие того айдишник и добавляется, что это он создатель.

Ответить

 

Shvarz

Тут походу функцию надо писать , хотя бы пример какой-нибудь....

Ответить

 

Shvarz

Yii::$app->user->id - полчение текущего айди пользователя
и потом нужно в представлении _form или create записать в поле user_id это значение

Ответить

 

Дмитрий Елисеев

Впишите в контроллере:

$model = new Event();
$model->user_id = Yii::$app->user->id;

и всё.

Ответить

 

Shvarz

спс, я был близок, во второй строке у меня небыло в начале $model...
Жесть столько времени убито, надо синтакисис учить...

Ответить

 

Shvarz

Вопрос еще один созрел: Если я создаю,допустим событие в котором нужно добавить файлы.
Как загрузить сразу файлы в момент формирования события? (хочу хранить файлы, логи все в бд)
Какие способы выбрать и правильно ли я вообще мыслю?
Способы:
1)сразу создавать событие с пустыми параметрами, но только чтобы был айди события и сразу загружать файлы к событию?
2)Или сделать временную таблицу туда записывать файлы ?

Ответить

 

Shvarz

Когда я нажимаю на кнопку создать событие т.е actionCreate событие уже в базе создается с айдишником или нет? Извините за глупые вопросы понимаю как понимаю ...

Ответить

 

Дмитрий Елисеев

Айдишник добавляется после save(). Если же нужно загрузить по Ajax до сохранения модели, то обычно грузим всё во временную папку и сохраняем имена файлов в сессию. А в момент сохранения уже перемещаем эти файлы куда надо.

Ответить

 

Shvarz

Спс, для начала пойду путем создания 2-ой формы, а потом когда всю структуру выведу буду оптимизировать...

Ответить

 

Shvarz

таблица Event связана с таблицей User:

$this->addForeignKey('fk-event-user_id','{{%event}}','user_id','{{%user}}','id','CASCADE','RESTRICT');
$this->addForeignKey('fk-event-isp_id','{{%event}}','isp_id','{{%user}}','id','CASCADE','RESTRICT');

В представлении event\index вывожу вместо параметров 'user_id' и 'isp_id' следующее:

 [
   'attribute' => 'user_id',              
     'value'=>function(Event $event){
           return $event->user->username;
                }         
  ],

  [
   'attribute' => 'isp_id',              
        'value'=>function(Event $event){
             return $event->user->username;
                }             
  ],

Он выводит имена , но если потом сравнить с id , то неправильно , одного айди вообще не выводит , вместо него повторяет имя старого, что я не так ?

Ответить

 

Shvarz

Т.е у меня есть айди создателя и айди исполнителя, и привязаны они к одному айди из таблицы User.

Ответить

 

Дмитрий Елисеев

Ну так и выводите из разных:

$event->user->username
$event->isp->username

Или проще:

[
    'attribute' => 'user_id',              
    'value' => 'user.username';
],
[
    'attribute' => 'isp_id',              
    'value' => 'isp.username';
],
Ответить

 

Shvarz

Заработало,спс. Ток я не вкурю , почему так?

Ответить

 

Shvarz

типо отбрасывается _id ?

Ответить

 

Дмитрий Елисеев

В модели Event генерируются методы getUser() и getIsp() с hasOne либо hasMany. Это и есть связи $event->user и $event->isp.

Ответить

 

Shvarz

Ага догнал, спс...

Ответить

 

Shvarz

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

return $this->last_name.' '.$this->name.' '.substr($this->patronymic,1,1).' '.$this->username;

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

$event=Event::find(),
$ggstr=substr($event->user->last_name,0,1),
'value'=>ArrayHelper::getValue(function (Event  $event) {
return $event->user->name . ' ' . $event->user->last_name; })
Ответить

 

Shvarz

Нашел проблему, кому интересно решается через mb_substr

Ответить

 

Shvarz

Хочу сделать так :gри создании заявки ( Event), я выбираю из >dropDownList отдел( Department), после выбора отдела у меня выбирается 1 исполнитель только из этого выбранного отдела.
Но не работает , брал материал:

1) http://quabr.com/34989819/yii2-dependent-dropdown-list
2) https://www.youtube.com/watch?v=ZepxKw8VA7w

в итоге переделал под свой вариант и вот что получилось , но не работает при выборе исполнителя...

ProfileController:

    public function actionLists($id)
    {        
        $countProfile=User::find()->where(['department_id'=>$id])->count();
        $profile=User::find()->where(['department_id'=>$id])->all();
        if ($countProfile > 0)
        {
            foreach ($profile as $user1) {
                echo "<option value='" . $user1->user_id. "'>" . $user1->fioName . "</option>";
            }
        }
        else
        {
            echo "<option> - </option>";
        }
    }

event-form:

 <?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>

    <?php
    $dataDEP = ArrayHelper::map(Department::find()->asArray()->all(), 'id', 'name');
    echo $form->field($model, 'dep_id')->dropDownList($dataDEP,
        [
            'prompt'=>'Selected department',
            'onchange'=>'
            
            $.post( "'.Yii::$app->urlManager->createUrl('profile/lists?id=').'"+$(this).val(), function ( data ){           
              $( "select#profile-dep_id" ).html(data);
               });
        ']);

    echo "<br>";
    $dataUSER = ArrayHelper::map(User::find()->asArray()->all(), 'id', 'fioName');
    echo $form->field($model, 'isp_id')->dropDownList($dataUSER,
        [
            'prompt'=>'Selected user',
            'id'=>'dep_id']
    ); ?>

Что не так , думаю либо со связями проблема, либо еще что-то в модель нужно записать ...
Помогите.....

Ответить

 

Shvarz

Все сделал, без всяких kratikov =)

Ответить

Оставить комментарий

Войти | Завести аккаунт


(никто не увидит)



Можно использовать теги <p> <ul> <li> <b> <i> <a> <pre>