goncin@wordpress.com:~$ _

Linux, programação e toda sorte de nerdices

O Yii Framework e os “models” (modelos)

Dando seguimento à série de artigos sobre o Yii Framework, desejo compartilhar algumas reflexões acerca dos modelos (models) do padrão de desenvolvimento MVC e de como o Yii Framework implementa o conceito.

Para deixar as coisas mais claras, tomei a liberdade de traduzir a definição de modelo constante deste artigo da Wikipédia de língua inglesa (quase sempre mais completa que a versão lusófona):

O modelo é utilizado para gerenciar informações e notificar os observadores quando a informação é alterada. O modelo é a representação dos dados específica de um negócio, sobre os quais a aplicação trabalha. A lógica de negócio dá significado aos dados brutos (como, por exemplo, determinar se hoje é o dia do aniversário do usuário, ou os totais, impostos e valores de frete para itens de um carrinho de compras). Quando o estado do modelo se altera, este notifica suas visões [views] associadas, de forma que elas possam ser atualizadas.

Várias aplicações usam um mecanismo de armazenamento persistente, como um banco de dados, para guardar os dados. O padrão MVC não menciona especificamente a camada de acesso aos dados, porque se supõe que ela esteja sob o modelo ou encapsulada por este. Modelos não são objetos de acesso a dados; contudo, em aplicações muito simples, com pouca lógica de negócio, não há nenhuma distinção efetiva a se fazer. O Active Record é um padrão de desenvolvimento bem aceito e que une o código da lógica de negócios e o de acesso aos dados – um modelo que sabe como persistir a si mesmo.

Do que foi abordado acima, aprofundemos dois tópicos.

1. O modelo nem sempre está relacionado a um objeto de banco de dados

Isso pode soar estranho, mas basta pensar um pouco para dar razão à assertiva. O ciclo de vida de uma aplicação MVC é, basicamente, coletar dados por intermédio de um formulário (visão, view), filtrá-los segundo as regras de negócio (o que é feito no controlador – controller) e armazená-los para posterior consulta, usando os modelos (models) para tanto.

Há ocasiões, no entanto, em que os dados coletados não precisam ou não devem ser armazenados – eles são necessários apenas em uma etapa intermediária do processamento. Talvez o exemplo mais típico dessa situação sejam os formulários de login, nos quais coletamos um nome de usuário e uma senha, que servem à autenticação/autorização. Depois disso, o nome do usuário (ou seu código, dependendo da lógica implementada) é, no máximo, armazenado num cookie ou num objeto de sessão. Armazenar a senha seria um total contrassenso, por questões de segurança.

O que nos impede, então, de representar os dados de um formulário de login como um modelo? É exatamente isso que o Yii Framework faz. Em todo projeto iniciado com o auxílio da ferramenta de linha de comando yiic, é gerado um modelo chamado LoginForm (na pasta protected/models), cujo conteúdo é o seguinte:

class LoginForm extends CFormModel
{
	public $username;
	public $password;
	public $rememberMe;

	private $_identity;

	/**
	 * Declares the validation rules.
	 * The rules state that username and password are required,
	 * and password needs to be authenticated.
	 */
	public function rules()
	{
		return array(
			// username and password are required
			array('username, password', 'required'),
			// rememberMe needs to be a boolean
			array('rememberMe', 'boolean'),
			// password needs to be authenticated
			array('password', 'authenticate', 'skipOnError'=>true),
		);
	}

	/**
	 * Declares attribute labels.
	 */
	public function attributeLabels()
	{
		return array(
			'rememberMe'=>'Remember me next time',
		);
	}

	/**
	 * Authenticates the password.
	 * This is the 'authenticate' validator as declared in rules().
	 */
	public function authenticate($attribute,$params)
	{
		$this->_identity=new UserIdentity($this->username,$this->password);
		if(!$this->_identity->authenticate())
			$this->addError('password','Incorrect username or password.');
	}

	/**
	 * Logs in the user using the given username and password in the model.
	 * @return boolean whether login is successful
	 */
	public function login()
	{
		if($this->_identity===null)
		{
			$this->_identity=new UserIdentity($this->username,$this->password);
			$this->_identity->authenticate();
		}
		if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
		{
			$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
			Yii::app()->user->login($this->_identity,$duration);
			return true;
		}
		else
			return false;
	}
}

A classe CFormModel, na hierarquia do Yii Framework, descende de CModel. Estão ali alguns métodos que costumamos ver nos posts anteriores, como o rules(), que estabelece as regras de validação para os dados, e o attributeLabels(), no qual podemos definir os nomes dos campos na linguagem natural do usuário.

Os dados de login são colhidos e processados, mas nunca armazenados em banco de dados – mesmo porque nem a classe CFormModel, nem sua ancestral, CModel, implementam um método save(). Pelo “jeitão de ser” do Yii Framework, CFormModel deve ser usado toda vez que os dados do formulário não serão armazenados (ao menos diretamente) num banco de dados. Para o trabalho com banco de dados, utilizamos o CActiveRecord.

2. O Active Record reúne em si regras de negócio e código de acesso a dados

O quão chocante lhe parece esta afirmação? Trata-se, é verdade, de uma quebra do paradigma MVC, que preconiza que as regras de negócio devem residir unicamente no controlador (controller). Ponderemos, porém: validação de dados é, em última análise, regra de negócio NOTA MENTAL: escrever um post sobre validação de dados no Yii Framework. E, se esses dados foram ou serão armazenados em banco de dados, a validação precisa obedecer, necessariamente, a definição da estrutura do BD, bem como as características e limitações do SGBD correspondente.

Logo, faz todo o sentido deixar que o próprio modelo verifique se a informação a ser armazenada num campo definido como VARCHAR(100) não ultrapassa esse comprimento. Podemos chamar isso, grosso modo, de forma. O controlador poderia ter-se encarregado de checar essa mesma informação quanto ao aspecto do conteúdo: é um endereço existente? É um nome de pessoa válido? É um município dentro da área de representação da empresa?

Por isso, e para poupar o precioso tempo do desenvolvedor, é que o Yii Framework mantém as regras de validação de dados, quanto à sua forma, no modelo (clique aqui para ver o exemplo de um código de modelo gerado a partir de um objeto de banco de dados), refletindo, sempre que possível, as regras já definidas no BD (tais quais campos requeridos, comprimento máximo, tipo de valor – numérico, alfanumérico, etc.). Tudo isso é implementado estendendo-se a classe CActiveRecord que, por seu turno, também estende CModel.

Concluindo…

O Yii Framework nos leva a repensar o conceito de modelo, desprendendo-o da correlação, julgada muitas vezes  necessária, com um objeto de banco de dados. Com isso, as possibilidades de uso dos modelos ampliam-se, como é o caso do formulário de login anteriormente citado.

O framework também implementa de forma elegante o padrão de desenvolvimento Active Record, encarregando os modelos gerados a partir de estruturas de bancos de dados da validação formal das informações, poupando o desenvolvedor de escrever código para isso 8) .

Para saber mais

  • The Definitive Guide to Yii (em português)

2 Respostas para “O Yii Framework e os “models” (modelos)

  1. Flávio 17/03/2011 às 16\0439

    parabéns pelo post, bem claro.

  2. Rodrigo Rodrigues [@madrodz] 17/03/2011 às 19\0708

    Otimo Post! eu estou me aventurando no PHP (engatinhando,na verdade), e estou utilizando o Yii nesse meu estudo. É muito bom! Muito obrigado goncin!

Deixe um comentário