11

CakePHP 的Model::afterFind()回调如下所示:

afterFind(array $results, boolean $primary = false)

根据文档:

$primary参数指示当前模型是否是发起查询的模型,或者该模型是否作为关联进行查询。如果将模型作为关联进行查询,则其格式$results可能会有所不同。

它们可以不同,但​​实验表明它们并不总是不同的。据我所知,该$primary参数实际上并不是那么有用。如果它设置为false您可能会或可能不会获得扁平的数据结构,因此您可能会或可能不会收到可怕的“不能将字符串偏移量用作数组”错误消息。

虽然我还没有尝试过,但我基于文档的想法是$primary完全忽略该标志并仅检查数据:

public function afterFind($results, $primary = false) {
  if (array_key_exists(0, $results) {
    // operate on $results[0]['User']['fieldname']
  } else {
    // operate on $results['fieldname']
  }
  return $results;
}

这是 hackish,我不喜欢它,但它似乎可能比$primary.

明确地说,我的问题是:

  1. $primary旗帜实际上有什么用?
  2. 我是否正确地说它对确定数组的结构没有$results用,还是我错过了一些东西?
4

4 回答 4

12

实际上,该$primary参数似乎仅在警告您格式$results不可预测的情况下有用。它在确定$results.

更多信息在这里:https ://groups.google.com/forum/?fromgroups=#!topic/cake-php/Mqufi67UoFo

那里提供的解决方案是检查!isset($results[$this->primaryKey])格式是什么$results。这也有点小技巧,但可以说比检查密钥“0”更好。

我最终想出的解决方案是做这样的事情:

public function afterFind($results, $useless) {

    // check for the primaryKey field
    if(!isset($results[$this->primaryKey])) {
        // standard format, use the array directly
        $resultsArray =& $results;
    } else {
        // stupid format, create a dummy array
        $resultsArray = array(array());
        // and push a reference to the single value into our array
        $resultsArray[0][$this->alias] =& $results;
    }

    // iterate through $resultsArray
    foreach($resultsArray as &$result) {
        // operate on $result[$this->alias]['fieldname']
        // one piece of code for both cases. yay!
    }

    // return $results in whichever format it came in
    // as but with the values modified by reference
    return parent::afterFind($results, $useless);
}

这减少了代码重复,因为您不必编写字段更改逻辑两次(一次用于数组,一次用于非数组)。

您可以通过$resultsArray在方法结束时返回来完全避免引用的东西,但我不确定如果 CakePHP(或其他一些父类)期望$results它被传入的方式会导致什么问题。另外这种方式没有复制$results数组的开销。

于 2013-04-23T01:31:14.600 回答
1

如果您不能总是依赖在primaryKey字段列表中并且您知道要查找的密钥,则可以使用更简单的方法。这是一个例子:

/**
 * Decrypt password
 *
 * @see Model::afterFind()
 */
public function afterFind($results, $primary = false) {        
    if (!empty($results['password'])) {
        $results['password'] = Security::rijndael($results['password'], Configure::read('encrypt.key'), 'decrypt');
        return $results;
    }

    foreach ($results as &$r) {
        if (!empty($r[$this->alias]['password'])) {
            $r[$this->alias]['password'] = Security::rijndael($r[$this->alias]['password'], Configure::read('encrypt.key'), 'decrypt');
        }
    }
    return $results;
}
于 2014-02-07T15:50:58.780 回答
0

我遇到了这个问题。接受的答案效果很好。然而,我不得不做一个小的调整。如果您要修改字段,例如从徽标构造一个完全限定的文件名,最好创建一个新字段,如“return parent::afterFind($results, $useless);” 如果从其他模型调用模型 find 将执行两次。

foreach($resultsArray as &$result) {
        // operate on $result[$this->alias]['fieldname']
        // one piece of code for both cases. yay!

        // Added logoFull instead of modifying logo
        if(isset($result[$this->alias]['logo'])){
            $result[$this->alias]['logoFull'] = Configure::read('urlImg') . 'logos' . DIRECTORY_SEPARATOR .
                'carrier' . DIRECTORY_SEPARATOR . $result[$this->alias]['logo'];
        }
    }
于 2014-01-27T01:14:44.617 回答
-2

书中的答案...

$primary 参数指示当前模型是否是发起查询的模型,或者此模型是否作为关联进行查询。如果将模型作为关联进行查询,则 $results 的格式可能会有所不同;

如果使用递归查找,则期望 $primary 为 true 的代码可能会从 PHP 中得到“不能将字符串偏移量用作数组”的致命错误。

因此,它在某些情况下可能对逻辑处理很有用,并且可以用来对您的 $results 产生连锁反应

于 2013-01-07T14:05:46.853 回答