Problema Con Scope En Relational Active Record

Hola gente, estoy tratando de aplicar un scopes en un ActiveRecord con relaciones:


Grupos::model()->with(array('grado' => array('scopes' => 'superiores')))->findAll();

Pero el scopes no se aplica, he probado directamente el modelo con el scope independientemente de la relacion y funciona perfectamente.

Tambien he probado asi:


Grupos::model()->findAll(array('with' => array('sede', 'grado' => array('scopes' => array('superiores')))));

Segun la DOC: http://www.yiiframework.com/doc/guide/1.1/en/database.arr#relational-query-with-named-scopes

Deberia funcionar.

Podrian ayudarme, gracias.

Hola Ramiro,

La forma más sencilla de aplicar un scope es:


Grupos::model()->nombreScope()->findAll()

y para las relaciones, en estos casos es saludable agregar "together"… es decir algo como:


Grupos::model()->together()->findAll(array('with'=>array(...)))

Ah, cabe agregar que estos scopes tienen que ser de los definidos en la función "scopes" del modelo "Grado"… es decir, el scope "superiores" debe existir en "scopes" del modelo "Grado".

Saludos

Hola robregonm gracias por la respuesta, el scope es del modelo grado declarado en la relación, por eso lo llamo dentro de with


Grupos::model()->findAll(array('with' => array('sede', 'grado' => array('scopes' => array('superiores')))));

El


together()

tampoco lo resolvió…

Perfecto, pruebe agregando el "together"…

Si no le funciona, podría publicar el modelo Grupos y el modelo Grado para echarles un vistazo?

Saludos

Por cierto, otra forma de aplciar scopes en relaciones es:


Grupos::model()->with('grado:superiores')->findAll();

Es decir,

  1. No necesariamente incluido en el findAll()

  2. Usando los "dos puntos" (: )

Ok, modelo Grupos:




<?php


/**

 * This is the model class for table "{{grupos}}".

 *

 * The followings are the available columns in table '{{grupos}}':

 * @property integer $codigrup

 * @property string $codisede

 * @property integer $codigrad

 * @property string $nombgrup

 */

class Grupos extends CActiveRecord {


  /**

   * Returns the static model of the specified AR class.

   * @param string $className active record class name.

   * @return Grupos the static model class

   */

  public static function model($className = __CLASS__) {

    return parent::model($className);

  }


  /**

   * @return string the associated database table name

   */

  public function tableName() {

    return '{{grupos}}';

  }


  /**

   * @return array validation rules for model attributes.

   */

  public function rules() {

    // NOTE: you should only define rules for those attributes that

    // will receive user inputs.

    return array(

      array('codisede, codigrad, nombgrup', 'required'),

      array('codigrad', 'numerical', 'integerOnly' => true),

      array('codisede', 'length', 'max' => 20),

      array('nombgrup', 'length', 'max' => 30),

      // The following rule is used by search().

      // Please remove those attributes that should not be searched.

      array('codigrup, codisede, codigrad, nombgrup', 'safe', 'on' => 'search'),

    );

  }


  /**

   * @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(

      'sede' => array(self::BELONGS_TO, 'Sedes', 'codisede'),

      'grado' => array(self::BELONGS_TO, 'Grados', 'codigrad'),

      'cursos' => array(self::HAS_MANY, 'Cursos', 'codigrup')

    );

  }


  /**

   * @return array customized attribute labels (name=>label)

   */

  public function attributeLabels() {

    return array(

      'codigrup' => 'Codigo',

      'codisede' => 'Sede',

      'codigrad' => 'Grado',

      'nombgrup' => 'Nombre',

    );

  }


  /**

   * Retrieves a list of models based on the current search/filter conditions.

   * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

   */

  public function search() {

    // Warning: Please modify the following code to remove attributes that

    // should not be searched.


    $criteria = new CDbCriteria;


    $criteria->compare('codigrup', $this->codigrup);

    $criteria->compare('codisede', $this->codisede, true);

    $criteria->compare('codigrad', $this->codigrad);

    $criteria->compare('nombgrup', $this->nombgrup, true);

    $criteria->with = array('sede', 'grado');


    return new CActiveDataProvider($this, array(

      'criteria' => $criteria, 'pagination' => array('pageSize' => 20)

    ));

  }

}



Modeo Grados




<?php


/**

 * This is the model class for table "{{grados}}".

 *

 * The followings are the available columns in table '{{grados}}':

 * @property integer $codigrad

 * @property integer $codinive

 * @property string $descgrad

 */

class Grados extends CActiveRecord {


  /**

   * Returns the static model of the specified AR class.

   * @param string $className active record class name.

   * @return Grados the static model class

   */

  public static function model($className = __CLASS__) {

    return parent::model($className);

  }


  /**

   * @return string the associated database table name

   */

  public function tableName() {

    return '{{grados}}';

  }


  /**

   * @return array validation rules for model attributes.

   */

  public function rules() {

    // NOTE: you should only define rules for those attributes that

    // will receive user inputs.

    return array(

       array('codigrad, codinive, descgrad', 'required'),

       array('codigrad, codinive', 'numerical', 'integerOnly' => true),

       array('descgrad', 'length', 'max' => 50),

       // The following rule is used by search().

       // Please remove those attributes that should not be searched.

       array('codigrad, codinive, descgrad', 'safe', 'on' => 'search'),

    );

  }


  /**

   * @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(

       'nivelEscolaridad' => array(self::BELONGS_TO, 'NivelesEscolares', 'codinive')

    );

  }


  public function scopes() {

    parent::scopes();


    return array(

       'superiores' => array('condition' => 't.codigrad IN (0, 5, 9, 11)')

    );

  }


  /**

   * @return array customized attribute labels (name=>label)

   */

  public function attributeLabels() {

    return array(

       'codigrad' => 'Codigrad',

       'codinive' => 'Codinive',

       'descgrad' => 'Descgrad',

    );

  }


  /**

   * Retrieves a list of models based on the current search/filter conditions.

   * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.

   */

  public function search() {

    // Warning: Please modify the following code to remove attributes that

    // should not be searched.


    $criteria = new CDbCriteria;


    $criteria->compare('codigrad', $this->codigrad);

    $criteria->compare('codinive', $this->codinive);

    $criteria->compare('descgrad', $this->descgrad, true);

    $criteria->with = array('nivelEscolaridad');


    return new CActiveDataProvider($this, array(

       'criteria' => $criteria, 'pagination' => array('pageSize' => 20)

    ));

  }


}



Tampoco funciona…

Dos cosas:

  1. Qué versión de Yii usa?

  2. Le está prudciendo algún error?

"Ñapa": Por si acaso comente la línea en scopes que dice: "parent::scopes()".

Saludos

Tengo la ultima version 1.1.13

No arroja ningún error.

Ya quite esa linea, y tampoco.

Si no arroja ningún error entonces hay un principio que dice “crea lo que dice”… en otras palabras, si no dice nada, entonces significa que no hay error en Yii… sino en el programador :)

En términos más precisos, revise que la condición devuelve datos.

Puede revisar el SQL que se genera con Firebug activándolo en el componente "log" del config/main.php:




        'log' => array(

            'class' => 'CLogRouter',

            'routes' => array(

                array(

                    'class' => 'CWebLogRoute',

                    'showInFireBug' => true,

                    'enabled' => true,

                ),

            ),



Si, eso hice y mira, esta es la consulta SQL que devuelve:




SELECT `t`.`codigrup` AS `t0_c0`, `t`.`codisede` AS `t0_c1`,

`t`.`codigrad` AS `t0_c2`, `t`.`nombgrup` AS `t0_c3`, `sede`.`codisede` AS

`t1_c0`, `sede`.`codicole` AS `t1_c1`, `sede`.`nombsede` AS `t1_c2`,

`sede`.`geposede` AS `t1_c3`, `sede`.`danesede` AS `t1_c4`,

`sede`.`fecrsede` AS `t1_c5`, `sede`.`tiposede` AS `t1_c6`,

`sede`.`carasede` AS `t1_c7`, `sede`.`codiespe` AS `t1_c8`,

`sede`.`codimeto` AS `t1_c9`, `sede`.`codinive` AS `t1_c10`,

`sede`.`codnivop` AS `t1_c11`, `sede`.`codidepa` AS `t1_c12`,

`sede`.`codimuni` AS `t1_c13`, `sede`.`codicpob` AS `t1_c14`,

`sede`.`zonasede` AS `t1_c15`, `sede`.`diresede` AS `t1_c16`,

`sede`.`telesede` AS `t1_c17`, `sede`.`pwebsede` AS `t1_c18`,

`sede`.`mailsede` AS `t1_c19`, `sede`.`coorsede` AS `t1_c20`,

`sede`.`escusede` AS `t1_c21`, `grado`.`codigrad` AS `t2_c0`,

`grado`.`codinive` AS `t2_c1`, `grado`.`descgrad` AS `t2_c2` FROM

`tb_grupos` `t`  LEFT OUTER JOIN `tb_sedes` `sede` ON

(`t`.`codisede`=`sede`.`codisede`)  LEFT OUTER JOIN `tb_grados` `grado` ON

(`t`.`codigrad`=`grado`.`codigrad`) AND (t.codigrad IN (0, 5, 9, 11)) 

WHERE (sede.codisede = :codisede)



Y los resultados nos sor reales ya que no esta teniendo en cuenta esto


AND (t.codigrad IN (0, 5, 9, 11)) 

ahora si pongo eso mismo como condicion en el where


WHERE (sede.codisede = :codisede AND (t.codigrad IN (0, 5, 9, 11))) 

de esta menera los registros son correctos, lo que me lleva a concluir que el scope no esta bien escrito.

Bueno te cuento que lo resolvi agregando un joinType a la relacion


Grupos::model()->findAll(array('with' => array('sede', 'grado' => array('scopes' => array('superiores'), 'joinType' => 'INNER JOIN'))));

Talvez fue descuido mio, pero ahi esta, muchas gracias por tu ayuda…

Ah, qué bueno que al fin se resolvió…

Por acá estaremos ante cualquier otra inquietud.

Saludos.

Y gracias por este tip no me lo sabia… Lo de mostrar en Firebug

Jejeje, hay cositas que se aprenden por ahí :)

Algo que vi en tu scope es que usas el alias de la tabla como t (t.attributo) y cuando hace el join no tiene sentido. De esta forma, el t.codigrad lo estas aplicando sobre la tabla Grupos y no sobre la tabla Grados.

De tu sql:


[color=#000000]FROM

[/color][color=#008800]`tb_grupos`[/color][color=#000000] [/color][color=#008800]`t`[/color][color=#000000]  LEFT OUTER JOIN [/color][color=#008800]`tb_sedes`[/color][color=#000000] [/color][color=#008800]`sede`[/color][color=#000000] ON

[/color][color=#666600]([/color][color=#008800]`t`[/color][color=#666600].[/color][color=#008800]`codisede`[/color][color=#666600]=[/color][color=#008800]`sede`[/color][color=#666600].[/color][color=#008800]`codisede`[/color][color=#666600])[/color][color=#000000]  LEFT OUTER JOIN [/color][color=#008800]`tb_grados`[/color][color=#000000] [/color][color=#008800]`grado`[/color][color=#000000] ON

[/color]

[color=#666600][size=2]([/size][/color][color=#008800][size=2]`t`[/size][/color][color=#666600][size=2].[/size][/color][color=#008800][size=2]`codigrad`[/size][/color][color=#666600][size=2]=[/size][/color][color=#008800][size=2]`grado`[/size][/color][color=#666600][size=2].[/size][/color][color=#008800][size=2]`codigrad`[/size][/color][color=#666600][size=2])[/size][/color][size=2] AND [/size][color=#666600][size=2]([/size][/color][size=2]t[/size][color=#666600][size=2].[/size][/color][size=2]codigrad IN [/size][color=#666600][size=2]([/size][/color][color=#006666][size=2]0[/size][/color][color=#666600][size=2],[/size][/color][size=2] [/size][color=#006666][size=2]5[/size][/color][color=#666600][size=2],[/size][/color][size=2] [/size][color=#006666][size=2]9[/size][/color][color=#666600][size=2],[/size][/color][size=2] [/size][color=#006666][size=2]11[/size][/color][color=#666600][size=2]))[/size][/color]



El INNER JOIN debería devolverte los mismos o menos items que los actuales, pero no debería ser un problema.