编程语言
首页 > 编程语言> > CakePHP 3.0.8转换行为和数据验证(requirePresence,notEmpty)

CakePHP 3.0.8转换行为和数据验证(requirePresence,notEmpty)

作者:互联网

我的问题很简单,但我不知道如何解决.

我的网站是多语言的.我希望用户能够根据需要添加多种语言的文章,同时要求输入语言(取决于语言环境).

问题是,根据CakePHP的翻译约定,无论使用哪种语言,所有输入都必须以字段名称结尾.因此,所有字段对于同一字段都具有相同的规则.我不能要求一个“名称”,而不需要另一种语言的名称.

例如,默认语言的输入为:

<input type="text" name="name" required="required" maxlength="45" id="name">

然后,在同一字段中输入另一种语言:

<input type="text" name="locales[fr_CA][name]" required="required" maxlength="45" id="locales-fr-ca-name">

由于以下规则,“必需”属性会自动添加到这两个属性:

$validator
    ->requirePresence('name', 'create')
    ->notEmpty('name')
    ->add('name', [
        'length' => [
            'rule' => ['minLength', 10],
            'message' => 'The title needs to be at least 10 characters long.',
        ]
    ]);

注意:保存时,必须将语言环境更改为默认语言(en_US),以便能够以多种语言保存默认语言(否则,默认输入将保存在默认表以及i18n表中).

if ($this->request->is('post')) {
    I18n::locale('en_US');
    // ......

编辑:所以这是我保存(IngredientsController.php)时的完整代码

public function add() {
    $ingredient = $this->Ingredients->newEntity();
    if ($this->request->is('post')) {
        $ingredient = $this->Ingredients->patchEntity($ingredient, $this->request->data);

        if(isset($this->request->data['locales'])) {
            foreach ($this->request->data['locales'] as $lang => $data) {
                $ingredient->translation($lang)->set($data, ['guard' => false]);
            }
        }

        $locale = I18n::locale(); // At this point the locale is fr_CA (not de default)
        I18n::locale('en_US'); // Change the locale to the default

        if ($this->Ingredients->save($ingredient)) {
            $this->Flash->success(__('The ingredient has been saved.'));
            I18n::locale($locale); // Put the locale back to the user's locale
            return $this->redirect(['action' => 'index']);
        } else {
            I18n::locale($locale);
            $this->Flash->error(__('The ingredient could not be saved. Please, try again.'));
        }
    }

    $this->set(compact('ingredient'));
    $this->set('_serialize', ['ingredient']);
}

我设置默认语言环境是bootstrap.php

/**
 * Set the default locale. This controls how dates, number and currency is
 * formatted and sets the default language to use for translations.
 */
ini_set('intl.default_locale', 'en_US');
Configure::write('Config.locales', ['fr_CA']);

我在AppController.php中确定用户的语言环境

public function beforeFilter(Event $event)
{
    $locales = Configure::read('Config.locales');
    $boom = explode(',', str_replace('-', '_', $_SERVER['HTTP_ACCEPT_LANGUAGE']));
    $user_lang = substr($boom[0], 0, 2);

    // This piece of code is only to change the locale to fr_CA even if the user's language is just fr or fr_FR
    if(in_array($user_lang, Configure::read('Config.langs'))) {
        if(in_array($boom[0], $locales)) {
            I18n::locale($boom[0]);
        } else {
            foreach ($locales as $locale) {
                if(substr($locale, 0, 2) == $user_lang) {
                    I18n::locale($locale);
                }
            }
        }
    }

    $this->set('locales', $locales);
    $this->set('locale', I18n::locale());
}

因此,如果在与默认设置不同的语言环境下保存时,相同的默认输入将保存在配料表以及fr_CA的i18n表中

解决方法:

默认值保存在翻译表中

在更改默认语言环境的情况下,将默认语言的输入存储在翻译表中的事实似乎是预期的行为,就像在读取数据时会根据当前语言环境检索数据一样,保存数据时同样如此.

Cookbook > Database Access & ORM > Behaviours > Translate > Saving in Another Language

将语言环境更改为默认值是一种解决方法,但可能会带来一些干扰,因为它会干扰使用该值检查当前语言环境的任何代码.最好直接在表格上设置所需的语言环境

$Ingredients->locale(I18n::defaultLocale());

或者,这是侵入性最小的选项,而是在主要实体上

$ingredient->_locale = I18n::defaultLocale();

同样,前者是链接文档部分所描述的但没有实际显示的内容,需要修复.

字段选择“错误的”验证规则

虽然我可以看到为什么表单助手(分别是实体上下文)为“错误的”字段选择了验证规则,即xyz.name字段为name字段选择了验证规则,但我无法确定这是怎么回事上班.

> https://github.com/cakephp/cakephp/blob/3.0.10/src/View/Form/EntityContext.php#L394
> https://github.com/cakephp/cakephp/blob/3.0.10/src/View/Form/EntityContext.php#L439

由于它不会出现嵌套错误,因此我想这是预期的行为,但是我不确定,因此我建议使用create an issue over at GitHub进行说明.在任何情况下,都有多种解决方法,例如,通过重命名字段或将必需的选项设置为false.

echo $this->Form->input('locales.fr_CA.name', [
    // ...
    'required' => false
]);

在您的示例中,这几乎只是一个前端问题,因为这些字段实际上不会在服务器端进行验证.

另一个选择是使用自定义转换表类,其中特定于转换的验证实际上适用于所使用的字段,但是,除非您实际上确实想应用任何验证,否则这不建议这样做.

将验证/应用规则应用于已翻译的列

为了完整起见,我们也涵盖验证/应用程序规则.

为了实际应用验证和/或应用程序规则,并使它们在表单中被识别,您将使用一个保存规则的自定义转换表类,并且必须使用转换行为用于hasMany的实际属性名.关联的翻译表,即_i18n.

这是一个例子.

SRC /型号/表/ IngredientsI18nTable.php

namespace App\Model\Table;

use Cake\Datasource\EntityInterface;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class IngredientsI18nTable extends Table
{
    public function initialize(array $config) {
        $this->entityClass('Ingredient');
        $this->table('i18n');
        $this->displayField('id');
        $this->primaryKey('id');
    }

    public function validationDefault(Validator $validator) {

        $validator
            ->allowEmpty('name')
            ->add('name', 'valid', [
                'rule' => function ($value, $context) {
                    return false;
                }
            ]);
        return $validator;
    }

    public function buildRules(RulesChecker $rules)
    {
        $rules->add(
            function (EntityInterface $entity, $options) {
                return false;
            },
            'i18nName',
            [
                'errorField' => 'name'
            ]
        );

        return $rules;
    }
}

IngredientsTable

public function initialize(array $config) {
    // ...

    $this->addBehavior('Translate', [
        // ...
        'translationTable' => 'IngredientsI18n'
    ]);
}

查看范本

echo $this->Form->hidden('_i18n.0.locale', ['value' => 'fr_FR']);
echo $this->Form->input('_i18n.0.name');

echo $this->Form->hidden('_i18n.1.locale', ['value' => 'da_DK']);
echo $this->Form->input('_i18n.1.name');

// ...

现在,这些字段将选择正确的验证器,因此不会被标记为必填项.创建/修补实体时还将应用验证,最后还要应用应用规则.但是我不能保证这没有任何副作用,因为内部的Translate行为似乎无法说明_i18n属性已在外部设置的情况!

同样,您仍然必须使用translations()在实体上设置翻译,以便正确保存翻译!

foreach ($this->request->data['_i18n'] as $translation) {
    $ingredient->translation($translation['locale'])->set('name', $translation['name']);
}

标签:php,validation,cakephp,cakephp-3-0,internationalization
来源: https://codeday.me/bug/20191009/1877956.html