2012-08-15 8 views
5

No puedo encontrar demasiada documentación sobre la aplicación de un alcance predeterminado a un modelo en yii, me preguntaba si alguien podría explicarme o señalarme en la dirección correcta.aplicando un alcance predeterminado con referencia a una relación en yii

La versión rápida de mi pregunta:

¿Es posible agregar una relación con un ámbito predeterminado, o para añadir un '' con criterios de forma predeterminada para cada búsqueda AR en un modelo?

La versión larga de mi pregunta:

Un breve resumen de mi aplicación:

Tengo dos modelos, provider y item. Que tienen una relación m: 1 donde un proveedor puede tener muchos artículos, pero cada artículo solo puede tener un proveedor.

hasta ahora tengo estas relaciones:

class Provider extends CActiveRecord 
{ 
    ... 
    public function relations() 
    { 
     return array(
      'items' => array(self::HAS_MANY, 'Item', 'id_provider', 'order'=>'rank DESC'), 
     ); 
    } 
    ... 
} 

class Item extends CActiveRecord 
{ 
    ... 
    public function relations() 
    { 
     return array(
      'provider' => array(self::BELONGS_TO, 'Provider', 'id_provider'), 
     ); 
    } 
    ... 
} 

Dentro de mi modelo de objetos ya tengo un DefaultScope que filtra todos los elementos sin conexión (es decir, sólo muestra los elementos que se exponen a offline = false):

public function defaultScope() 
{ 
    $alias = $this->getTableAlias(false,false); 
    return array(
     'condition'=>"`$alias`.`offline` = false", 
    ); 
} 

lo que quiero hacer ahora, es también filtrar los elementos en los que su proveedor se establece en línea (es decir, sólo mostrar los elementos en provider.offline = false junto con la corriente item.offline = false).

He intentado unirse a la tabla proveedores en el DefaultScope:

public function defaultScope() 
{ 
    $alias = $this->getTableAlias(false,false); 
    return array(
     'join'=>"JOIN `provider` AS `provider` ON `provider`.`id` = `$alias`.`id_provider`", 
     'condition'=>"`$alias`.`offline` = false AND `provider`.`offline` = false", 
    ); 
} 

Sin embargo la unión se aplica después de la instrucción ON, y causese un error (CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'provider.offline' in 'on clause').

También he intentado añadir una con criterios a la DefaultScope:

public function defaultScope() 
{ 
    $alias = $this->getTableAlias(false,false); 
    return array(
     'with'=>"provider", 
     'condition'=>"`$alias`.`offline` = false AND `provider`.`offline` = false", 
    ); 
} 

pero me da el mismo error: SQLSTATE [42S22]: La columna no encontrado: 1054 Desconocido columna 'provider.offline' en ' en la cláusula'`).

¿Alguna sugerencia?

Respuesta

6

Hay un par de cosas que me gustaría probar:

En primer lugar, cambiar su condición de aplicar a todo el asunto (y no se olvide que si no hay elementos para un proveedor, no volverá el proveedor)

public function defaultScope() 
{ 
    return array(
     'with'=> array("provider" => array(
      'condition'=> "t.offline = false AND provider.offline = false", 
     ) 
    ); 
} 

en segundo lugar, trate de añadir alcances de sus modelos y luego hacer referencia a ellos en el ámbito predeterminado de este modo:

public function defaultScope() 
{ 
    return array(
     'scopes'=> array('default'), 
    ); 
} 

class Provider extends CActiveRecord 
{ 
    ... 
    public function scopes() 
    { 
     ... 
    } 
    ... 
} 

class Item extends CActiveRecord 
{ 
    ... 
    public function scopes() 
    { 
     ... 
    } 
    ... 
} 
+0

Por supuesto ! Estaba poniendo la condición en la declaración principal de "condición", no dentro del "con". Tu primera sugerencia funciona perfectamente, ¡gracias! – Stu

0

acaba de tener un problema similar. Si bien la primera sugerencia de Benjamin me indicó la dirección correcta (¡muy apreciada!), Me encontré con un problema inesperado al usar 'condición' y 'con', que podría ser útil tener en cuenta.

Si la tabla a la que se une ('provider' en el ejemplo) tiene su propio defaultScope, parece que esto se aplica como parte de la cláusula SQL ON cuando usa 'with', restringiendo las filas devueltas.

Como se utiliza una unión externa, aún se obtiene un registro de cada fila en la tabla principal ('elemento'), pero los campos 'proveedor' pueden ser nulos para algunas filas si el valor predeterminado del proveedor impide que esas filas devuelto.

Esto no causa ningún problema hasta que intente aplicar una 'condición' que involucre uno de esos campos de proveedor. Esto se hace como parte de la cláusula WHERE que se procesa después de la unión, pero dado que ese campo es nulo, la condición fallará y el registro no se devolverá.

En algunos casos esto puede ser el comportamiento que desea, pero en otros casos es posible que desee mover las pruebas en los campos 'proveedor' dentro de la unión mediante la opción on:

public function defaultScope() 
{ 
return array(
    'with'=> array("provider" => array(
     'condition'=> "t.offline = false", 
     'on'=>"provider.offline = false", 
    ) 
); 
} 
Cuestiones relacionadas