lorena85 1 Denunciar post Postado Novembro 18, 2013 class User extends AbstractEntity { public function hasField($field) { return in_array( $field, array( 'id', 'email', 'login', 'password', 'salt', ), true ); } } Eu, sinceramente, não esperava isso de você, meu caro @Henrique Barcelos O que foi @Evandro Oliveira, tem algo de errado ae ?? Compartilhar este post Link para o post Compartilhar em outros sites
Evandro Oliveira 331 Denunciar post Postado Novembro 18, 2013 O que foi @Evandro Oliveira, tem algo de errado ae ?? Nada de mais. Apenas que, vindo do Henrique, eu esperava algo envolvendo http://php.net/ReflectionClass'>Reflection ou afins pra fazer introspecção de entidades, não um Array hard-coded dentro do método que será criado e destruído cada vez que for necessário consultar um campo da entidade. Compartilhar este post Link para o post Compartilhar em outros sites
Enrico Pereira 299 Denunciar post Postado Novembro 18, 2013 Isso é um bom exemplo de primitive obsession. O problema prático de usar __set/__get é a má performance. Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Novembro 18, 2013 Nada de mais. Apenas que, vindo do Henrique, eu esperava algo envolvendo Reflection ou afins pra fazer introspecção de entidades, não um Array hard-coded dentro do método que será criado e destruído cada vez que for necessário consultar um campo da entidade.Hahaha, concordo que não é a melhor opção, trouxe esse exemplo antigo por questão de simplicidade, meu caro... Mas caso por exemplo eu queira que o atributo 'id' não fosse setado diretamente fora da classe pelo método __set , pois antes que o valor fosse atribuído na array, a classe verificaria se o valor é uma string ou numérico! Vamos com calma aí... Qual a razão para você não querer que o atributo [inline]id[/inline] seja diretamente setado? Eu não vejo problema algum em fazê-lo, já que ao alterar o [inline]id[/inline], vc está criando um novo dado. Mas, é possível trabalhar nisso. Vamos repensar essa estrutura um pouco: <?php interface FieldTypeInterface { public function convert($value); } class IntType implements FieldTypeInterface { public function convert($value) { return (int) $value; } } class DoubleType implements FieldTypeInterface { public function convert($value) { return (double) $value; } } class StringType implements FieldTypeInterface { public function convert($value) { return (string) $value; } } interface EntityFieldInterface { public function getName(); public function getType(); public function isReadOnly(); } class EntityField implements EntityFieldInterface { private $name; private $type; private $readOnly; public function __construct($name, FieldTypeInterface $type, $readOnly = false) { $this->name = $name; $this->type = $type; $this->readOnly = $readOnly; } public function getName() { return $this->name; } public function getType() { return $this->type; } public function isReadOnly() { return $this->readOnly; } } interface EntityModelInterface { public function getName(); public function getField($fieldName); public function hasField($fieldName); } class DefaultEntityModel implements EntityModelInterface { private $name; private $fields = array(); public function __construct($name, array $fields) { $this->name = $name; $this->setFields($fields); } public function getName() { return $this->name; } private function setFields($fields) { foreach ($fields as $field) { if (! $field instanceof EntityFieldInterface) { throw new InvalidArgumentException('Field must be instance of EntityFieldInterface'); } $this->fields[$field->getName()] = $field; } } public function hasField($fieldName) { return array_key_exists($fieldName, $this->fields); } public function getField($fieldName) { if (!$this->hasField($fieldName)) { throw new DomainException("EntityModel '{$this->name}' has no field named '{$fieldName}'"); } return $this->fields[$fieldName]; } } interface EntityInterface { public function get($fieldName, $defaultValue = null); public function set($fieldName, $fieldValue); public function __get($fieldName); public function __set($fieldName, $fieldValue); public function setFromArray(array $data); public function toArray($useDirty = true); } class DefaultEntity implements EntityInterface { private $dataModel; private $data = array(); private $cleanData = array(); private $dirty = array(); public function __construct(EntityModelInterface $dataModel, array $data, $dirty = false) { $this->dataModel = $dataModel; $this->setupData($data, $dirty); } private function setupData(array $data, $dirty) { foreach ($data as $field => $value) { if ($this->dataModel->hasField($field)) { // Law of Demeter diz oi =] $this->data[$field] = $this->dataModel->getField($field)->getType()->convert($value); $this->dirty[$field] = $dirty; } } if ($dirty === false) { $this->cleanData = $this->data; } } public function set($field, $value) { $fieldObj = $this->dataModel->getField($field); // Irá lançar uma exceção se não houver o tal campo... if ($fieldObj->isReadOnly()) { throw new LogicException("Cannot set value to read-only field '{$field}'"); } $this->data[$field] = $fieldObj->getType()->convert($value); $this->dirty[$field] = true; } public function get($field, $defaultValue = null) { $fieldObj = $this->dataModel->getField($field); // Irá lançar uma exceção se não houver o tal campo... return array_key_exists($field, $this->data) ? $this->data[$field] : $defaultValue; } public function __set($field, $value) { $this->set($field, $value); } public function __get($field) { return $this->get($field); } public function setFromArray(array $data) { foreach ($data as $field => $value) { try { $this->set($field, $value); } catch (DomainException $e) { // Não faz nada... } } } public function toArray($useDirty = true) { return $useDirty === true ? $this->data : $this->cleanData; } } Usando: $intType = new IntType(); $stringType = new StringType(); $doubleType = new DoubleType(); $userModel = new DefaultEntityModel('user', array( new EntityField('id', $intType, true), new EntityField('name', $stringType), new EntityField('surname', $stringType), new EntityField('birth_date', $stringType), )); $productModel = new DefaultEntityModel('product', array( new EntityField('id', $intType, true), new EntityField('name', $stringType), new EntityField('description', $stringType), new EntityField('value', $doubleType), )); $user = new DefaultEntity($userModel, array( 'id' => 1, 'name' => 'João', 'surname' => 'da Silva', 'birth_date' => '1990-01-01', )); $product = new DefaultEntity($productModel, array( 'id' => 1, 'name' => 'Facas Ginsu', 'description' => 'As incríveis facas Ginsu, inquebráveis!', 'value' => 499.99, )); var_dump($user->toArray()); var_dump($product->toArray()); $user->id = 2; // erro, pois é somente-leitura $user->value = 30; // erro, pois a propriedade não existe Perceba que agora ficou um pouco mais difícil criar uma entidade. Aqui temos um bom caso para aplicarmos o padrão [inline]Factory Method[/inline] ou até mesmo um [inline]AbstractFactory[/inline] para facilitar a criação das entidades:// Na inicialização: $factory = new EntityFactory(); $factory->registerModel('user', $userModel); $factory->registerModel('product', $productModel); // Em algum lugar do código: $factory->createEntiry('user', $data); Só para a questão de performance apontada pelo Enrico:http://www.garfieldtech.com/blog/magic-benchmarks Apesar de existir um impacto considerável, os testes são para 2.000.000 (dois milhões) de chamadas. Considerando que um código comum não terá nem 2.000 chamadas, a diferença de performance é desprezível. A ideia de que métodos mágicos são gargalos de performance é uma falácia: o acesso a banco de dados é MUITO mais custoso. Compartilhar este post Link para o post Compartilhar em outros sites
lex21 2 Denunciar post Postado Novembro 19, 2013 Um dica, já que está utilzando php orientado, use um framework codeigniter2 por exemplo. Melhor eficiência e menos tempo gasto.;) Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Novembro 19, 2013 Prefiro me dar um tiro no pé do que usar CodeIgniter... Frameworkzinho furreca, pseudo-OO, cheio de gambiarra. A ideia aqui é justamente entender COMO funciona um framework, para só aí passar a utilizar um. Do contrário, se você não entende os conceitos, acaba ficando viciado em um framework específico. No dia em que precisar de outro, não vai saber usar. Compartilhar este post Link para o post Compartilhar em outros sites
Enrico Pereira 299 Denunciar post Postado Novembro 19, 2013 O CodeIgniter já está morto, já que a EllisLab tocou o barco e divulgou isso há meses (aqui). Chamar um monte de variáveis globais De OO é sacanagem.. Compartilhar este post Link para o post Compartilhar em outros sites
Manoel Barros 1 Denunciar post Postado Novembro 21, 2013 @Henrique Barcelos para que serve os atributos "cleanData" e "dirty" da classe DefaultEntity no código que você fez ? Nada de mais. Apenas que, vindo do Henrique, eu esperava algo envolvendo Reflection ou afins pra fazer introspecção de entidades, não um Array hard-coded dentro do método que será criado e destruído cada vez que for necessário consultar um campo da entidade. O que significa "Introspecção de entidades" em OO ? Compartilhar este post Link para o post Compartilhar em outros sites
Evandro Oliveira 331 Denunciar post Postado Novembro 21, 2013 O que significa "Introspecção de entidades" em OO ? Introspecção significa inspeção interna ou de seu interior. Entidades representam o conteúdo "palpável" do seu modelo de negócios. Em OO, na maioria das vezes uma entidade é representada por uma classe, embora isso não seja unanimidade. Introspecção de entidades no caso, seria útil para que você não precisasse ficar declarando os campos de uma classe dentro de um Array. Podendo fazê-lo como propriedades da classe - inclusive - tirando proveito disso. Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Novembro 21, 2013 Henrique Barcelos para que serve os atributos "cleanData" e "dirty" da classe DefaultEntity no código que você fez ? Apenas para manter um registro dos dados originais do objeto caso eu altere algum valor. Isso torna um UPDATE mais eficiente, pois eu mando alterar apenas os campos que sofreram modificações. @Evandro, solta um exemplo aí pra gente de como vc faria... Compartilhar este post Link para o post Compartilhar em outros sites
Manoel Barros 1 Denunciar post Postado Novembro 22, 2013 @Henrique Barcelos o que o @Evandro Oliveira falou sobre Introspecção , segue introspecção no código que você fez? Pois os campos que a entidade tem, são declaradas por uma array, isso seria uma introspecção? Compartilhar este post Link para o post Compartilhar em outros sites
Evandro Oliveira 331 Denunciar post Postado Novembro 22, 2013 @Evandro, solta um exemplo aí pra gente de como vc faria...Forma 1: Se houver suporte a algum parser de annotations: class User extends AbstractEntity { /** * @property \integer $id @entityField */ private $id; /** * @property \string $name @entityField */ private $name; ... }Como eu disse, havendo suporte a annotations, ficaria a cargo do parser retornar tudo que esteja taggeado como [inline]@entityField[/inline] Sem suporte a annotations, uma forma bacana - apesar de pouco prática - seria informar via constantes, onde você pode, inclusive, definir o tipo. class User extends AbstractEntity { const FIELD_ID = AbstractEntity::FIELD_TYPE_INTEGER; const FIELD_NAME = AbstractEntity::FIELD_TYPE_STRING; }O método de consulta, que poderia ficar em AbstractEntity seria algo tipo isso: public function __construct(...) { ... $this->fields = $this->parseFields(); } protected function mountFieldName($actualName, $currentValue) { return $actualName + ucfirst($currentValue); } protected function parseFields() { $output = []; $me = new ReflectionClass($this); foreach ($me->getConstants() as $constName) { if ('FIELD_' !== substr($constName, 0, 6)) { continue; } $name = substr($constName, 6); $name = strtolower($name); $output[] = array_reduce(explode('_', $name), [$this, 'mountFieldName'], ''); } return $output; }Vou reinstalar o IDE pra testar o código e - enquanto houver tempo para editar o post - faço qualquer edição que seja necessária. Compartilhar este post Link para o post Compartilhar em outros sites
William Bruno 1501 Denunciar post Postado Novembro 22, 2013 Tô vendo isso aqui, ficar cada vez mais parecido com: http://forum.imasters.com.br/topic/409112-proposta-de-fluent-interface-dao-phpoo/ Onde começaram uma discussão inútil sobre herança.. Compartilhar este post Link para o post Compartilhar em outros sites
Henrique Barcelos 290 Denunciar post Postado Novembro 23, 2013 Se formos apagar tudo o que é "inútil" deste fórum, acaba o conteúdo... Compartilhar este post Link para o post Compartilhar em outros sites
Manoel Barros 1 Denunciar post Postado Novembro 25, 2013 @William Bruno no código que você apresentou neste tópico http://forum.imasters.com.br/topic/409112-proposta-de-fluent-interface-dao-phpoo/ Como seria se caso os dados em vez de gravar no banco de dados passasse a ser gravado num arquivo ? Pois o "DAO" que você fez, só monta uma SQL para gravar os dados no banco de dados e como fica o caso de gravar num arquivo Compartilhar este post Link para o post Compartilhar em outros sites
Evandro Oliveira 331 Denunciar post Postado Novembro 25, 2013 Depende do ponto de vista e da pessoa em questão. Pra mim, a menos que não agregue nada a ninguém nenhum debate é inútil. Pra mim aquela discussão foi bastante útil, só não foi para o assunto do tópico em questão =\ Compartilhar este post Link para o post Compartilhar em outros sites
William Bruno 1501 Denunciar post Postado Novembro 25, 2013 @Manoel Barros, Por que vc quer isso ? Caso realmente precise, basta usar uma Factory e escrever outra classe que persista em arquivos. A responsabilidade daquele DAO que apresentei é para SQL, faz isso e pronto. Em todos os sistemas que fiz, eu nunca tive a necessidade de salvar em arquivos. Então eu fiz algo que resolvesse meu problema e pronto. Usando a interface da classe DAO, basta vc escrever outra que tenha o mesmo comportamento, receba um VO e persista ele. Worse is Better e YAGNI :lol: Compartilhar este post Link para o post Compartilhar em outros sites