1

みなさん、こんにちは。

最近、私はベータ版アプリケーションを純粋なPHP/jQueryからCakePHP/ExtJSに変換するという任務を負っています(これは私が初めてです)。

私の問題は、メイングリッドに入力する最も複雑なクエリにあります。

物事を単純にするために、正しいベイクされた関係とモデルを持つ3つのテーブルがあります:Projects、、ToDoExtraToDo

Projects hasMany ToDoExtraToDo

ToDoExtraToDo列がTitleありCompleteます。

私の目標は、これら3つの表に基づいて、各プロジェクトの完了率を取得することです。 私がこれについて行った方法は、列のSUMを列のCOUNTComplete割ったものです。私はCakePHPの方法で読みやすさ/パフォーマンス/otherstuffIdontknowyetを試しています。Complete

もともと、生のSQLでは、次のように実行していました。

SELECT
  `idProject`,

  (SELECT
    ROUND((SUM(`Complete`) / COUNT(`Complete`)) * 100),
   FROM
    (SELECT `Complete`, `ProjectID` FROM `ToDo`
      UNION ALL
     SELECT `Complete`, `ProjectID` FROM `ExtraToDo`) orders
   WHERE
    `ProjectID` = `idProject`
  ) AS 'Completion'

FROM 
  `Projects`

また、CakePHPを決定する前に試した、KohanaPHPMVCフレームワークでこれをかなり簡単に機能させることができました。私は彼らのクエリがどのように作成されたかが大好きでした...:

private function get_completion() {
  $Query = DB::select('ProjectID', array(DB::expr('ROUND((SUM(`Complete`) / COUNT(`Complete`)) * 100)'), 'Completion'))
    ->from(array('ToDo', 'ExtraToDo'))
    ->group_by('ProjectID');

  return $Query;
}

public function get_all() {
  $Query = DB::select()
    ->from('Projects')
    ->join(array(self::get_completion(), 'Completion'))
    ->on('projects.id', '=', 'Completion.ProjectID')
    ->execute()
    ->as_array();

  return $Query;      
}

残念ながら、CakePHPの方法でこれを実行している間、CakePHPでこれを機能させるのに完全に苦労しました。

virtualFieldsが私の答えの鍵であると確信していますが、ドキュメントを読んでx、y、zを試した後です。私はそれらとそれらがどのように関係しているかを理解することができませんでした。

よろしくお願いします-T6

4

2 に答える 2

1

ProjectモデルクラスにafterFind()関数を作成するか、この計算を実行する必要があるときに呼び出す関数を追加することをお勧めします。

計算を実行する関数は次のようになります。

getPercentageComplete($project){
{
$total_todos = count($project['ToDo']);
$completed_todos = 0;
foreach($project['ToDo'] as $todo){
   if($todo['Complete']) //assuming this is a boolean field
        $completed_todos++;
}
return $completed_todos / $total_todos;
}

次に、afterFindは次のようになります。

function afterFind(&$results)
{
  foreach ($results as &$project)
  {
   $project['Project']['percentageComplete'] = $this->Project->getPercentageComplete($project);
   }
return $results;
}

afterFind()の詳細については、CakePHPBakery- >コールバックメソッドをご覧ください。

于 2013-01-02T03:06:54.900 に答える
1

それはネストされた選択の多くです。IMOは、より良いクエリを作成したほうがよいでしょう。

これでうまくいくはずです。

class Project extends AppModel {
    public $findMethods = array(
        'completion' => true
    );

    // other code

    protected function _findCompletion($state, $query, $results = array()) {
        if ($state == 'before') {
            $this->virtualFields['total'] = 'ROUND((SUM(Todo.Complete + TodoExtra.Complete) / (COUNT(Todo.Complete) + COUNT(TodoExtra.Complete))) * 100)';

            $query['fields'] = array(
                $this->alias . '.' . $this->primaryKey,
                'total'
            );

            $query['joins'] = array(
                array(  
                    'table' => 'todos', 
                    'alias' => 'Todo', 
                    'type' => 'left', 
                    'foreignKey' => false, 
                    'conditions'=> array('Todo.project_id = ' , $this->alias . '.' . $this->primaryKey) 
                ),
                array(  
                    'table' => 'todo_extras', 
                    'alias' => 'TodoExtra', 
                    'type' => 'left', 
                    'foreignKey' => false, 
                    'conditions'=> array('TodoExtra.project_id = ' . $this->alias . '.' . $this->primaryKey) 
                ),
            );

            $query['group'] = array(
                $this->alias . '.' . $this->primaryKey
            );
            return $query;
        }

        return $results;
    }

    // other code
}

find('first')これで、またはのように使用できるカスタム検索メソッドができfind('all')ました。

コントローラから:

$this->Project->find('completion');

またはプロジェクトモデルで

$this->find('completion');

次のようなものが返されるはずです。

$results = array(
    0 => array(
        'Project' => array(
            'id' => 1,
            'total' => 50
        )
    ),
    1 => array(
        'Project' => array(
            'id' => 2,
            'total' => 75
        )
    )
);
于 2013-01-03T12:58:36.940 に答える