2011-06-28 16 views
5

Hola acaba de cuestionarmejor manera de obtener datos relacionados de modelos en yü y volver JSON

im trabajando en una aplicación de descanso para un proyecto que está utilizando SproutCore en la parte delantera.

Mi pregunta es realmente ¿cuál es la forma más efectiva de obtener datos de un modelo con otros modelos relacionados cuando se necesita devolver json? Leí ayer que se recomienda trabajar la capa DAO cuando se trabaja con matrices, por lo que para mi ejemplo esto es lo que tengo hasta ahora.

Tengo una lista de clientes, cada cliente tiene marcas HAS_MANY y cada marca tiene proyectos HAS_MANY. No obtener una gama muy bien formado parte posterior de clientes con arreglan sus marcas Heres lo que tengo

$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']; 
      } 

    } 

Esto está regresando lo que quiero hasta ahora, pero es la manera más eficaz de lograr lo que im después ??

+0

Si no tiene el objeto CActiveRecord para su tabla 'client', hágalo primero (consulte: http://www.yiiframework.com/doc/guide/1.1/es/database.ar). Y después de eso, podrá obtener datos simples como: '$ clients = Client :: model() -> with ('brand') -> findByAttributes (array ('status' => 1));' –

+0

Como voy a estar volviendo json, ¿no es mejor trabajar con la capa DAO que realizar qurios usando ar? Devuelve muchísima más información de la que necesito. así que cuando llegué a codificar la matriz, terminé con más objetos de los que necesito devolver? –

+0

Si entendí correcto que: 1) Puede escribir las columnas que desea seleccionar (lanzar clase de modelo 'Cliente' y hacer relación a' Marca') 2) a continuación, hacer la declaración 'foreach' después de seleccionar estos 2.1) y conviértalo en json como lo hizo en su ejemplo de pregunta / . Todavía lo recomiendo primero para crear modelos para tablas. Lo hago primero y si tuve algunos cambios globales sobre la tabla, cambio solo mi clase de modelo. –

Respuesta

1

Si no desea utilizar CActiveRecord utilizando la funcionalidad with(), debe escribir una consulta SQL que se una a la tabla 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']; 
} 

Esto es mucho más eficiente que hacer una consulta para recuperar todos los clientes y luego hacer consultas N a buscar sus marcas (donde N es el número de clientes). También puede unirse a su tercera tabla projects y recuperar todos los proyectos relacionados para cada marca.

+0

Hola otra vez galymzhan, parece que estoy respondiendo a todos mis temas relacionados con yii !! Esto parece ser un enfoque mucho más sensato, sin embargo, al probar tu ejemplo me costaba recuperar el json, php parece hacer algunas cosas funky al convertir arreglos en json. Seguiré intentando con tu ejemplo construir la matriz según sea necesario para la solicitud del cliente. –

3

de configuración de cliente modelo

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 "*" 
    } 

} 

Configuración Marca modelo

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 "*" 
    } 

} 

Utilizar búsqueda/marca del cliente en su función de acción

$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 
     ) 
    ) 
    ... 
) 

*/ 

Es esto que querías? Me doy cuenta, si quieres seleccionar sólo ID de marca (en ningún otro dato más) puedes buscar por sql y GROUP_CONCAT (MySQL) y seleccionar todos los identificadores de marca para el cliente en una fila separados por comas. 1,2,3,4,5,20,45,102.

1

Me doy cuenta de que esto es antiguo, pero yo estaba buscando una solución yo mismo y pensé que era una buena idea.

En mi clase controlador base (protegido/Componentes/controller.php) I añadieron las siguientes funciones:

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

Ahora, llamando renderJsonDeep en un objeto, o conjunto de objetos, codificará el objeto (s) en JSON, incluidas las relaciones que haya realizado, como agregarlas al param con 'en' en DbCriteria.

Si el objeto secundario tiene alguna relación, también se establecerá en el JSON, ya que getAttributesDeep se llama de forma recursiva.

Espero que esto ayude a alguien.

Cuestiones relacionadas