Динамические поля ActiveForm и обработка в контроллере

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
nickdenry
Сообщения: 99
Зарегистрирован: 2015.10.28, 04:55

Динамические поля ActiveForm и обработка в контроллере

Сообщение nickdenry »

Скажу сразу - все работает, новые модели добавляются, удаляемые модели удаляются. Мой вопрос - насколько корректна функция populateRelatedModelWithRequest, а именно добавление новых значений для модели и удаление "лишних"?

Аналогично теме http://www.yiiframework.ru/forum/viewto ... 19&t=16928
Имею ActiveForm со сниппетом, подобным http://bootsnipp.com/snippets/featured/multiple-fields
Модели Customer, CustomerPhones. Customer hasMany CustomerPhones.

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

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

foreach ($modelCustomerPhones as $key => $modelCustomerPhone)
{
    echo($form->field($modelCustomerPhone, '['.$key.']number',
        ['template'=>$phoneFieldTemplate])->textInput()
    );
} 
Каждое поле имеет вид (включая динамически добавляемые и удаляемые поля, индекс непрерывно возрастает)

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

    
    <input type="text" value="" name="CustomerPhone[0][number]" class="form-control" id="customerphone-0-number">
    ...
    <input type="text" value="" name="CustomerPhone[n][number]" class="form-control" id="customerphone-n-number">
    ...
    <input type="text" value="" name="CustomerPhone[m][number]" class="form-control" id="customerphone-m-number">

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

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

    /**
     * Заполняет связанные моделb в соответствии с запросом и индексами.
     * Добавляет пустые модели для заново добавленных полей.
     * Удаляет лишние связанные модели, если поле было удалено динамически (не присутствует в $request)
     *
     * @param ActiveRecord $parentRelationModel Родительская модель.
     * @param Array $relatedModelsArray Массив дочерних моделей.
     * @param yii\web\Request $request Запрос Yii::$app->request;
     * @param String $relationName Название связи между родительской и дочерней моделью (для unlink).
     * @param String $formFieldName название поля формы.
     *
     * @return Array Актуальный массив с моделями.
     */
public function populateRelatedModelWithRequest($parentRelationModel, $relatedModelsArray, $request, $relationName, $formFieldName)
    {
        $modelClass = get_class(reset($relatedModelsArray));

        // Получаем разницу между ключами в запросе и ключами в модели.
        // Если запрос не содержит модель - создаем ее.
        $requestDifference = array_keys(array_diff_key($request[$formFieldName], $relatedModelsArray));
        foreach ($requestDifference as $key)
        {
            $relatedModelsArray[$key] = new $modelClass;
        }

        // Получаем разницу между ключами в модели и ключами в запросе.
        // Если моедль не присутствует в запросе - удаляем связанное значение и убираем модель из массива.
        $modelDifference = array_keys(array_diff_key($relatedModelsArray, $request[$formFieldName]));
        foreach ($modelDifference as $key) {
            $parentRelationModel->unlink($relationName, $relatedModelsArray[$key], true);
            unset($relatedModelsArray[$key]);
        }

        return $relatedModelsArray;
    }
Соотвественно на actionCreate или actionUpdate

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


public function actionCreate()
{
....
// Инициализация моделей.
....
$requestData = Yii::$app->request;
// Если $_POST, актуализируем массив моделей
if ($requestData)
        {
            $modelCustomerPhones = $this->populateRelatedModelWithRequest($modelCustomer, $modelCustomerPhones, $requestData, 'customerPhones', 'CustomerPhone');
        }

    //  Сохранение
        if ($modelCustomer->load($requestData) &&
            $modelCustomer->validate() &&
            CustomerPhone::loadMultiple($modelCustomerPhones, $requestData) &&
            CustomerPhone::validateMultiple($modelCustomerPhones)) 
        {
            ...
 
Спасибо.
Ответственные программисты с высоким уровнем технического долга (c)
Ответить