goncin@wordpress.com:~$ _

Linux, programação e toda sorte de nerdices

Entendendo as “relations” (relações) do Yii Framework

No post em que apresentei o Yii Framework, demonstrei a capacidade que este possui de gerar o código dos modelos para o padrão de desenvolvimento MVC a partir da estrutura do banco de dados. Hoje vou um passo além, para mostrar que o código gerado reflete não apenas os atributos, mas também as relações (foreign keys) existentes entre as tabelas do BD.

Consideremos, pois, uma estrutura de dados bem simples:

A tabela 'aluno' possui uma chave estrangeira N para 1 em 'escola'

A tabela 'aluno' possui uma chave estrangeira N para 1 em 'escola'

Nessa estrutura hipotética, cada aluno está vinculado a uma escola; por óbvio, uma escola pode possuir zero ou mais alunos. Na UML, esse tipo de relação é denominado dependência, como nos ensina o companheiro #SouDev Edgard Davidson. A partir dessas informações, o Gii (scaffolder do Yii Framework – veja aqui como habilitá-lo no seu projeto) pode gerar o código para os modelos. Desde a versão 1.0.1 do framework, não é mais necessário que as relações provenham das chaves estrangeiras previamente definidas no banco de dados; é possível defini-las em código, editando o corpo do método relations().

Do código gerado para ambos os modelos (Aluno e Escola, que se encontram na árvore do projeto sob protected/models), destaco os seguintes trechos:

<?php
class Aluno 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(
			'escola' => array(self::BELONGS_TO, 'Escola', 'cod_escola'),
		);
	}

  (...)

}
<?php
class Escola 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(
			'alunos' => array(self::HAS_MANY, 'Aluno', 'cod_escola'),
		);
	}

  (...)

}

O Gii capturou as definições de chaves estrangeiras e estabeleceu as relações entre as tabelas de acordo com aquelas. No caso, um aluno pertence a (self::BELONGS_TO) uma escola, que, por seu turno, tem vários (self::HAS_MANY) alunos.

A partir disso, abre-se uma miríade de possibilidades. Neste cenário, seria comum ter de apresentar, junto com as informações do aluno, o nome da escola no qual este estuda. Poderíamos escrever o seguinte:

<?php
  // Recupera os dados do aluno cujo código é 1000
  $aluno = Aluno::model()->findByPk(1000);

  echo 'Código: ' . $aluno->cod_aluno . '<br />';
  echo 'Nome do aluno: ' . $aluno->nome_aluno . '<br />';
  echo 'Nome da escola: ' . $aluno->escola->nome_escola . '<br />';

Notem (linha 7) que, para obter o nome da escola, não foi preciso instanciar um objeto da classe Escola apenas para que obtivéssemos o nome da escola. Ao invés disso, beneficiamo-nos de uma relação definida no modelo Aluno.

De forma semelhante, a partir de uma instância da classe Escola, seremos capazes de listar todos os alunos vinculados a ela, escrevendo algo como:

<?php
  // Recupera os dados da escola cujo código é 50
  $escola = Escola::model()->findByPk(50);

  // Recupera uma lista de alunos vinculados à escola
  $alunos = $escola->alunos;

  foreach($alunos as $aluno) {
    echo 'Código: ' . $aluno->cod_aluno . '<br />';
    echo 'Nome do aluno: ' . $aluno->nome_aluno . '<br />';
    echo '<hr />';
  }

O código da linha 6 é o bastante para se obter uma lista de alunos vinculados à escola, graças à relação definida na classe Escola.

Em ambos os exemplos, utilizei a técnica chamada lazy loading para recuperar dados relacionados. Há ainda outras formas de se fazer isso, bem como outros tipos de relações além de self::BELONGS_TO e self::HAS_MANY, sobre as quais você pode obter mais informações consultado o Guia Definitivo do Yii Framework.

Um aspecto final a ser salientado é que estivemos utilizando, durante todo o tempo, um outro padrão de desenvolvimento, denominado Active Record. Ele nos permitiu trabalhar com as informações do banco de dados sem lançar mão, em momento algum, da linguagem SQL. O Active Record, por sua vez, é uma das implementações possíveis de ORM (Object-relational mapping) 8) .

Anúncios

20 Respostas para “Entendendo as “relations” (relações) do Yii Framework

  1. Pingback: Tweets that mention Entendendo as “relations” (relações) do Yii Framework « goncin@wordpress.com:~$ _ -- Topsy.com

  2. Ana Paula 19/01/2011 às 08\0841

    Parabens pelos post sobre Yii, estão muito bem explicados, torço para que popule, pois na documetanação não tem muitos exemplos, sendo uma carencia geral para quem como eu estou iniciando com o Yii.

    • darlecio 13/05/2011 às 18\0610

      Cara parabens pelo o Post, Como Ana Paula firmou sendo uma carencia em exemplos praticos para quem esta iniciando.. torço tambem para não só pela popularidade e tambem para um incentivo aos mais veterenos no assunto compartilhar conhecimento..

      no agurdo de mais post. huehwuehuwe

      abraço

      Darlecio Almeida

  3. guilleurbani 09/08/2011 às 14\0201

    boa tarde
    entendi tudo,
    mas nao comprendo onde coloca o codigo para obter
    os alunos vinculados a uma escola.

    obrigada.

  4. guilleurbani 09/08/2011 às 14\0219

    e que coloco na controller ?
    o problema es o siguiente
    tenho uma tabela programas
    e uma tabela apresentadores
    cada programa pode ter um o mas apresentadores
    entao eu fiz uma relacao.
    en apresentadores e programas defini as relations
    agora preciso definir alguma coisa en na controller
    para enviar as views.
    porque preciso presentar en na tela
    uma lista de programas con os apresentadores da outra tabela
    se comprende ? (desculpa se nao se comprende, mas nado falo portugues muito bom)
    mas nao acho nehuma coisa que fale sobre que colocar na controller

    obrigada 🙂

    • goncin 09/08/2011 às 14\0223

      Do you speak English?
      ¿Hablas español?
      Parli italiano?
      Parlez-vous français?
      Ĉu vi parolas esperanton?

    • goncin 09/08/2011 às 14\0243

      ¡Hola! 🙂 En este caso, podrías hacer lo siguiente:

      Supongo que tengas un ProgramaController, y hay dentro de el una actionView. Si has usado el Gii para generar tu controller, los tendrás.

      Para un ejemplo rápido, no es siquiera necesario cambiar el codigo de la actionView. Pero, en la view correspondiente (views/Programa/view.php), sería posible hacer algo como lo que demustro más abajo, suponiendo que las relaciones estén correctamente definidas en los models:

      <?php
      
        echo '<h1>Programa<h1>';
        echo $model->nombre_programa, '<br /><br />'; // Se imprime el nombre del programa
        
        echo '<h2>Presentador(es)</h2>';
        // Para cada presentador vinculado a el programa que estamos viendo, le imprimimos el nombre
        foreach($model->presentadores as $presentador)
          echo $presentador->nombre_presentador, '<br />';
      
      ?>
      

      ¿Qué le parece? ¿Simple, no?

  5. guilleurbani 09/08/2011 às 14\0225

    hablo español 🙂
    vos tambien ?
    hay seria genial,
    asi si podes me das una mano con esto,
    ya llevo dos dias leyendo los mismos temas y post
    y no consigo adiantar mucho.
    es que ya no razono lo que leo :/

  6. guilleurbani 09/08/2011 às 15\0343

    perfecto eso si comprendo
    y funciona, pero solo para un apresentador,
    el que tengo definido en la tabla programa en id_apres
    las tablas estan asi:

    tabla programa
    con los siguientes atributos:
    id_prog
    nome
    id_apres

    tabla apresentadores
    con los siguientes atributos:
    id_apres
    nome
    id_prog

    en los id no se como definir, que un programa puede tener por ejemplo 3 id de apres, id_apres1, id_apres2 e id_apres3
    y la misma cosa con apresentadores, que en id_prog en phpmyadmin pueda definir id_prog1, id_prog2

    en las relations es many_many
    Y AHI CON CERTEZA esta el problema porque por lo que tengo entendido preciso mas una tabla,
    y de ahi quitar id_apres de programa.
    y quitar id_prog de apres.
    y generar una nueva tabla prog_apres
    que tenga id_prog
    e id_apres
    y ahi ESTA EL PROBLEMA
    para que selecionado un programa me muestre los nombres de los apresentadores relacionados
    se entiende?

    desde ya muchas gracias

    • goncin 09/08/2011 às 16\0404

      Por supuesto, tendrás que crear la tabla “prog_apres”, conteniendo sólo los campos “id_prog” y “id_apres”.

      Una vez la tengas creado, te bastará modificar la relación en el model correspondiente al programa, así:

      (...)
      'apresentadores' => array(self::MANY_MANY, 'Apresentadores', 'prog_apres(id_prog, id_apres)),
      (...)
      

      Eso es lo suficiente para que mi ejemplo anterior vuelve a funcionar.

  7. guilleurbani 09/08/2011 às 16\0440

    hasta ahi seguimos bien
    y sigo entendiendo
    ahora el problema esta en:

    en la tabla programas
    tengo un programa con:
    id = 2
    nome = telejornal

    en la tabla apresentadores
    tengo dos apresentadores:
    id=1
    nome= juan jose

    id=2
    nome= maria

    y en la tabla prog_apres tengo:
    id_prog = 2
    id_apres = 1

    y

    id_prog = 2
    id_apres = 2

    pero en el echo no precisaria un if
    que compra si el id_prog de la tabla programas es igual al id_ prog de prog_apres
    y si el id_apres de la tabla apresentadores es igual al id_apres de prog apres?

    porque le coloque eso y me da

    Trying to get property of non-object

    se lo quite, le deje solo como tu ejemplo y sigue dando el mismo error…
    y en las tablas estan bien definidos los id_prog y id_apres

  8. guilleurbani 09/08/2011 às 17\0500

    estoy teniendo un problema al pasar datos del controller al view,
    ya casi solucionado 🙂

    muchas gracias por tu ayuda !

  9. guilleurbani 10/08/2011 às 09\0913

    problema casi solucionado
    me sigue mostrando, solo el primer apresentador

    el codigo es
    foreach($dados_prog as $presentador)
    echo $apresentador->nome; )

    la idea es que quede mas o menos asi:
    programas

    id nome apresentadores
    24 telejornal Juan, Jose

    ó

    id nome apresentadores
    24 telejornal Juan,
    Jose,
    Agustin

    nosé que forma sea mas conveniente,
    porque despues me tiene que dejar agregar mas apresentadores o quitar, pero ese ya es otro tema,
    ahora el tema esta en que me los muestre a TODOS y NO solo uno.
    sera que precisa un if qe compare id_prog de la tabla programas e id_prog de prog_apres y a su vez id_apres de la tabla apresentadores con id_apres de la tabla prog_apres ?
    (if((($dados_prog->id_prog)==($prog_apres->id_prog))and (($apresentador->id_apres)==($prog_apres->id_apres))))

    se entiende?
    lo hice pero me ejecutaba la cantidad de veces del id del progama
    o sea si era 2 me mostraba 2 veces el nombre del primer apresentador

    desde ya muchas gracias.

  10. guilleurbani 10/08/2011 às 10\1035

    ya encontre por donde viene el problema, en al definicion de las relaciones, me faltaba el with en las tablas programa y apresentadores
    y definir las relaciones en la tabla intermediaria.
    asi que ando por ahi modificando 🙂

  11. guilleurbani 11/08/2011 às 09\0915

    buenos dias,
    te comento el problema con el que ando pro si me puedes ayudar,

    tengo 3 tablas

    programa con:
    id_prog
    nome

    apresentadores con:
    id_apres
    nome

    prog_apres con:
    id_prog
    id_apres

    esa tercer tabla(prog_apres) esta definida porque la relacion programa apresentadores es muchos a muchos.
    con respecto a las relaciones tengo definido:

    en Apresentador:
    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(
    ‘script’=>array(self::MANY_MANY ,’Script’,’ProgApres(id_prog, id_apres)’),
    ‘prog_apres’=>array(self::HAS_MANY ,’ProgApres’,’id_apres’),
    );
    }

    en programa (que seria Script):
    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(
    ‘apresentador’=>array(self::MANY_MANY ,’Apresentador’,’ProgApres(id_prog, id_apres)’),
    ‘prog_apres’=>array(self::HAS_MANY ,’ProgApres’,’id_prog’),

    );
    }

    y en prog_apres

    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(
    ‘apresentador’=>array(self::HAS_MANY , ‘Apresentador’,’id_apres’),
    ‘script’=>array(self::HAS_MANY ,’Script’,’id_prog’),
    );
    }

    y en la controler, tengo asi:

    public function actionView() {
    Yii::import(‘application.models.tv.praca.programa.Script’);
    Yii::import(‘application.models.tv.praca.programa.Apresentador’);
    Yii::import(‘application.models.tv.praca.programa.ProgApres’);

    $dados_prog = Script::model()->with(‘apresentador’)->findByAttributes(array(‘id_prog’=> $_GET[‘id’]));
    $prog_apres = ProgApres::model()->with(‘apresentador’,’script’)->findAllByAttributes(array(‘id_prog’ => $_GET[‘id’]));
    $apresentador = Apresentador::model()->find();

    $this->render(‘view’, array(
    ‘dados_prog’ => $dados_prog,
    ‘apresentador’ => $apresentador,

    ‘prog_apres’ => $prog_apres,
    ));
    }

    creeria, que esta todo bien definido,
    ahora el problema esta en que me da el siguiente error:
    CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘t.’ in ‘on clause’

    y por lo que estuve leyendo
    es problema de que se definen algunas tablas en una relacion con nombre t,
    pero intente por medio de alias modificarle, pero no obtuve resultados,
    que sera que puede andar errado?

    desde ya muchas gracias.

  12. rodrigo 12/09/2011 às 17\0550

    cara muito bom, quando der coloca mais coisa sobre yii…. Parabens

  13. Flávio 23/11/2011 às 16\0429

    VLW goncin, quando sobrar um tempinho publica mais tutoriais sobre o Yii.

  14. Gustavo Lima 29/02/2012 às 09\0945

    Muito bom tutorial está de parabéns 😀

  15. Carlos 20/04/2012 às 12\1236

    Esclarecedor.

    Merecemos mais posts assim em português.

    Obrigado

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: