Autorelacionamento

Antes de tudo, queria dizer que sou novo no Yii. Já programei em PHP há um tempo, sei dos conceitos de OO e conheço bem de banco de dados… mas ainda não estou perfeitamente confortável com o Yii. A ideia MVC também é nova pra mim, mas já estou mais ou menos acostumado com ela. É o primeiro framework MVC que pego pra estudar e acho que comecei bem.

Por tudo isso, perdoem-me se perguntar alguma bobagem.

Tenho a seguinte tabela:


create table tbl_assunto(

	id int(5) not null primary key auto_increment,

	descricao varchar(2000) not null,

	ordem int(5) not null default 0,

	assuntoPaiId int(4),

	constraint fk_ass_asspai foreign key (assuntoPaiId) references tbl_assunto(id)

) ENGINE = InnoDB;

Como dá pra perceber, o campo assuntoPaiId aponta para o Id da própria tabela. Então vamos às minhas necessidades…

  1. Com essa estrutura eu consigo montar uma hierarquia da seguinte forma:

02 Português

02.01 Interpretação de texto 

02.02 Acentuação gráfica

01 Informática

01.01 Banco de Dados

01.01.01 Conceitos

01.01.02 Modelagem

(a ordem está trocada já pra mostrar o primeiro problema)

Esses campos("02", "02.01", etc) representam a hierarquia e não existem na tabela… são frutos de um método no model Assunto e tem o seguinte código:


public function getHierarquia()

{

	$_hierarquia = '';

	if (!$this->assuntoPaiId=='')  //ASSIM É A MELHOR FORMA DE COMPARAR SE O PAI EXISTE?

	{

		$_hierarquia = $this->assuntoPai->getHierarquia() . '.'; //CHAMA RECURSIVAMENTE

	}

	$_hierarquia .= sprintf('%02.0f', $this->ordem);

	return $_hierarquia;

}

Ou seja, ele vai recursivamente usando o campo ordem como indicador de nível, até um assunto que não tem pai. Sendo assim, como eu faço pra criar um campo "virtual" chamado hierarquia de forma que possa ordenar na minha ação index o resultado obtido? Hoje ele ordena pelo id.

Obs.: Não quero criar um campo chamado hierarquia na tabela tbl_assunto pois ficaria mais fácil de resolver; mais difícil de manter; e eu aprenderia menos com o exemplo. Da forma que está, fica mais fácil a manuntenção pois basta que eu mantenha o campo "ordem" em sequência para minha hierarquia ficar certinha. Já fiz uma rotinha que renumera o campo ordem e o coloca em sequência. A intenção é dificultar e ver até onde a ferramenta me atende.

  1. Feito isso, pretendo criar um widget de forma que eu possa utilizá-lo em vários locais na minha aplicação. Nesse widget eu preciso que em alguns momentos só seja possível selecionar um assunto(radio buttom) e em outros seja possível selecionar vários assuntos(check box). Qual a melhor forma de implementar isso? Um detalhe é que a solução da primeira dúvida servirá para a segunda pois quero tudo ordenado pela hierarquia no meu widget.

Coloquei alguns arquivos relacionados(model, views e controller) em anexo…

Abraços

Heheh , acho que vc já solucionou o seu problema, só não sabe disso ainda :)

Vamos lá …

vc pode criar atributos virtuais no modelo de duas formas possíveis.

Uma é declarar uma variável.


class Assunto extends CActiveRecord{

  public $minhaVar;

 }

É bem simples, mas pouco útil.

Uma outra forma é criar um método, que retorne o valor que vc necessita, precedido da palavra "get". Um exemplo?


class Assunto extends CActiveRecord{

  public function getHierarquia(){

    $_hierarquia = '';

    if (!$this->assuntoPaiId=='') {

      $_hierarquia = $this->assuntoPai->getHierarquia() . '.';

    }

    $_hierarquia .= sprintf('%02.0f', $this->ordem);

  return $_hierarquia    ;

    }

 }

E usá-lo da seguinte forma:




$assunto = new Assunto();

echo $assunto->hierarquia;



Note que este segundo exemplo não tem uma variável do objeto.

No Yii, ele considera todo método público que o nome seja precedido de "get" como um atributo. Este atributo fica como somente leitura, e a forma de trabalhar fica a cargo do programador. Mas a forma de uso é igual a qualquer outro atributo que venha do banco.

Obs: Neste exemplo, o atributo é somente leitura. Caso vc deseje que este atributo possa ser setado, vc tem que desenvolver o método "setHierarquia()"

Ok Daniel, obrigado pela resposta… Mas como ordenar um resultado baseado nessa campo no actionIndex por exemplo?

Cara, ordenar por um atributo criado dinamicamente eu não sei … apesar de ter campos deste tipo no modelo, não tive a necessidade de ordena-los.

Suponho que não dê pra fazer com o FW automaticamente. Se tem alguma forma, eu desconheço. Eu, pensando por auto, ordenaria fazendo a minha própria rotina de ordenação neste caso.