简体   繁体   中英

CakePHP saving HABTM data

I have 2 models, Client and Security . They are associated with a HATBTM relationship. I have made a join table called clients_securities . So a Client can have many securities and a Security can belong to many Client s.

在此输入图像描述

Here are my relationship definitions:

 //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,
        )
);

I then made an edit action in my clients controller and did this:

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'));
        }
    }

In my edit view I build the form using the HtmlHelper, adding the client table fields and generating the multiple select with:

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

In addition I also have normal direct form inputs for the Client in the same form. eg

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

All these inputs get generated and populated with the correct values when the form is rendered but only the direct Client data is saved, not the HABTM data from the multi-select.

When I submit the form the clients_securities table is not populated with the join IDs.

What do I need to do to save it correctly and have then have the saved securities be pre-selected when I reload the "edit" view.


Edit: To clarify things, here is a pr() of $this->request->data . (The values ("ALLCMCT LX Equity") are the correct foreign keys for the securities table):

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
                )

        )

)

So essentially, say my client id was 12345, Cake should insert 2 records in the clients_securities table like so:

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

If I manually add some join records into clients_securities , when I go to edit a client the securities in the multi-select come up correctly pre-selected showing that the data is being read from the join table. When I save the form it actually removes the join records but does not save new ones.

Additional note: My security IDs are stored as CHAR(36) if that has any effect. This is not an auto-increment field, it contains the ticker of the security and each is unique.

The problem is in the format of the security_id and Security.id : char is unsupported.

I found this ticket (but I don't find any reference in the documentation)

you must create another column with a numeric id to use in the HABTM association

像这样修改表单输入:

echo $this->Form->input('Security.Security');
<?php 
Model::saveAssociated(array $data = null, array $options = array());

or

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

For more info please visit: http://book.cakephp.org/2.0/en/models/saving-your-data.html

I'll give it a try...

You forgot $this->Client->read(); after $this->Client->id = $id; in the edit() function (the internal of $this->Client are not initialized, so no client_id is present at the moment when save is done). The call "findById" will return only an array, but won't read the data to the object $this->Client.

Just a good educated guess..

也许我已经知道了,但我想您忘了在视图中创建一个带有客户端ID的隐藏输入

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

Its not populating mediater table because After populating both models It does not have their id to populate mediater table. So user beforeSave and afterSave function which will populate your mediator table. Add beforesave function in Client model

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;
    }

And in Security user AfterSave function,

public $securityIdArray = array();

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

First save security and use $securityIdArray to get id of security after $this->Model->save in your controller.

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

And yah As @Arilia said Modify you forum input field

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

and don't make saperate forms for both models

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM