segunda-feira, 12 de setembro de 2011

Codeigniter 2 + STI + PHPActiveRecord (parte 3)



Para validar o funcionamento do ORM em conjunto com o Codeigniter e o CIUnit vamos criar uma  simples aplicação acadêmica como prova de conceito guiada por testes e aplicando alguns design paterns quando necessário.

Requisitos:
  1. Um Curso é composto por uma ou mais Disciplinas
  2. Uma Disciplina pode fazer parte de nenhum ou muitos Cursos
  3. Cada Disciplina deve ser Ministrada por um único Professor Responsável
  4. Cada Disciplina pode pode ter outros Professores Adjuntos
  5. Um Professor pode Ministrar uma ou muitas Disciplinas diferentes
  6. Cada Turma de Estudantes deve ter uma Sala de aula
  7. Um Estudante pode se Matricular em um ou vários Cursos ou ainda em Disciplinas Isoladas
As palavras destacadas sugerem possíveis classes que compõe o sistema e são expressas no diagrama inicial abaixo.  O diagrama ainda deve crescer e ser alterado durante o desenvolvimento do sistema.

Diagrama de classes de exemplo

Iniciando com TDD

Iniciar criando a hierarquia de classes que representa a herança entre Teachers (Professores) e Students (Estudantes)

Criar um testes para validar a classe Person (Pessoas) que é a classe pai da herança.  Para simplificar vamos mapear a herança para nosso modelo relaciona em uma tabela simples (STI-Single Table Inheritance) incluindo um campo type na tabela para definir o tipo de objeto a que se refere a linha.

Criar a primeira classe de teste. Somente para prova de conceito vamos testar a herança na própria classe Person, mais tarde este testes devem ser refatorado.

Rodar os testes e ver falhar o primeiro teste que valida as classes que fazem parte da herança STI e representam os papéis Teachers e Students
$  phpunit --testdox --color models/PersonTest.php
$  phpunit --testdox --group models => só as classes com anotações


Tabelas para comportar o STI

Criar a tabela do topo da herança (peoples) e definir um campo (type) que vai receber o tipo de classe ao qual o registro se refere.
CREATE TABLE  `academico_test`.`people` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `type` varchar(150) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Criar uma view para mapear cada subclasse pelo tipo definido

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` 
SQL SECURITY DEFINER VIEW  `academico_test`.`students` AS 
select `people`.`id` AS `id`,`people`.`name` AS `name`,`people`.`type` AS `type` 
from `people` 
where (`people`.`type` = 'Student')

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` 
SQL SECURITY DEFINER VIEW  `academico_test`.`teachers` AS 
select `people`.`id` AS `id`,`people`.`name` AS `name`,`people`.`type` AS `type`,
`people`.`created_at` AS `created_at`,`people`.`updated_at` AS `updated_at` 
from `people` 
where (`people`.`type` = 'teacher')


Ajustando as classes de modelo
Sobreescrever o construtor das classes filhas para passar o tipo de cada uma delas. Também é necessário declarar a variáel stática que define o campo da chave primária da tabela.
<?php
class Student extends Person {
    static $primary_key = 'id';
    public function  __construct(array $attributes = array()) {
        parent::__construct(array_merge($attributes,array('type'=> __CLASS__ )));
    }
}
<?php
class Teacher extends Person {
   static $primary_key = 'id';
    public function  __construct(array $attributes = array()) {
        parent::__construct(array_merge($attributes,array('type'=> __CLASS__ )));
    }
}

Agora é só rodar novamente os testes e ver a barra verde, indicando que a implementação da herança com tabela simples está funcionando.
$  phpunit --testdox --color models/PersonTest.php
$  phpunit --testdox --group models => só as classes com anotações

Nenhum comentário:

Postar um comentário