2013-09-19 3 views
11

У меня есть 2 модели, Client и Security. Они связаны с отношением HATBTM. Я сделал таблицу соединений под названием clients_securities. Таким образом, Client может иметь много ценных бумаг, а Security может принадлежать многим Client.CakePHP сохранение данных HABTM

enter image description here

Вот мои определения отношения:

//Client Model: 
public $hasAndBelongsToMany = array(
    'Security' => 
     array(
      'className' => 'Security', 
      'joinTable' => 'clients_securities', 
      'foreignKey' => 'client_id', 
      'associationForeignKey' => 'security_id', 
      'unique' => true, 
     ) 
); 

//Security Model: 
public $hasAndBelongsToMany = array(
    'Client' => 
     array(
      'className' => 'Client', 
      'joinTable' => 'clients_securities', 
      'foreignKey' => 'security_id', 
      'associationForeignKey' => 'client_id', 
      'unique' => true, 
     ) 
); 

Я тогда сделал действие редактирования в мой контроллер клиентов и сделал это:

public function edit($id = null) { 
     if (!$id) { 
      throw new NotFoundException(__('Invalid client')); 
     } 

     $client = $this->Client->findById($id); 
     if (!$client) { 
      throw new NotFoundException(__('Invalid client')); 
     } 

     if ($this->request->is('post') || $this->request->is('put')) { 
      $this->Client->id = $id; 
      if ($this->Client->saveAll($this->request->data)) { 
       $this->Session->setFlash(__('Client has been updated.')); 
       return $this->redirect(array('action' => 'edit', $id)); 
      } 
      $this->Session->setFlash(__('Unable to update client.')); 
     } 

     if (!$this->request->data) { 
      $this->request->data = $client; 
      $this->set('securities', $this->Client->Security->find('list')); 
     } 
    } 

На мой взгляд редактирования я строю формы с помощью HtmlHelper, добавляя поля таблицы клиента и генерируя множественный выбор с помощью:

echo $this->Form->create('Client'); //start the form for the client model 
echo $this->Form->input('Security'); //generates a multi-select popuplated with securities 

Кроме того, у меня также есть обычные входы прямой формы для Client в том же виде. например

echo $this->Form->input('name'); //Input for the client name 
echo $this->Form->input('currency'); //Input for the client currency 
... 

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

Когда я отправляю форму, таблица clients_securities не заполняется идентификаторами объединения.

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


Edit: Для того, чтобы прояснить вещи, вот pr() из $this->request->data. (значение («ALLCMCT LX Equity») являются правильными внешними ключами для securities таблицы):

Array 
(
    [Client] => Array 
     (
      [id] => 1212 
      [name] => Example Client 
      [currency] => GBP 
      [partner] => 
      [risk_category_id] => 4 
      [client_code_id] => 1 
      [min_cash_balance] => 0 
      [active] => 1 
      [model] => 0 
      [institutional] => 0 
      [non_uk_situs] => 0 
      [reporting_status] => 0 
     ) 

    [Security] => Array 
     (
      [Security] => Array 
       (
        [0] => .1muslib3 index 
        [1] => .eurib3 index 
        [2] => .ukcpi2 index 
       ) 

     ) 

) 

Так по существу, сказать, что мой идентификатор клиента был +12345, торт должен вставить 2 записей в clients_securities таблице как так :

id | client_id | security_id 
---------------------------- 
1 | 12345  | ALLCMCT LX Equity 
2 | 12345  | APMKNTD LX Equity 

Если я вручную добавить некоторые присоединиться к записи в clients_securities, когда я иду редактировать клиенту ценные бумаги в мульти-выбора придумать правильно предварительно выбран, показывая, что данные считываются из соединительной таблице. Когда я сохраняю форму, она фактически удаляет записи соединения, но не сохраняет новые.

Дополнительное примечание: Мои идентификаторы безопасности хранятся в виде CHAR (36), если это имеет какой-либо эффект. Это не поле auto-increment, оно содержит тикер безопасности, и каждый из них уникален.

+0

Смотрите эту Http: // StackOverflow .com/a/18891807/1239506 –

+0

Я прочитал все связанные вопросы, которые я могу найти без успеха. – harryg

+0

Он должен работать так, как вы. Во всяком случае, вы попробовали «уникальный» => «keepExisting»? Кроме того, я не думаю, что формат ID является проблемой, но просто для того, чтобы убедиться, что вы пытались использовать фальшивый идентификатор INT? И наконец: не могли бы вы разместить полную информацию о параметрах 'pr ($ this-> request->)' (без конфиденциальных данных, конечно) – arilia

ответ

5

Проблема заключается в формате security_id и Security.id : char не поддерживается.

Я нашел этот ticket (но я не нашел каких-либо ссылок в документации)

вы должны создать еще один столбец с числовым id использовать в HABTM ассоциации

+0

Если я изменю свой тип столбца на CHAR (36), это разрешит его? Изменить: нет, это не так. – harryg

+0

Могла ли она работать, если я переработаю свои отношения в 'hasMany' и' ownTo'? Как мне это сделать? – harryg

+2

На мой взгляд, лучший способ - использовать числовой идентификатор и переименовать текущий идентификатор в нечто вроде «name» или «alfanumeric_identifier». Если вы не можете этого сделать, вы можете вручную сохранить элементы в таблице 'clients_securities', помещая массив' $ this-> request-> data ['Security'] ['Security'] 'в foreach cicle. то есть '$ this-> Client-> ClientsSecurity-> save (array ('client_id' => $ client_id, 'security_id' => $ security_id));'. Просто не забудьте сначала удалить старые отношения – arilia

0
<?php 
Model::saveAssociated(array $data = null, array $options = array()); 

or 

Model::saveAll(array $data = null, array $options = array()); 
?> 

Для получения дополнительной информации, пожалуйста, посетите: http://book.cakephp.org/2.0/en/models/saving-your-data.html

+0

Пожалуйста, дайте мне знать, если какой-либо trubble в вышеуказанном коде. рад помочь вам :) –

+0

Я попытался сменить 'save' на' saveAll', но не повезло. Не похоже, что данные в множественном выборе отправляются вместе с другими данными. – harryg

+0

Если я вручную добавлю запись объединения в базу данных, она заполняет и предварительно выбирает ценные бумаги правильно. Это просто не спасет. – harryg

1

измените форму ввода, как так:

echo $this->Form->input('Security.Security'); 
+0

Извините, ничего не измените – harryg

0

Я дам ему попробовать ...

Вы забыли $ this-> Client-> read(); после $ this-> Client-> id = $ id; в функции edit() (внутренняя часть $ this-> Client не инициализируется, поэтому клиентский_ид не присутствует в момент сохранения). Вызов «findById» возвращает только массив, но не будет читать данные объекту $ this-> Client.

Просто хорошая догадка ..

+0

Извините, без изменений. – harryg

0

Может быть, я worng, но я предполагаю, что вы забыли создать скрытый вход с идентификатором клиента на ваш взгляд

echo $this->Form->hidden('Client.id'); 
+0

Форма уже связана с 'Client', и в ней есть вход для идентификатора клиента. Полные данные запроса теперь в вопросе – harryg

0

Его не заселять mediater таблицы, потому что После заполнения обеих моделей у него нет своего идентификатора для заполнения таблицы медиатора. Таким образом, функция beforeSave и afterSave пользователя заполняет вашу таблицу посредников. Добавить BeforeSave функцию клиента модели

public function beforeSave($options = array()) { 
     parent::beforeSave($options = array()); 
      foreach (array_keys($this->hasAndBelongsToMany) as $model): 
       if(isset($this->data[$this->alias][$model])): 
        $this->data[$model][$model] = $this->data[$this->alias][$model]; 
        unset($this->data[$this->alias][$model]); 
       endif; 
      endforeach; 
     return true; 
    } 

И в безопасности функции пользователя AfterSave,

public $securityIdArray = array(); 

public function afterSave($created) { 
     if($created) { 
      $this->securityIdArray[] = $this->getInsertID(); 
     } 
     return true; 
    } 

Сначала сохраните безопасность и использовать $ securityIdArray получить идентификатор безопасности после $ this-> Модель-> сохранить в контроллер.

$this->Security->securityIdArray[] = $void['Security']['id']; 

И йах Как @Arilia сказал Modify You форум поле ввода

echo $this->Form->input('Security.Security'); 

и не делают saperate формы для обеих моделей

+0

Re вашей последней точкой, в которой формируется модель, принадлежит к полю 'Security.Security'?Целью является присвоение клиенту 1 или более ценных бумаг, что аналогично назначению тегов сообщению. Конечно, форма Клиента верна. – harryg

+0

Кроме того, модель «Ценные бумаги» никогда не бывает, и ее не нужно заполнять, а только таблицу соединений. В таблице уже есть ценные бумаги. Цель состоит в том, чтобы выбрать кого-то и заставить их «принадлежать» клиенту. – harryg

Смежные вопросы