如何将CakePHP 2模型关联更改为与bindModel和自定义查找程序的深层链接?

时间:2017-01-01 01:22:15

标签: php mysql cakephp associations cakephp-2.x

我正在尝试复制这个有效的SQL查询结果:

SELECT r.id, r.day, s.ddbroute_id, s.delivery_id, d.id, d.laststatusid, t.id, t.delivery_id, t.statusstage_id, st.id, st.stage
FROM ddbroutes r
LEFT JOIN ddbrouteslots s on r.id = s.ddbroute_id
LEFT JOIN deliveries d on s.delivery_id = d.id
LEFT JOIN trackingstatuses t on d.laststatusid = t.id 
LEFT JOIN statusstages st on t.statusstage_id = st.id

我正在使用带有

的CakePHP 2模型
  1. bindModel可以动态更改模型关联
  2. 自定义查找将逻辑放入模型
  3. 第二级以外的底部表没有共同字段。 错误消息是:'Model“Ddbroute”与模型“Delivery”无关。因此,我在'contains'数组中尝试使用和不使用Delivery,并且不会带来Delivery字段。 如果合适的话,我很乐意使用连接。我已经阅读了StackOverflow上我发现的最相关的帖子。

    我的代码包含更多信息,如下所示。感谢任何帮助。

    我有五个表(包括以下字段):

    ddbroutes (id, day)
    ddbrouteslots (id, ddbroute_id, delivery_id)
    deliveries (id, laststatusid)
    trackingstatuses (id, statusstage_id)
    statusstages (id, stage)
    

    模型中设置了以下关系:

    Ddbroute hasMany Ddbrouteslot (Ddbrouteslot belongsTo Ddbroute)
    Delivery hasOne Ddbrouteslot (Ddbrouteslot belongsTo Delivery)
    Delivery hasMany Trackingstatus (Trackingstatus belongsTo Delivery)
    Statusstage hasMany Trackingstatus (Trackingstatus belongsTo Statusstage)
    

    虽然Delivery hasOne Ddbrouteslot(这将是hasMany - 已修改 - 现在仍为hasOne),对于任何单个Ddbroute,每个Ddbrouteslot只有一个Delivery关联。可以在所有型号中设置包含。我不知道我是否需要先使用unbindModel(它没有更改错误信息)。

    我在Ddbroute.php模型文件中的代码(仅限于交付表)

    public $findMethods = array('ddbstatuses' => true);
    
      protected function _findDdbstatuses($state, $query, $results = array()) {
          if ($state === 'before') {
            $ddbrouteslotmodel = ClassRegistry::init('Ddbrouteslot');
            $ddbrouteslotmodel->unbindModel(
              array('belongsTo' => array('Delivery'))
            );
            $ddbrouteslotmodel->bindModel(
              array('hasOne' => array(
                'Delivery' => array(
                  'className' => 'Delivery',
                  'foreignKey' => 'id',
                  'dependent' => false,
                  'fields' => array(
                    'id', 'laststatusid'
                  )
                  )
                ))
              );
    
              $deliverymodel = ClassRegistry::init('Delivery');
              $deliverymodel->unbindModel(
                array('hasOne' => array('Ddbrouteslot'))
              );
              $deliverymodel->bindModel(
                array('belongsTo' => array(
                  'Delivery' => array(
                    'className' => 'Delivery',
                    'foreignKey' => 'delivery_id'
                    )
                  )
                )
              );
    
              $query['contain'] = array(
                'Ddbrouteslot', 'Delivery'
              );
            return $query;
          }
            return $results;
        }
    

    在另一个控制器中,运行查找操作:

    $this->LoadModel('Ddbroute');
    $ddbstatuses = $this->Ddbroute->find('ddbstatuses');
    $this->set(compact('ddbstatuses')); // to make available in a view
    

    我还尝试了一个长连接数组,但查询没有引入任何Delivery,Trackingstatus或Statusstage信息,尽管查询似乎已经运行。

      public $findMethods = array('ddbstatuses' => true);
    
      protected function _findDdbstatuses($state, $query, $results = array()) {
      if ($state === 'before') {
    
        ClassRegistry::init('Delivery'); // not sure these three lines were needed so I tried with and without them
        ClassRegistry::init('Trackingstatus');
        ClassRegistry::init('Statusstage');
    
    
    
        $query['joins'] = array(
          array(
            'table' => 'ddbrouteslots',
            'alias' => 'Ddbrouteslot',
            'type' => 'LEFT',
            'conditions' => array(
                'Ddbroute.id = Ddbrouteslot.ddbroute_id'
          )),
          array(
            'table' => 'deliveries',
            'alias' => 'Delivery',
            'type' => 'LEFT',
            'conditions' => array(
              'Ddbrouteslot.id = Delivery.id'
          )),
          array(
            'table' => 'trackingstatuses',
            'alias' => 'Trackingstatus',
            'type' => 'LEFT',
            'conditions' => array(
              'Delivery.laststatusid = Trackingstatus.id'
          )),
          array(
            'table' => 'statusstages',
            'alias' => 'Statusstage',
            'type' => 'LEFT',
            'conditions' => array(
              'Trackingstatus.statusstage_id = Statusstage.id'
          ))
      );
    
    
        $query['contain'] = array(
            'Ddbrouteslot',
              'Delivery',  // Not sure I should be adding these other models, so I tried with and without them
              'Trackingstatus',
              'Statusstage'
          );
        return $query;
      }
      return $results;
    }
    

1 个答案:

答案 0 :(得分:0)

经过一些帮助,我现在有四个解决方案来获取我的数据,尽管其中有三个是第一个的变体。我相对缺乏经验,有些基本的东西我不欣赏。

<强> 1。在控制器中

$this->LoadModel("Ddbrouteslot");
$res = $this->Ddbrouteslot->find("all", array(
  "conditions" => array(
    "Ddbrouteslot.delivery_id > 0",
    "Ddbrouteslot.ddbroute_id" => 45
),
"contain" => array(
    "Ddbroute",
    "Delivery" => array(
"Trackingstatus" => array(
   "order" => array(
   "Trackingstatus.id" => "desc"
    ),
    "limit" => 1,
    "Statusstage"
   )
  )
 )
);

来自DebugKit的时间:主查询是20ms; Trackingstatus和Statusstage是额外的查询,每个18毫秒x 4四个相关的交付;总时间为164毫秒。这很慢,这并不理想。

这是从第二个模型Ddbrouteslot开始的,因为它与Ddbroute和Delivery都有直接关系。任何协会都没有变化。 从Ddbrouteslot到Delivery的belongsTo关系运行良好。 delivery_id上的Delivery和Trackingstatus之间已经存在很多关系。

<强> 2。使用SQL

$this->LoadModel("Ddbroute");
$qres = $this->Ddbroute->query(
    "SELECT *
    FROM 
    ddbroutes AS r
    LEFT JOIN ddbrouteslots s on r.id = s.ddbroute_id
    LEFT JOIN deliveries d on s.delivery_id = d.id
    LEFT JOIN trackingstatuses t on d.laststatusid = t.id 
    LEFT JOIN statusstages st on t.statusstage_id = st.id
    WHERE s.delivery_id > 0 AND s.ddbroute_id = 45
;"
debug($qres);
时间:这花了19毫秒。这意味着它要快得多。 Cake文档中不建议这样做,显然它不像纯Cake发现那样可以在数据库之间移植。

第3。更改基础模型

$rres = $this->Ddbroute->find("all", array(
    "conditions" => array(
    "Ddbroute.id" => 45
),
"recursive" => -1,
"contain" => array(

        "Ddbrouteslot" => array(
            "conditions" => array(
                "Ddbrouteslot.delivery_id > 0"
            ),
            "Delivery" => array(
                "Trackingstatus" => array(
                    "order" => array(
                        "Trackingstatus.id" => "desc"
                    ),
                    "limit" => 1,
                    "Statusstage"
                )
            )
        )
    )
));
debug($rres);

时间:主查询是18ms;交付,Trackingstatus和Statusstage每个18ms,4个相关交付;总时间为234毫秒。它的速度较慢,因为需要为每个发货运行Delivery,因为它不在Ddbroute的模型中。 改变递归并没有什么不同。

<强> 4。使用自定义查找 这与上面1.)的查询相同,但只是使用自定义查找方法。

public $findMethods = array('ddbstatuses' => true);   
protected function _findDdbstatuses($state, $query, $results = array()) {
    if ($state === 'before') {       
        $query['conditions'] = array(
          "Ddbrouteslot.delivery_id > 0",
          "Ddbrouteslot.ddbroute_id" => 45
        );
        $query['contain'] = array(
          "Ddbroute",
          "Delivery"=> array(
             "Trackingstatus" => array(
                "order" => array(
                "Trackingstatus.id" => "desc"
             ),
             "limit" => 1,
                "Statusstage"
              )
           )
          );
         return $query;
      }   
   return $results;
}