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

これはハックで、私は好きではありませんが、よりも便利なようです$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);
}

これにより、フィールド変更ロジックを2回(配列用に1回、非配列用に1回)記述する必要がないため、コードの重複が減少します。

メソッドの最後に戻るだけで参照を完全に回避できる$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);」のように新しいフィールドを作成することをお勧めします。モデル検索が他のモデルから呼び出された場合、2回実行されます。

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 に答える