Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Andrey Knupp Vital

View, Template ..

Recommended Posts

Bem, estou dando continuidade ao meu mini-fw, e na parte da View, eu fiz o seguinte esquema:

<?php
         namespace MVC\Views;

         class View {

                private $vars = array ( ) ;

                public function assign( $var , $value ) {
                       $this->__set( $var , $value );
                }

                public function __set ( $var , $value ) {
                       $this->vars [ $var ] = $value ;
                }

                public function __get ( $var ) {
                       if ( isset ( $this->vars [ $var ] ) ) {
                              return $this->vars [ $var ] ;
                       } else return null ;
                }

                public function render ( $template , $path = null ) {
                       ob_start ( ) ;
                       $dir = ( ! is_null ( $path ) ? $path : sprintf ( '%s%sTemplates' , __DIR__ , DIRECTORY_SEPARATOR  ) ) ;
                       $filename = sprintf ( '%s%s%s' , $dir , DIRECTORY_SEPARATOR , $template ) ;
                       if ( file_exists ( $filename ) ) require_once $filename ;
                       return ob_get_flush();
                }

         }

 

Beleza, funciona normalmente, consigo renderizar os arquivos phtml conforme o planejado ..

<?php
          $view = new View ( ) ;

          $view->title = 'teste';
          $view->encoding = 'iso-8859-1';

          $view->render( 'index.phtml' ) ;

 

Input/Output

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
      <head>
             <meta http-equiv="Content-Type" content="text/html;charset=<?php echo $this->encoding ?>" />
             <title><?php echo $this->title ?></title>
      </head>
      <body>

      </body>
</html>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
      <head>
             <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1" />
             <title>teste</title>
      </head>
      <body>

      </body>
</html>

 

 

 

Só que, quero adicionar um recurso de Helpers, que seriam objetos / functions já escritas para serem usadas na view .. qual seria a melhor maneira de fazer isso ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Você pode logo no construtor definir algumas variáveis de template com tais objetos e nos setters, antes de permitir que uma nova variável de template seja criada, verificar se o nome desejado já não está em uso por algum helper.

 

Eu não entendo direito como esses helpers funcionam, mas se for como imagino que é, no meu caso por exemplo, eu pré-determino uma variável de template chamada _request para que, no template eu possa, dentre tantas coisas, montar um path absoluto por utilizar meu método Request::getBaseUrl()

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mais ou menos.

 

A diferença é que você não vai acessar na forma de variável e sim de propriedade:

 

class View {

   private $forbidden = array( '_request' );

   private $tplVars = array();

   public function  __construct() {

       $this -> tplVars['request'] = new Request;
   }

   public function __get( $tplVar ) {
       return ( array_key_exists( $tplVar, $this -> tplVars ) ? $this -> tplVars[ $tplVar ] : FALSE );
   }

   public function __set( $tplVar, $value ) {

       if( in_array( $tplVar, $this -> forbidden ) ) {
           throw new Exception( sprintf( '<strong>%s</strong> é uma variável de template reservada', $tplVar ) );
       }

       $this -> tplVars[ $tplVar ] =& $value;
   }
}

Esse pseudo-código ilustra bem o exemplo. Não sei se é a melhor alternativa, mas não me parece errado.

 

Eventualmente, você pode até criar métodos que manipulem a propriedade $forbidden, incluindo outras variáveis definidas logo que a View Engine é instanciada, antes mesmo de o fluxo cair nas mãos do Controller (no meu caso, minha Application).

Compartilhar este post


Link para o post
Compartilhar em outros sites

Marrapá, eu disse no finalzinho do do post #2. :o

 

Uma das utilidades da minha Request é retornar, depois de tratado, o URI base completo do sistema, que é um apanhado de informações vindas de parse_url() sobre a variável de servidor REQUEST_URI junto com, opcionalmente, um basepath representado por um ou mais subdiretórios acima de public_html.

 

Tudo isso, mais verificações, tratamento de barras e etc. resultou no meu método Request::getBaseUrl() o qual é usado nas tags <link>, <img>, <script>...

 

Claro, até hoje, esse método é o único usado no meus Templates. Se, ao terminar um sistema eu verificar que, de fato, não usei mais nada da Request, posso auto-atribuir não mais um objeto e sim a string já pronta.

Compartilhar este post


Link para o post
Compartilhar em outros sites

E o que os helpers tem haver com isso ? eles não são requisitados .. e sim importados pra dentro da view, pensa no uso do baseURL, fullURL .. esses sim seriam helpers que seriam utilizados em praticamente todos os links ..

 

 

[ Epic Fail ]

Ainda não estou pescando o uso da Request, com a View .. e/ou Controller ..

Compartilhar este post


Link para o post
Compartilhar em outros sites

Então, minha View ainda não tem suporte à View Helpers mesmo porque ainda não sei exatamente como eles funcionam.

 

Mas como eu disse no final do post #4, futuramente posso ter uma Interface chamada ViewHelpers para garantir esse contrato de modicação. Algo como:

 

interface ViewHelpers {

   public function registerHelper( View $view, Object $object = NULL );
}

No meu caso como todo setup da aplicação ocorre numa mesma classe (Application), se eu quiser registrar um helper de qualquer módulo eu faço ali na hora.

 

Vamos ver um sistema simplificado de Cache. COmo eu tenho até o momento dois backends (File e APC), na classe abstrata à eles eu poderia fazer:

 

abstract class AbstractBackend extends Object implements Backend, ViewHelpers {

   // ...

   public function registerHelper( View $view, Object $object = NULL ) {

       try {

           return $view -> registerHelper( 'cache', $this );

       } catch( ViewException $e ) {

           throw new CacheException( $e );
       }
   }
}

Na View seria adicionado algo como:

 

public function registerHelper( $helper, Object $object ) {

   $helper = sprintf( '_%s', $helper );

   $this -> tplVars[ $helper ] =& $object;

   $this -> forbidden[] = $helper;

   return $this;
}

E na Application:

 

class FooApplication extends AbstractApplication {

   public function setupView() {

       return new View;
   }

   public function setupResources() {

       $cache = new Backend\APC;

       $cache -> registerHelper( $this -> view );

       Registry::getInstance() -> set( 'cache', $cache );
   }
}

Fiz tudo isso de cabeça, aqui e agora, enxergando muito pouco (estou com problema na vista), mas em linhas gerais seria isso.

 

Apesar de baseado no meu sistema, eu omiti muita coisa para simplificar.

 

Com isso, eu poderia invocar, no template, algum informação cacheada sem precisar criar uma variável de template para isso.

 

Suponhamos que eu tenha uma lista de dados que não muda ou muda muito pouco.

 

Eu poderia fazer no Controller:

 

ListController extends AbstractController {

   public function main() {

       $cache = Registry::getInstance() -> get( 'cache' );

       try {

           $data = $cache -> load( 'AlmostImmutableDataList' );

       } catch( CacheException $e ) {

           $model = new ListModel;

           $data = $model -> fetchAll();

           $cache -> add( 'AlmostImmutableDataList', $data );
       }

       $this -> dataList = $data;
   }
}

Para pegar informação do cache, se possível (try) ou recriar a lista se falhar (catch) e só então passar ao template.

 

Ou, agora, no template:

 

<?php foreach( $this -> _cache -> load( 'AlmostImmutableDataList' ) as $data ) : ?>

<!-- Faz alguma coisa -->

<?php endforeach; ?>

Claro, isso é uma base muito crua, incompleta, instável e ainda precisaria aprimorar a captura da possível exceção disparada pêga no Controller, mas acho que depois de tooooodo esse exemplo dá pra sacar o que eu quise dizer.

 

Quer dizer, espero que sim, explicar as coisas sempre foi difícil pra mim.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Acabou que sua idéia do main() me caiu como uma luva .. sabe o outro tópico, na dúvida do setDatabaseConnection ? .. então, esse método main é abstrato na AbstractModel, ou Model se preferir, ou seja, ele tem que ser implementado em qualquer model .. daí, é nele que eu dou o init em qqr coisa necessária para ser utilizado no mapper, logo, no mapper, eu já verifico se tem uma conexão com o banco na execução de métodos que utilizam o banco ( tudo )

 

<?php
      abstract class Mapper {
             final public function __construct ( ) {
                    $this->main();
             }    
      }

      abstract class Model extends Mapper { 
             abstract public function main ( ) ;      
      }

      class Customers extends Model { }

 

No código acima, gera um fatal error, mas deu pra pescar a idéia.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom, no meu caso, main é apenas um método. Inicialização adicional vai num init, o qual é chamado no fim do construtor da classe abstrata.

 

Porém, seu eu fosse você eu não faria esse método abstrato. Eu criaria ele na própria classe abstrata mas não prefixaria ele com final.

 

Assim, sobrescreve o método apenas quem precisar. Assim, nas classes que não precisarem você não tem um:

 

public function main {}

Vazio, às moscas...

 

Mas você não disse se toda a novela que eu escrevi ajudou em alguma coisa. Espero que sim. :grin:

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.