CakePHP 2.X: запретить saveAssociated() создавать запись, если она уже существует

У меня есть следующие модели:

class Useragent extends AppModel {

    public $validate = array(
        'useragent' => array(
            'unique' => array(
                'rule' => 'isUnique',
            ),
        )
    );

    public $hasMany = array(
        'LoggedActions'
    );
}

а также

class LoggedAction extends AppModel {

    public $belongsTo = array(
        'Useragent' => array(
            'className' => 'Useragent',
        )
    }
} 

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

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

    $data=array(
        'LoggedAction'=>array(
            'ip_address' => 3232235521, //INET_ATON format
        ),
        'Useragent'=>array(
            'useragent'=>'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
        )
    );

    $this->LoggedAction->saveAssociated($data);

Я хочу Useragent модель игнорировать сохранение, если пользовательский агент уже присутствует в useragents стол (основан исключительно на поле Useragent.useragent, не на Useragent.id что неизвестно при выполнении сохранения).

Я знаю, что могу реализовать это на контроллере, имея дело с Useragent сначала а потом с LoggedAction, Тем не менее, я хотел бы, чтобы модель позаботилась об этом прозрачно.

  • Возвращая ложь в Useragent::beforeSave() если запись существует не работает, так как ничего не сохраняется.
  • Замена Useragent['id'] в Useragent::beforeSave() с id из существующей записи, полученной из базы данных, не будет проверяться. Удаление правила проверки приведет к Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY',

Возможность переопределить Useragent::save() метод, так что он игнорирует операцию сохранения, но устанавливает Useragent->id к id записи, извлеченной из базы данных и возвращающей массив (как при обычном сохранении), но не уверен, что это нарушит другие функции.

Другой вариант - написать метод с именем LoggedAction::saveWithUseragent(), который будет реализовывать описанную функциональность. Но, как я уже сказал, я хотел бы модель Useragent позаботиться об этом как можно более прозрачно.

Есть ли лучший способ реализовать это, что мне не хватает?

1 ответ

Я наконец решил переопределить Useragent::save(),

Вот так мой Useragent класс теперь выглядит:

class Useragent extends AppModel
{

    public $displayField = 'useragent';

    public $hasMany = array(
        'LoggedActions'
    );


    public function save($data = null, $validate = true, $fieldList = array()){

        if ($useragent=$this->findByUseragent($data['useragent'])){
            $this->id=$useragent[$this->alias]['id'];
            return($useragent);
        }
        return parent::save($data,$validate,$fieldList);
    }
}

Пока проблем нет.

Тот же подход можно использовать для тегов, связанных с другими моделями.

Другие вопросы по тегам