cakephp 模型 saveAssociated 错误 - 不能将字符串偏移量用作数组

Posted

技术标签:

【中文标题】cakephp 模型 saveAssociated 错误 - 不能将字符串偏移量用作数组【英文标题】:cakephp model saveAssociated error - Cannot use string offset as an array 【发布时间】:2013-11-19 11:22:21 【问题描述】:

我这里有一个梨形的。它把我逼疯了,花了一天的时间在上面。我希望有人可以快速浏览一下并指出明显的内容。

我几乎完成了从 1.3.14 到 2.4.2 的 cakephp 升级。我遇到的其余问题之一是 saveAll 模型调用......它实际上是正确插入第一个数组的数据,但其余部分抛出异常。

我得到的错误是:

Error: Cannot use string offset as an array 
File: /srv/www/test/public_html/app/Lib/cakephp/lib/Cake/Model/Model.php    
Line: 2453

如果我查看 Model.php,问题就出现在这里:

        case 'hasMany':
            foreach ($values as $i => $value) 

                if (isset($values[$i][$association])) 
                    $values[$i][$association][$key] = $this->id;
                 else                         
                    $values[$i] = array_merge(array($key => $this->id), $value, array($key => $this->id));
                
            

$values[$i][$association][$key] = $this->id;

我在这里转储了输出,本例 $values[$i][$association] = 3,它不是数组。

现在,查看发布的数据,我看不出有什么问题。和 cake1.3.14 一样。

发布数据的 var_dump:

array(3) 
  ["Client"]=>
  array(20) 
    ["NAME"]=>
    string(6) "ZZTEST"
    ["PHONE"]=>
    string(0) ""
    ["X_PHONE2"]=>
    string(0) ""
    ["FAX"]=>
    string(0) ""
    ["EMAIL"]=>
    string(0) ""
    ["X_REQUIRE_PO"]=>
    string(1) "N"
    ["TAXREG"]=>
    string(0) ""
    ["CREDLIMIT"]=>
    string(5) "10000"
    ["X_QCHECKAPP"]=>
    string(1) "Y"
    ["X_PUBLIC_LIABILITY_EXPIRY"]=>
    string(10) "19-03-2014"
    ["ADDRESS1"]=>
    string(0) ""
    ["ADDRESS2"]=>
    string(0) ""
    ["POST_CODE"]=>
    string(0) ""
    ["DELADDR1"]=>
    string(0) ""
    ["DELADDR2"]=>
    string(0) ""
    ["DELADDR6"]=>
    string(0) ""
    ["NOTES"]=>
    string(0) ""
    ["HEAD_ACCNO"]=>
    int(-1)
    ["CURRENCYNO"]=>
    int(0)
    ["AVE_DAYS_TO_PAY"]=>
    int(-1)
  
  ["ClientRateGroup"]=>
  array(1) 
    ["rate_group_id"]=>
    string(1) "3"
  
  ["ClientExtra"]=>
  array(2) 
    ["client_type_id"]=>
    string(1) "1"
    ["client_salesperson_id"]=>
    string(2) "25"
  

控制器的一个sn-p:

class ClientsController extends AppController

public $name = 'Clients';
public $uses = array('ExonetClient', 'Quote');

// The saveAll call is causing the problem
function add()


    if (!empty($this->request->data)) 
        $this->request->data['ExonetClient']['HEAD_ACCNO']      = -1;
        $this->request->data['ExonetClient']['CURRENCYNO']      = 0;
        $this->request->data['ExonetClient']['AVE_DAYS_TO_PAY'] = -1;
        $this->Client->create();
        unset($this->ExonetClient->ClientRateGroup->validate['client_id']);
        unset($this->ExonetClient->ClientExtra->validate['client_id']);

        // Allow an entry to clients_rate_groups table if the rate group is
        //selected for a client
        if (!empty($this->request->data['ClientRateGroup']['rate_group_id'])
            || !empty($this->request->data['ClientExtra']['client_type_id'])
        ) 

            if ($this->ExonetClient->saveAll($this->request->data, array('validate' => true)) === true) 
                //
                // If an AJAX request, then echo the ID of the item.
                if ($this->RequestHandler->isAjax()) 
                    echo $this->ExonetClient->getLastInsertId();
                    exit;
                
                else 
                    $this->Session->setFlash(
                        __('The client has been saved successfully'),
                        'default',
                        array('class' => 'success')
                    );

                    $this->redirect(array('action' => 'index'));
                
            
            else 
                $error = __('The client could not be saved. Please, try again.');
                if ($this->RequestHandler->isAjax()) 
                    $this->set('error_message', $error);
                
                else 
                    $this->Session->setFlash($error);
                
            
        


以下是相关模型:

客户:

App::uses('AppModel', 'Model');

class ExonetClient extends AppModel

    public $name         = 'ExonetClient';
    public $actsAs       = array(
        'CakephpAssets.Logable' => array('change' => 'serialize', 'userModel' => 'User', 'userKey' => 'user_id'),
        'LocationStorage' => array(),
    );
    public $useDbConfig  = 'exonet';
    public $useTable     = 'DR_ACCS';
    public $primaryKey   = 'ACCNO';
    public $displayField = 'NAME';

    public $hasMany      = array(
        'ContactLink' => array(
            'className'  => 'ExonetClientContact',
            'foreignKey' => 'ACCNO',
            'dependent'  => true,
        ),
        'SubcontractorIncompatibility' => array(
            'className'  => 'ClientsSubcontractor',
            'foreignKey' => 'client_id',
            'dependent'  => true,
        ),
        'Docket' => array(
            'className' => 'Docket',
            'foreignKey' => 'client_id',
            'dependent' => false,
        ),
        'SpreadsheetQueue' => array(
            'className' => 'SpreadsheetQueue',
            'foreignKey' => 'client_id',
            'dependent' => false,
        ),
        'Spreadsheet' => array(
            'className' => 'Spreadsheet',
            'foreignKey' => 'client_id',
            'dependent' => false,
        ),
        'ClientRateGroup' => array(
            'className' => 'ClientRateGroup',
            //'joinTable' => 'clients_rate_groups',
            'foreignKey' => 'client_id',
            //'associationForeignKey' => 'client_id',
            //'unique' => true,
            'dependent' => true,
            'conditions' => '',
            //'fields' => '',
            'order' => array('effective_date' => 'DESC', 'expiry_date' => 'DESC'),
            'limit' => '',
            'offset' => '',
            'finderQuery' => ''
            //'deleteQuery' => '',
            //'insertQuery' => ''
        ),


    );

ClientExtra:

App::uses('AppModel', 'Model');
class ClientExtra extends AppModel

    public $name = 'ClientExtra';
    public $validate = array(
        'client_type_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'allowEmpty' => true,
            ),
        ),
        'client_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
            ),
        ),
    );
    //The Associations below have been created with all possible keys, those that are not needed can be removed

    public $belongsTo = array(
        'ClientType' => array(
            'className' => 'ClientType',
            'foreignKey' => 'client_type_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'Client' => array(
            'className'  => 'ExonetClient',
            'foreignKey' => 'client_id',
            'conditions' => '',
            'fields'     => '',
            'order'      => ''
        ),
        'Salesperson' => array(
            'className' => 'Salesperson',
            'foreignKey' => 'client_salesperson_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );

ClientRateGroup:

App::uses('AppModel', 'Model');

class ClientRateGroup extends AppModel

    public $useTable = 'clients_rate_groups';
    public $name = 'ClientRateGroup';
    public $validate = array(
        'rate_group_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                'allowEmpty' => true,
            ),
        ),
        'client_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
            ),
        ),
        'effective_date' => array(
            'date' => array(
                'rule' => array('date'),
            ),
        ),
    );

    public $belongsTo = array(
        'RateGroup' => array(
            'className' => 'RateGroup',
            'foreignKey' => 'rate_group_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'Client' => array(
            'className'  => 'ExonetClient',
            'foreignKey' => 'client_id',
            'conditions' => '',
            'fields'     => '',
            'order'      => ''
        )
    );

【问题讨论】:

请注意,您的错误消息中的行号与您在 2.4.2 中显示的型号代码不匹配 我在里面有一些调试语句,一定是把行号弄错了。绝对是 2.4.2 代码库 【参考方案1】:

您的数据格式不正确,无法保存hasMany 关联数据。检查docs for Model::saveAssociated()

为了保存一条记录及其具有hasMany关联的相关记录,数据数组应该是这样的:

$data = array(
    'Article' => array('title' => 'My first article'),
    'Comment' => array(
        array('body' => 'Comment 1', 'user_id' => 1),
        array('body' => 'Comment 2', 'user_id' => 12),
        array('body' => 'Comment 3', 'user_id' => 40),
    ),
);

所以你的ClientRateGroup 键应该包含一个数据数组的数组,类似于:

'ClientRateGroup' => array(
    array('rate_group_id' => 3)
)

也许你的ClientExtra 数据也应该这样格式化,不确定Client 模型上没有适当的关联,很可能这实际上应该是Client hasOne ClientExtra 关联,很难说。

【讨论】:

自蛋糕 1.3.14 以来这是否发生了变化?我将尝试按照 saveAssociated 文档重新格式化请求。 @AdamP 我不确定,现在无法测试,但 1.3 的书提倡相同的风格:book.cakephp.org/1.3/en/The-Manual/Developing-with-CakePHP/…

以上是关于cakephp 模型 saveAssociated 错误 - 不能将字符串偏移量用作数组的主要内容,如果未能解决你的问题,请参考以下文章

Cakephp:使用`saveAssociated()`时如何将`parent_id`保存到基于树的模型中?

Cakephp saveAssociated 和 SaveAll Nothing 正常工作

在 CakePHP 中保存新的关联记录

CakePHP如何在一个saveAll中不知道外键的情况下创建hasMany数据?

CakePHP- 保存相关模型数据

CakePHP 模型关联深层模型包含