问题 CakePHP 2.x:Model :: afterFind()上的$ primary标志实际上有用吗?


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 阵,或者我错过了什么?

1697
2017-12-31 21:45


起源



答案:


的确如此 $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 阵列。


11
2018-04-23 01:31



今天遇到这个问题。有时$ result结果集是一个多维数组,有时它不是。我觉得这应该是一个非常大的问题。 - vinhboy
哇,我可以吻你。在我敲了4个小时后,这才救了我。 - bowlerae


答案:


的确如此 $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 阵列。


11
2018-04-23 01:31



今天遇到这个问题。有时$ result结果集是一个多维数组,有时它不是。我觉得这应该是一个非常大的问题。 - vinhboy
哇,我可以吻你。在我敲了4个小时后,这才救了我。 - bowlerae


如果你不能总是依赖 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;
}

1
2018-02-07 15:50





我遇到了这个问题。接受的答案很有效。但是,我不得不做一个小调整。如果你想修改一个字段,例如从logo构造一个完全限定的文件名,最好创建一个新字段,如“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'];
        }
    }

0
2018-01-27 01:14





书中的答案......

$ primary参数指示当前模型是否为   查询所源自的模型或此模型是否存在   被问到是一个协会。如果模型被查询为关联   $ results的格式可能不同;

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

因此,它在某些情况下可用于逻辑处理,并且可能用于对$结果产生影响


-2
2018-01-07 14:05



您可能会注意到我引用了相同的文档部分。但是,正如我在我的问题中所说,如果 $primary 被设定为 false 这并不一定意味着 $results 将以任何不同的格式。正如文档所说,“格式 $results  能够 不一样。“但话说回来,它可能不会。实验支持这一点。 - eaj