Проверка формы HABTM в CakePHP - PullRequest
5 голосов
/ 11 января 2010

У меня есть таблица Projects и таблица Users, которые связаны отношением HABTM. На странице «Добавить» новый проект у меня есть раздел с несколькими флажками для выбора пользователей для нового проекта. Я хочу иметь хотя бы одного пользователя для проекта. Какой лучший способ подойти к этому в CakePHP?

Ответы [ 7 ]

19 голосов
/ 11 января 2010

Попробуйте это:

// app/models/project.php
/**
 * An additional validation check to ensure at least one User is
 * selected. Spoofs Cake into thinking that there are validation
 * errors on the Project model by invalidating a non-existent field
 * on the Project model, then also invalidates the habtm field as
 * well, so when the form is re-displayed, the error is displayed
 * on the User field.
 **/
function beforeValidate() {
  if (!isset($this->data['User']['User'])
  || empty($this->data['User']['User'])) {
    $this->invalidate('non_existent_field'); // fake validation error on Project
    $this->User->invalidate('User', 'Please select at least one user');
  }
  return true;
}
12 голосов
/ 07 мая 2013

Я наткнулся на ту же проблему, но сейчас - 3 года спустя - с CakePHP 2.3 .

Чтобы быть ясно; Group имеет и принадлежит User. У меня была такая форма:

// View/Groups/add.ctp
echo $this->Form->input('name');
echo $this->Form->input('User');

С правилом проверки, как в ответе пользователя user448164:

// Model/Group.php
public $validate = array(
    'User' => array(
        'rule' => array('multiple', array('min' => 1)),
        'message' => 'Please select one or more users'
    )
);

Это не сработало, после поиска в Google, я нашел этот вопрос, который все еще не мог быть лучшим решением. Затем я попробовал несколько вещей и обнаружил, что это работает нормально:

// View/Groups/add.ctp
echo $this->Form->input('name');
echo $this->Form->input('Group.User');

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

Надеюсь, однажды это кому-нибудь поможет.

Обновление для CakePHP 2.4.x (возможно, также 2.3.x)

Когда я писал этот ответ, я использовал CakePHP 2.3.x. Тогда он отлично работал как для проверки, так и для сохранения данных. Теперь при применении того же кода в новом проекте, используя CakePHP 2.4.x, он больше не работал.

Я создал тестовый пример, используя следующий код:

$data = array(
    'User' => array(
        'Client' => array(8)
    ),
);
$this->User->create();
$this->User->saveAll($data);

Моей первой мыслью было: сохранение всех означает сохранение всех «корневых» моделей, что на самом деле имеет для меня смысл. Чтобы сохранить глубже, чем просто «корневые», вам нужно добавить опцию deep. В итоге я получил следующий код:

$data = array(
    'User' => array(
        'Client' => array(8)
    ),
);
$this->User->create();
$this->User->saveAll($data, array('deep' => true));

Работает как шарм! Удачного кодирования. :)

Обновление (2014/03/06)

Снова сталкиваемся с той же проблемой, в данном случае с hasMany вместо habtm. Похоже, что он ведет себя так же. Но я снова нашел этот ответ и запутался.

Я бы хотел пояснить, что ключом для ввода Group.User вместо User. В противном случае он не будет использовать проверку модели User.

6 голосов
/ 15 сентября 2010

Я только что сам посмотрел на его проблему в проекте и нашел немного более элегантное решение, если вы имеете дело только с отношениями habtm и вам нужно убедиться, что установлен хотя бы один флажок.

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

Добавьте это к beforeValidate ()

// проверить модель habtm и добавить к данным

  foreach($this->hasAndBelongsToMany as $k=>$v) {
   if(isset($this->data[$k][$k]))
   {
    $this->data[$this->alias][$k] = $this->data[$k][$k];
   }
  }

В правилах проверки добавить следующее:

'User' => array(
   'rule' => array('multiple', array('min' => 1)),
   'message' => 'Please select one or more users'
  )
2 голосов
/ 14 января 2016

2016 обновление для CakePhp 2.7

Полный ответ здесь: Проверка формы HABTM с CakePHP 2.x


TL; DR;

AppModel.php

public function beforeValidate($options = array()){
   foreach (array_keys($this->hasAndBelongsToMany) as $model){
     if(isset($this->data[$model][$model]))
       $this->data[$this->name][$model] = $this->data[$model][$model];
   }
   return true;
 }

 public function afterValidate($options = array()){
   foreach (array_keys($this->hasAndBelongsToMany) as $model){
     unset($this->data[$this->name][$model]);
     if(isset($this->validationErrors[$model]))
       $this->$model->validationErrors[$model] = $this->validationErrors[$model];
   }
   return true;
 }

В основной модели вашего HABTM:

public $validate = array(
    'Tag' => array(
        'rule' => array('multiple', array('min' => 1)),
        'required' => true,
        'message' => 'Please select at least one Tag for this Post.'
        )
    );
2 голосов
/ 11 января 2010

В блоге teknoid есть довольно глубокое решение вашей проблемы здесь. Наиболее эффективный способ сделать это - добавить пользовательскую проверку вашей модели, как вы упомянули в своем комментарии выше. Проверить http://teknoid.wordpress.com/2008/10/16/how-to-validate-habtm-data/

Из статьи, где тег HABTM Post (:: Пользователи Project HABTM):

Сначала мы проверяем модель тега, используя данные из формы, чтобы обеспечить что хотя бы один тег был выбран. Если Итак, мы сохраняем сообщение и соответствующие Теги.

1 голос
/ 24 июля 2013

Если вы используете CakePHP 2.3.x , вам может потребоваться добавить этот код в вашу модель в дополнение к коду, предоставленному GuidoH, в противном случае ваши данные модели HABTM могут не сохраниться:

public function beforeSave($options = array()){
  foreach (array_keys($this->hasAndBelongsToMany) as $model){
    if(isset($this->data[$this->name][$model])){
      $this->data[$model][$model] = $this->data[$this->name][$model];
      unset($this->data[$this->name][$model]);
    }
  }
  return true;
}
0 голосов
/ 24 апреля 2014

В соответствии с моим комментарием к ответу Гвидо выше, я точно использую ответ Гвидо, однако я изменяю данные обратным вызовом beforeSave до его сохранения в базе данных.

У меня есть эта проблема на Cake 2.4.5 +

public function beforeSave($options = array()) {
    $temp = $this->data['Group']['User'];
    unset($this->data['Group']['User']);
    $this->data['User']['User'] = $temp;

    return true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...