Страница 1 из 1
Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 16:29
nepster
Есть форма, которая содержит следующие поля:
title
meta_title
meta_description
и тп.
Я сделал форму, которая генерируется на основе подключенных языков, тоесть такие поля превращаются в массивы:
title[ru]
meta_title[ru]
meta_description [ru]
title[en]
meta_title[en]
meta_description [en]
и тп.
Выглядит это вот таким образом:
Код: Выделить всё
<div class="row">
<div class="col-md-4 col-md-4 col-sm-4 col-xs-6 col-lg-4"><?= $form->field($formModel, 'meta_title['.$lang['code'].']')->textInput(['maxlength' => true]) ?></div>
<div class="col-md-4 col-md-4 col-sm-4 col-xs-6 col-lg-4"><?= $form->field($formModel, 'meta_description['.$lang['code'].']')->textInput(['maxlength' => true]) ?></div>
<div class="col-md-4 col-md-4 col-sm-4 col-xs-6 col-lg-4"><?= $form->field($formModel, 'meta_keywords['.$lang['code'].']')->textInput(['maxlength' => true]) ?></div>
</div>
Все отлично работает, за исключением, когда речь идет о валидации. Тоесть если в русском языке к примеру допущена ошибка, то Yii помечает ошибку как глобально на все поле. Тоесть, вместо title-ru он говорит, что ошибка в поле title, тем самым указывая, все все переводы указаны неверно, даже если это не так.
Все происходит вот из-за этого кода:
Код: Выделить всё
public static function getAttributeName($attribute)
{
if (preg_match('/(^|.*\])([\w\.]+)(\[.*|$)/', $attribute, $matches)) {
return $matches[2];
} else {
throw new InvalidParamException('Attribute name must contain word characters only.');
}
}
Тоесть он просто всегда удаляет все, что в [] и не дает возможность валидировать только определенное поле в массиве. Что с этим делать ?
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 18:00
andrei.obuhovski
Сдается мне, что тут нужно было так делать:
Код: Выделить всё
$form->field($model, "[".$lang['code']."]meta_title")
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 18:01
rak
варианты навскидку:
1. делать переводы отдельными моделями, тогда можно использовать код вида
Код: Выделить всё
<?= $form->field($langModels['en'], '[en]meta_title')->textInput() ?>
2. добавить дополнительные поля в модель, валидировать их, а перед сохранением сохранять в нужные поля бд
3. использовать готовое поведение, например, вот это
https://github.com/OmgDef/yii2-multilingual-behavior
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 18:26
nepster
andrei.obuhovski писал(а):Сдается мне, что тут нужно было так делать:
Код: Выделить всё
$form->field($model, "[".$lang['code']."]meta_title")
В таком случае придется создавать свойства в модели по имени кодов языка, а заранее мы не знаем сколько их будет и какие они.
rak писал(а):варианты навскидку:
1. делать переводы отдельными моделями, тогда можно использовать код вида
Код: Выделить всё
<?= $form->field($langModels['en'], '[en]meta_title')->textInput() ?>
2. добавить дополнительные поля в модель, валидировать их, а перед сохранением сохранять в нужные поля бд
3. использовать готовое поведение, например, вот это
https://github.com/OmgDef/yii2-multilingual-behavior
1 - хороший вариант. Но тогда нужно будет писать мануал по php и yii2 в админке и возможность создавать модели для заказчика через текстовый редактор.
2 - не вариант, так как мы изначально не знаем какие языки и какие поля. Так как в любой момент в админке могут скажем добавить язык или удалить язык.
3 - я не использую подобные расширения, это весьма сомнительные реализации. С Yii2 нужно быть особо осторожным.
А зачем было так усложнять ? Интересно, что по поводу этого скажем Александр Макаров ?
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 18:48
andrei.obuhovski
nepster писал(а):andrei.obuhovski писал(а):Сдается мне, что тут нужно было так делать:
Код: Выделить всё
$form->field($model, "[".$lang['code']."]meta_title")
В таком случае придется создавать свойства в модели по имени кодов языка, а заранее мы не знаем сколько их будет и какие они.
По аналогии как здесь:
https://github.com/yiisoft/yii2/blob/ma ... r-input.md
$form->field($setting, "[$index]value")
Только вместо $index, ваш код языка.
Foreach'у какая разница что перебирать.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 19:05
nepster
Либо я понял смысл и мне такое к сожалению не подходит, либо я не понял идею =(.
У меня нет работы с ActivRecord, вообще с ним на прямую лучше не работать. У меня есть модель (base Model), в которой я получаю все данные, там я их валидирую привожу к нужному формату и только потом сохраняю через актив рекорд. Тоесть по сути мне нужно сейчас при валидации сделать что-то такое:
Код: Выделить всё
$this->addError('[en]title', 'Возникла ошибка именно с языком EN');
И в любом случае та нехорошая регулярка обрезает все, что есть в [].
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 22:51
andrei.obuhovski
Если я правильно понял, то у вас одни и те же поля повторяются N количество раз. (где N - количество языков)
Тогда вам нужно создать одну модель с этими полями. А выводить, и заполнять, и валидировать через foreach (или loadMultiple и validateMultiple). При этом в качестве ключей вам нужно указать коды ваших языков(или их айдишнники).
Т.е. логика примерно такая:
При выводе:
1) Получаем массив языков
2) Перебираем их в цикле, и делаем новый массив из FormModel. В качестве ключей указываем коды языков.
3) Выводим в цикле форму. $form->field($formModel, "[$lang]meta_title")
При отправке:
1) Model::LoadMultiple()
2) Model::ValidateMultiple()
3) Сохраняем в цикле
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.02.29, 23:51
nepster
Честно говоря я не совсем понимаю зачем *Multiple у меня нет нескольких моделей и валидация мне нужна кастомная. Да и в этом случае тот злой метод вчерашнего удалит скобки и оставит только title. В результате ошибки будут везде.
По факту я просто в одной модели хочу поработать с языками и потом что-то сделать, мне не нужно по модели на каждый язык. Это походу косяк yii.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.01, 00:52
Nerf
Переопределите yii\widgets\ActiveField. Как минимум error(). А потом еще...
Про js валидацию, наверное, стоит забыть. Получите снежный ком проблем.
andrei.obuhovski дело говорит.
Сделайте на каждый язык модель(не суть AR или нет) с нужными вам полями.
Controller:
Код: Выделить всё
$models = [];
$langCodes = ['ru', 'en']; // из параметров, БД...
foreach($langCodes as $code) {
$models[$code] = new YouModel([
'lang' => $code,
]);
}
if (Model::loadMultiple($models, Yii::$app->request->post()) && Model::validateMultiple($models)) {
foreach ($models as $model) {
// $model->save(false);
// ваша логика сохранения
}
return $this->redirect('index');
}
return $this->render('update', ['models' => $models]);
View:
Код: Выделить всё
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($models as $langCode => $model) { // вывод всех полей модели, или продублируйте foreach, чтобы вывести заголовок 1, заголовок 2...
echo $form->field($model, "[$langCode]title")->label($model->getTranslatedLabel('title')); // label() опционально
echo $form->field($model, "[$langCode]meta_title")->label($model->getTranslatedLabel('meta_title'));
// ...
}
ActiveForm::end();
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.01, 10:32
nepster
Сделайте на каждый язык модель(не суть AR или нет) с нужными вам полями.
Nerf писал(а):Переопределите yii\widgets\ActiveField. Как минимум error(). А потом еще...
Про js валидацию, наверное, стоит забыть. Получите снежный ком проблем.
andrei.obuhovski дело говорит.
Сделайте на каждый язык модель(не суть AR или нет) с нужными вам полями.
Controller:
Код: Выделить всё
$models = [];
$langCodes = ['ru', 'en']; // из параметров, БД...
foreach($langCodes as $code) {
$models[$code] = new YouModel([
'lang' => $code,
]);
}
if (Model::loadMultiple($models, Yii::$app->request->post()) && Model::validateMultiple($models)) {
foreach ($models as $model) {
// $model->save(false);
// ваша логика сохранения
}
return $this->redirect('index');
}
return $this->render('update', ['models' => $models]);
View:
Код: Выделить всё
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($models as $langCode => $model) { // вывод всех полей модели, или продублируйте foreach, чтобы вывести заголовок 1, заголовок 2...
echo $form->field($model, "[$langCode]title")->label($model->getTranslatedLabel('title')); // label() опционально
echo $form->field($model, "[$langCode]meta_title")->label($model->getTranslatedLabel('meta_title'));
// ...
}
ActiveForm::end();
Я ж говорю, к сожалению за ранее неизвестно какие будут языки, сколько их, какой по умолчанию и тп. Все задает админ.
JS валидация это такое, она и так не всегда работает, например в случае с exist unique и тп.
Мне кажется это жирный косяк АктивФорма. А точнее даже хелпера Html::error(). Потому, как если убрать ту регулярку вроде пробелмы пропадают. И тут либо что-то мы упускаем, либо косячелло.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.01, 10:52
andrei.obuhovski
nepster писал(а):
Я ж говорю, к сожалению за ранее неизвестно какие будут языки, сколько их, какой по умолчанию и тп. Все задает админ.
После того как админ задал, оно же хранится где-то. Вот оттуда и берите.
nepster писал(а):
JS валидация это такое, она и так не всегда работает, например в случае с exist unique и тп.
Ajax-валидацией решается.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.01, 22:12
rak
nepster писал(а):
3 - я не использую подобные расширения, это весьма сомнительные реализации. С Yii2 нужно быть особо осторожным.
угу, а потом тот, кто будет поддерживать этот код будет вспоминать предыдущего разработчика не злым тихим словом за очередной велосипед с квадратными колесами
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.01, 23:23
nepster
Вот как раз наоборот скорее всего. У меня вся логика инкапсуляция в разных моделях, а не вешаются глобальные непонятные поведения на всю модель. Я уже это проходит. Если у вас несколько сценариев и все завязано на одной форме, то оптом геморроя будет прилично. Если ваше приложение хоть чуть-чуть больше блога, с актив рекордом нужно быть очень осторожным.
По теме, такое вариант работает (привет велосипедам), но проблема в том, что мне нужна логика валидации. Например если вы указали дефолтный язык, то для друго-го валидация на required будет необязательна. В свою очередь, если вы указали другой язык, то тоже самое для дефолтного.
Как только нужно сделать что-то кастомное, виджеты yii сыпятся.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.01, 23:45
nepster
В общем пока реализовал в стиле Yii2 "не нравится? переопредели":
В бутстрап файле (только для админки, ну понятно, что для продакшина человек в здравом уме виджеты yii не использует):
Код: Выделить всё
Yii::$container->set('yii\widgets\ActiveForm', [
'fieldClass' => 'app\components\backend\ActiveField',
]);
Привет DI. Отличная штука, когда пришло озарение зачем она.
Далее переопределяем 2 метода
Код: Выделить всё
public function error($options = [])
public function begin()
На первый взгляд работает. Но если кому-то нужно будет, такую штуку не используйте, пока не понятно к чему это может привести.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.02, 00:47
rak
nepster писал(а):Вот как раз наоборот скорее всего. У меня вся логика инкапсуляция в разных моделях, а не вешаются глобальные непонятные поведения на всю модель. Я уже это проходит. Если у вас несколько сценариев и все завязано на одной форме, то оптом геморроя будет прилично. Если ваше приложение хоть чуть-чуть больше блога, с актив рекордом нужно быть очень осторожным.
По теме, такое вариант работает (привет велосипедам), но проблема в том, что мне нужна логика валидации. Например если вы указали дефолтный язык, то для друго-го валидация на required будет необязательна. В свою очередь, если вы указали другой язык, то тоже самое для дефолтного.
Как только нужно сделать что-то кастомное, виджеты yii сыпятся.
тут проблема скорее с проектированием бд.
по-хорошему, нужно все поля, которые необходимо переводить, вынести в отдельную таблицу бд. по сути поведение, которое я скидывал выше и реализует эту логику, причем не создавая дополнительных моделей.
но можно его и не использовать, а реализовать тоже самое самому.
стандартная валидация yii отлично работает для определенной структуры, если начинать выдумывать что-то свое, то естественно, что стандартные варианты не будут работать без напильника.
но вот для чего городить огород для задач, которые уже 100 раз решались ранее - не понятно
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.02, 03:21
Nerf
Just fo lulz...
Вот как раз наоборот скорее всего. У меня вся логика инкапсуляция в разных моделях
Как раз наоборот наоборот. Логика в разных моделях звучит многообещающе... Почитайте про SOLID.
Если ваше приложение хоть чуть-чуть больше блога, с актив рекордом нужно быть очень осторожным.
О Боже, какой мужчина! ActiveRecord - это ORM по одноименному шаблону проектирования. Что же там такого опасного?
но проблема в том, что мне нужна логика валидации. Например если вы указали дефолтный язык, то для друго-го валидация на required будет необязательна. В свою очередь, если вы указали другой язык, то тоже самое для дефолтного.
И почему для этого не работают rules()?
Как только нужно сделать что-то кастомное, виджеты yii сыпятся.
Потому что вы пытаетесь их использовать не по назначению.
Мне кажется это жирный косяк АктивФорма. А точнее даже хелпера Html::error(). Потому, как если убрать ту регулярку вроде пробелмы пропадают. И тут либо что-то мы упускаем, либо косячелло.
Если убрать ту регулярку, часть функционала не будет работать.
только для админки, ну понятно, что для продакшина человек в здравом уме виджеты yii не использует
Продакшена? Я использую виджеты yii и в бекенде, и в фронтенде. И вроде на здравый ум не так часто жалуются
Yii::$container->set('yii\widgets\ActiveForm', [
'fieldClass' => 'app\components\backend\ActiveField',
]);
Только учтите, что в других местах будет использоваться этот класс(в зависимости где вы это указали). Если используете ActiveForm в других местах и явно не задаете fieldClass, то что-то у вас скорее всего поломается. Не проще указать в конфиге ActiveForm? С DIC как раз нужно быть осторожней.
По непонятным причинам, обрабатывая набор некоторых сущностей, вы пытаетесь слепить их вместе и ругаетесь, что решение вам не подходит, а поэтому неправильное. Ну, на ошибках учимся.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.02, 10:42
nepster
rak писал(а):nepster писал(а):Вот как раз наоборот скорее всего. У меня вся логика инкапсуляция в разных моделях, а не вешаются глобальные непонятные поведения на всю модель. Я уже это проходит. Если у вас несколько сценариев и все завязано на одной форме, то оптом геморроя будет прилично. Если ваше приложение хоть чуть-чуть больше блога, с актив рекордом нужно быть очень осторожным.
По теме, такое вариант работает (привет велосипедам), но проблема в том, что мне нужна логика валидации. Например если вы указали дефолтный язык, то для друго-го валидация на required будет необязательна. В свою очередь, если вы указали другой язык, то тоже самое для дефолтного.
Как только нужно сделать что-то кастомное, виджеты yii сыпятся.
тут проблема скорее с проектированием бд.
по-хорошему, нужно все поля, которые необходимо переводить, вынести в отдельную таблицу бд. по сути поведение, которое я скидывал выше и реализует эту логику, причем не создавая дополнительных моделей.
но можно его и не использовать, а реализовать тоже самое самому.
стандартная валидация yii отлично работает для определенной структуры, если начинать выдумывать что-то свое, то естественно, что стандартные варианты не будут работать без напильника.
но вот для чего городить огород для задач, которые уже 100 раз решались ранее - не понятно
В бд все впорядке. Отдельная табилца, ключи, все дела. У вас просто не было задач посложнее.
Nerf писал(а):Just fo lulz...
Вот как раз наоборот скорее всего. У меня вся логика инкапсуляция в разных моделях
Как раз наоборот наоборот. Логика в разных моделях звучит многообещающе... Почитайте про SOLID.
Если ваше приложение хоть чуть-чуть больше блога, с актив рекордом нужно быть очень осторожным.
О Боже, какой мужчина! ActiveRecord - это ORM по одноименному шаблону проектирования. Что же там такого опасного?
но проблема в том, что мне нужна логика валидации. Например если вы указали дефолтный язык, то для друго-го валидация на required будет необязательна. В свою очередь, если вы указали другой язык, то тоже самое для дефолтного.
И почему для этого не работают rules()?
Как только нужно сделать что-то кастомное, виджеты yii сыпятся.
Потому что вы пытаетесь их использовать не по назначению.
Мне кажется это жирный косяк АктивФорма. А точнее даже хелпера Html::error(). Потому, как если убрать ту регулярку вроде пробелмы пропадают. И тут либо что-то мы упускаем, либо косячелло.
Если убрать ту регулярку, часть функционала не будет работать.
только для админки, ну понятно, что для продакшина человек в здравом уме виджеты yii не использует
Продакшена? Я использую виджеты yii и в бекенде, и в фронтенде. И вроде на здравый ум не так часто жалуются
Yii::$container->set('yii\widgets\ActiveForm', [
'fieldClass' => 'app\components\backend\ActiveField',
]);
Только учтите, что в других местах будет использоваться этот класс(в зависимости где вы это указали). Если используете ActiveForm в других местах и явно не задаете fieldClass, то что-то у вас скорее всего поломается. Не проще указать в конфиге ActiveForm? С DIC как раз нужно быть осторожней.
По непонятным причинам, обрабатывая набор некоторых сущностей, вы пытаетесь слепить их вместе и ругаетесь, что решение вам не подходит, а поэтому неправильное. Ну, на ошибках учимся.
1) SOLID никакого отношения не имеет к Yii2. В Yii2 почти каждый класс нарушет принцип единой ответственности. И как говорил Александр, можно обойтись без SOLID и Yii2 это некий баланс между безнесом и суровым ооп. Поэтому писать по SOLID в рамках Yii2 крайне тяжело, а иногда и невозможно.
2) ActiveRecord - на больших проектах это очень опасная штука. Я уже 500 раз описывал ее проблемы. Все у кого выростает проект, рано или позжно понимают, что неправильно приготовленный ActiveRecord - это полный ад.
3) По поводу нерабочего функционала, ну может быть, поэтому пока я сам првоерю и уже позже смогу казать подробнее.
4) "Я использую виджеты yii и в бекенде, и в фронтенде. И вроде на здравый ум не так часто жалуются
" - потому, что вы не решаете "суровые" задачи. Для прототипов и стандартны штуковен это то что нужно.
5) и по поводу ActiveForm. Мне такое поведение нужно только в админке, на фронте я не рискую больше использовать актив форм. Используя DI контейнер мы просто подменяем данные помолчанию. Тоесть в остальных случаях будет стандартное значение. Это делается для того, чтобы каждой форме не прописывать конфиг.
На самом деле DI это очень крутая штука, которой не пользуются в Yii2, потому что так исторически сложилось.
Re: Как указать ошибку для конкретного поля, которое является массивом ?
Добавлено: 2016.03.02, 16:07
Nerf
1) SOLID никакого отношения не имеет к Yii2. В Yii2 почти каждый класс нарушет принцип единой ответственности. И как говорил Александр, можно обойтись без SOLID и Yii2 это некий баланс между безнесом и суровым ооп. Поэтому писать по SOLID в рамках Yii2 крайне тяжело, а иногда и невозможно.
Это всего лишь набор принципов. Я не настаиваю, что нужно строго следовать им везде. Но стараться придерживаться их, наверное, все же неплохо. На самом деле, не зная что в действительности представляют ваши объекты, я могу быть не прав, но со стороны кажется, что вы делаете "велосипед с квадратными колесами".
ActiveRecord - на больших проектах это очень опасная штука. Я уже 500 раз описывал ее проблемы. Все у кого выростает проект, рано или позжно понимают, что неправильно приготовленный ActiveRecord - это полный ад.
Очень интересно услышать доводы. Наверное, "неправильно приготовленный ActiveRecord - это полный ад" - ключевое. Что не есть проблема AR.
4) "Я использую виджеты yii и в бекенде, и в фронтенде. И вроде на здравый ум не так часто жалуются
" - потому, что вы не решаете "суровые" задачи. Для прототипов и стандартны штуковен это то что нужно.
Выпейте немного "антиЧСВина". Что же в них такого ужасного, опасного и т.п., чтобы их не использовать?
Используя DI контейнер мы просто подменяем данные помолчанию. Тоесть в остальных случаях будет стандартное значение. Это делается для того, чтобы каждой форме не прописывать конфиг.
В остальных случаях будет то, что вы указали в DIC, если явно не указано что использовать. Т.е. в других виджетах ActiveForm будет использоваться переопределенный класс.
На самом деле DI это очень крутая штука, которой не пользуются в Yii2, потому что так исторически сложилось.
Не используете вы => все? В "ядре" Yii используется.