2011-06-28 14 views
5

您好只是質疑最好的辦法讓從警予模型的相關數據並返回JSON

IM對正在使用的前端SproutCore的一個項目,一個寧靜的應用程序的工作。

我的問題其實只是什麼是需要返回JSON時,與其他相關模型的模型中獲取數據的最有效方法。我昨天讀到,它推薦在處理數組時使用DAO層,所以對於我的示例,這是迄今爲止我所擁有的。

我有一個客戶列表,每個客戶端HAS_MANY品牌和每個品牌HAS_MANY項目。不 得到一個很好的形成陣列後面的客戶與thier品牌繼承人我有什麼

$clients = Yii::app()->db->createCommand('select client.* from client where client.status = 1')->queryAll(); 

     foreach($clients as $ckey => $client) 
     { 
      $clients[$ckey] = $client; 
      $brand_ids = Yii::app()->db->createCommand('select brand.id as brand_id, brand.client_id as b_client_id from brand where brand.client_id ='.$client['id'])->queryAll(); 

      foreach($brand_ids as $bkey => $brand_id) 
      { 
       $clients[$ckey]['brands'][] = $brand_id['brand_id']; 
      } 

    } 

這回我想要什麼,但迄今爲止它是要實現什麼IM之後的最有效的方法?

+0

如果您沒有CActiveRecord對象用於您的表「客戶端」,請先執行它(請參閱:http://www.yiiframework.com/doc/guide/1。1/EN/database.ar)。 ('brand') - > findByAttributes(array('status'=> 1));' –

+0

( )然後你將能夠獲得簡單的數據: '$ clients = Client :: model() - >作爲im將要返回json是不是更好地與DAO層一起工作,因爲使用ar執行quries會返回比我需要更多信息的地獄。所以當我來編碼數組我結束了更多的對象比我需要返回?? –

+0

如果我理解正確: 1)你可以編寫你想要選擇的列(拋出模型類'客戶端'並且關聯到'品牌') 2)接下來,在選擇這些後執行'foreach'語句 2.1)並像你在你的問題示例中那樣轉換爲json / 我仍然建議先爲表創建模型。我首先要做,如果我對錶格進行全局更改,我只改變我的模型類。 –

回答

1

如果您不想使用使用with()功能的CActiveRecord,那麼您應該編寫一個SQL查詢加入brand表。

$rows = Yii::app()->db 
    ->createCommand(
     'SELECT c.*, b.id as brand_id 
     FROM client c INNER JOIN brand b 
     WHERE c.status = 1 AND b.client_id = c.id') 
    ->queryAll(); 
$clients = array(); 
foreach ($rows as row) { 
    if (!isset($clients[$row['id']])) { 
     $clients[$row['id']] = $row; 
     $clients[$row['id']]['brands'] = array(); 
    } 
    $clients[$row['id']]['brands'][] = $row['brand_id']; 
} 

這比做一次查詢檢索所有客戶端,然後做N次查詢來獲取自己的品牌(其中N是客戶端的數量)更有效。您也可以加入您的第三張表projects並檢索每個品牌的所有相關項目。

+0

嘿再次galymzhan,似乎回答我所有的yii相關的主題! 這似乎是一個更合理的方法,但是在嘗試你的例子時我很努力地讓json返回很好,php在將數組轉換成json時似乎做了一些時髦的事情。我不斷嘗試用你的例子來根據客戶端請求的需要構建數組! –

3

設置客戶模型

class Client extends CActiveRecord 
{  
    //... 
    /** 
    * @return array relational rules. 
    */ 
    public function relations() 
    { 
      // NOTE: you may need to adjust the relation name and the related 
      // class name for the relations automatically generated below. 
      return array(
        'brands' => array(self::HAS_MANY, 'Brand', 'client_id'), 
      ); 
    } 
    //... 
    public function defaultScope() { 
     return array('select'=>'my, columns, to, select, from, client'); //or just comment this to select all "*" 
    } 

} 

設置品牌模型

class Brand extends CActiveRecord 
{ 
    //... 
    /** 
    * @return array relational rules. 
    */ 
    public function relations() 
    { 
      // NOTE: you may need to adjust the relation name and the related 
      // class name for the relations automatically generated below. 
      return array(
        'client' => array(self::BELONGS_TO, 'Client', 'client_id'), 
      ); 
    } 
    //... 
    //... 
    public function defaultScope() { 
     return array('select'=>'my, columns, to, select, from, brand'); //or just comment this to select all "*" 
    } 

} 

做客戶端/品牌的搜索結果在您的動作功能

$clients = Client::model()->with('brands')->findAllByAttributes(array('status'=>1)); 

$clientsArr = array(); 
if($clients) { 
    foreach($clients as $client) { 
     $clientsArr[$client->id]['name'] = $client->name; //assign only some columns not entire $client object. 
     $clientsArr[$client->id]['brands'] = array(); 

     if($client->brands) { 
      foreach($client->brands as $brand) { 
       $clientsArr[$client->id]['brands'][] = $brand->id; 
      } 
     } 

    } 
} 

print_r($clientsArr); 
/* 
Array (
    [1] => Array (
     name => Client_A, 
     brands => Array (
      0 => Brand_A, 
      1 => Brand_B, 
      2 => Brand_C 
     ) 
    ) 
    ... 
) 

*/ 

這是你想要的? 我意識到,如果你想只選擇品牌ID(在別的沒有更多的數據),你可以通過SQL和GROUP_CONCAT(MySQL的)搜索並用逗號分開一行選擇所有品牌的IDS客戶端。 1,2,3,4,5,20,45,102

1

我意識到這是舊的,但我一直在尋找一個解決方案,我認爲這是一個很好的解決方案。

以我基Controller類(被保護/組件/ Controller.php這樣)添加以下功能:

protected function renderJsonDeep($o) { 
    header('Content-type: application/json'); 
     // if it's an array, call getAttributesDeep for each record 
    if (is_array($o)) { 
     $data = array(); 
     foreach ($o as $record) { 
      array_push($data, $this->getAttributesDeep($record)); 
     } 
     echo CJSON::encode($data); 
    } else { 
      // otherwise just do it on the passed-in object 
     echo CJSON::encode($this->getAttributesDeep($o)); 
    } 

     // this just prevents any other Yii code from being output 
    foreach (Yii::app()->log->routes as $route) { 
     if($route instanceof CWebLogRoute) { 
      $route->enabled = false; // disable any weblogroutes 
     } 
    } 
    Yii::app()->end(); 
} 

protected function getAttributesDeep($o) { 
     // get the attributes and relations 
     $data = $o->attributes; 
    $relations = $o->relations(); 
    foreach (array_keys($relations) as $r) { 
      // for each relation, if it has the data and it isn't nul/ 
     if ($o->hasRelated($r) && $o->getRelated($r) != null) { 
        // add this to the attributes structure, recursively calling 
        // this function to get any of the child's relations 
      $data[$r] = $this->getAttributesDeep($o->getRelated($r)); 
     } 
    } 
    return $data; 
} 

現在,調用renderJsonDeep一個對象,或對象的陣列上,將編碼對象(一個或多個),包括任何你已經拉過的關係,比如將它們添加到DbCriteria中的'with'參數中。

如果子對象有什麼關係,這些將在JSON,以及因爲getAttributesDeep被遞歸調用設置。

希望這可以幫助別人。