Buscar temas sin respuesta | Ver temas activos |

Nuevo tema Responder al tema Índice general » Programacion: Vieja escuela » Teoria de sistemas
Autor Mensaje
Desconectado 
 Asunto: MVC. con codigo.
NotaPublicado: 27 Mar 2008 11:26 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
Esto es una implementacion, mas que nada de Controller/Routing, que hackie.. en un dia, para usar mod_rewrite, clean urls, mvc en el laburo.
Si alguien ve algun tipo de vulnerabilidad. porfavor avise, puteeme, riansee. viene bien.

Asumamos una estructura del root de un vhost:
Código:
.
..
index.php
controller/
model/
view/
mastropiero/
includes/


Junto a un .htacces:
Código:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]

En cristiano: todo request que no mapee a un archivo o directorio existente. se pasa lo que viene despues del host, como parametro url a index.php.

index.php
Código:
<?
/**
    * LICENSE
    * GPL, blah blah.  google it.
    *
    * @category MastropieroVC
    * @package ControllerRuteo
    * @copyright Copyright (c) 2006-2008 Allkom S.A. http://www.all-kom.com.ar
    * @license http://www.gnu.org/licenses/gpl.txt
    */
include("includes/configurations.php");

/**
* Registro Controladores permitidos.  fuera de estos, ninguno va a poder ser ejecutado
*/
$controladores = array("Soluciones", "Servicios", "Casos", "Rrhh", "Admin", "Usuario", "Home", "Hardware");

/**
* Defino controlador y accion por defecto.
*
*/
define('CONTROLADOR_DEFECTO', "Home");
define('ACCION_DEFECTO', "index");

/**
* Agarro la url que me pasa el modrewrite
*/

if(isset($_GET["url"])){
   $parametros = explode("/",$_GET["url"]);
   unset($_GET["url"]);
}

/**
* creo el Meta-Controlador
* Registro los controladores que defini con el meta-controller
*/

$controller = new ControllerRuteo($controladores);
$controller->Render($parametros);

?>

Basicamente, uno agrega una capa por sobre $_GET. Reemplazando el uso de $_GET, por parametros, que ahora van a ver como se van pasando de lado a lado.

ControllerRuteo.php
Código:
<?
   /**
    * LICENSE
    * GPL, blah blah.  google it.
    *
    * @category MastropieroVC
    * @package ControllerRuteo
    * @copyright Copyright (c) 2006-2008 Allkom S.A. http://www.all-kom.com.ar
    * @license http://www.gnu.org/licenses/gpl.txt
    */
   class ControllerRuteo{
      /**
       * Controller que se llama el request.
       * @var string $controller
       */
      public $controller;
      /**
       * Perfil/Role del usuario.  Para implementar ACL sobre Controllers.
       *
       * @var string $_perfil;
       */
      protected $_perfil;
      /**
       * array de con controler autorizados.
       *
       * @var array(string) $_clasesRegistradas
       */
      protected $_clasesRegistradas;

      /**
      *   Inicio con controlador por defecto, luego cambia, si es necesario.
      */
      public function __construct($registrados = array()){
         $this->controller = CONTROLADOR_DEFECTO;
         $this->_perfil = $_SESSION["usuario"]["perfil"];
         $this->_clasesRegistradas = $registrados;
      }
      
      /**
       * Dice si tiene acceso a ese control en particular
       * Rutina de control de acceso al controller
       * TODO:  Podria llamar un objeto que implemente una interface, si quisiera extenderlo en tal medida.
       * @return Boolean
       */
      protected function _tienePermiso($controller){
         $bool = true;
         return $bool;
      }
      /**
       * Set/Get de clases registradas
       *
       * @param array $reg
       * @return array
       */
      public function Registrados($reg = array()){
         if(count($reg) == 0)
            return  $this->_clasesRegistradas;
         else
            $this->_clasesRegistradas = $reg;
      }
      
      /**
       * Aca esta la magia.
       * crea una instancia de la subclase de Controller y llama render de ese controller.
       * hace un define del Controller, para tener el "enviroment" del request en todo momento.
       */
      public function Render($params = array()){
            //Primer param es siempre el controller.
            if(count($params) > 0){
               $this->controller = array_shift($params);
               define("CONTROLLER", $this->controller);
            }
            //chequeo que este registrado el controller en la lista.
            if(in_array($this->controller, $this->_clasesRegistradas)){
               //si el usuario tiene permiso sobre el controller.
               if($this->_tienePermiso($this->controller)){
                  //hace un "dispatch" (basicamente es un factory pattern) del controller solicitado.                  
                  $var = $this->controller."_Controller";
                  $class = new $var;
                  $class->Render($params);
                  
               }else{
                  //TODO: Llamar una excepcion custom que redirija/loggee, etc...
                  throw new Exception("No tiene acceso sobre el controlador");
               }
               
            }else{
               //Idem todo arriba.
               throw new Exception("El controlador: $this->controller no esta registrado");
            }
      }
   }
?>

Esta re bien comentado, aveces me sorprendo.
Cuando menciono patter, noten como utilizo convencion para llamar a una clase con nombre Controlador + "_controller" ( que es un toque verboso, pero cuando tenes controller y model de una misma entidad, ayuda a no confundir. Entidad_Controller y Entidad_Model)

Controller.php
Código:
<?
/**
    * LICENSE
    * GPL, blah blah.  google it.
    *
    * @category MastropieroVC
    * @package Controller
    * @copyright Copyright (c) 2006-2008 Allkom S.A. http://www.all-kom.com.ar
    * @license http://www.gnu.org/licenses/gpl.txt
    */
class Controller{
   /**
    * Accion del controller.  2 parametro de la url.  1ero que me llega.
    * @var string $_action
    */
   protected $_action;
   /**
    * Again, es al pedo realmente.
    * @var $_SESSION["usuario"]["perfil"] o similar
    */
   protected $_perfil;

   
   public function __construct(){
      $this->_action = ACCION_DEFECTO;
      $this->_perfil = $_SESSION["usuario"]["perfil"];
   }
   
      /**
    * Dice si tiene acceso a esa Accion en particular
    * Rutina de control de acceso al controller
    * @return Boolean
    */
   protected function _tienePermiso($accion){
      $bool = true;
      return $bool;
   }
   
   /**
   *   Dispatcher de acciones.
   */
   public function Render($params = array()){
      
      if(count($params) > 0){
         foreach ($params as $parametro){
            if(!ereg("^[a-zA-Z0-9_\ \-]+$", $parametro)) //valido que sea un string "valido" como accion.
               throw new Exception("Naughty you! Invalid chars para llamar accion", 7);
         }
         $this->_action = array_shift($params);
         define("ACTION", $this->_action); // defino la accion en el enviroment del request.
      }
      
      
      //Aparte de no poder llamar funciones que empiezen con _, Render.  Los metodos deben ser publicos para que se puedan ejecutar.
      if($this->_tienePermiso($this->_action) && (substr($this->_action, 0, 1) != "_") && $this->_action != "Render"){
         
         if(count($params) <= 0){
            $var = $this->_action;
            $this->$var();
            
         }else{
            /**
             * Ejecuta la accion y pasa lo que queda de los parametros a la accion.
             * al mandar el stack de parametros, no necesito ningun eval.
             */
            $this->{$this->_action}($params);
         }
      }else
         //un redirect a un 404 seria mas conviniente/prolijo
         throw new Exception("No tiene acceso sobre la accion");
   }
}

?>


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 27 Mar 2008 11:31 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
En pocas palabras.
Lo que harias para empezar a usar esto seria:
registrar controladores en el index.php
crear una subclase de controller en /controller/ y agregarle tus acciones.

Por ejemplo:
Código:
class Hardware_Controller extends Controller{
   public function index(){
      $vw = new View("view/hardware/lista.tpl");
      echo $vw->fetch();
   }
       //Sobreescribo para implementar mis condiciones de acceso a la accion o controlador.
       protected function _tienePermiso($accion){
      if(!$_SESSION["access"])
         Redirect(Href("Usuario"));
      return true;
   }
}


Que lo llamaria: www.lala.com/Hardware

Como se ve mas arriba, al no tener accion definida, llama la por defecto, en este caso index.


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 27 Mar 2008 11:38 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
Como manejar includes.
Por la naturaleza dinamica de todas las clases que llamo y toda la bola.
En el include que hago en el index.php, defino el autoload, que es la funcion que llama php siempre que no encuentra una clase en el codigo incluido.
Código:
/**
*  0 Elegancia.  entendible.
*/
function __autoload($class_name) {
   $arr = explode("_", $class_name);
   if(count($arr) > 1){
      $file = "";
      
      $filename = "";
      
      for($i=0;$i<count($arr)-1;$i++)
         if($i == 0)
            $filename .= $arr[$i];
         else
            $filename .= "_".$arr[$i];
      
      
      switch($arr[count($arr)-1]){
         case 'Controller' : $file = $_SERVER["DOCUMENT_ROOT"]."/controller/".$filename.".php";
                        break;
         case 'Model':  $file = $_SERVER["DOCUMENT_ROOT"]."/model/".$filename.".php";
                        break;
      }
      
   }else{
      $file = $_SERVER["DOCUMENT_ROOT"]."/mastropiero/$class_name.php";
   }
   
   if(file_exists($file))
      include($file);
}


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 27 Mar 2008 11:47 
poster a 4 mbps
Avatar de Usuario

Registrado: 19 Nov 2003 23:02
Mensajes: 1484
Ubicación: Haedo - Palomar
muy bien explicado, aporto con un "framework" mvc en php, si, entre comillas porque no se puede llamar framework, son pocas lineas pero es realmente bueno

OneFileFramework

http://www.pmedia.no/off/

en la pagina dice

Código:
    * Want internationalization? Use PHP's own gettext().
    * Want powerful database abstraction? Use PHP's own PHP Data Objects.
    * Want the fastest and most powerful PHP templating language? Use PHP itself!
    * Want fancy URL's? Use mod_rewrite.
    * Want efficient caching? Use mod_cache.


y tiene toda la razon

para hacer cosas chicas y prolijas viene realmente bien, no son esos frameworks sobrecargados, se agrega lo que se necesite, el codigo es una boludez, cuando lo use, le hice mejoras, lo adapte digamos, y como libreria de persistencia use adodb

_________________
http://personales.ciudad.com.ar/rulrulrul/increible.htm


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 27 Mar 2008 11:54 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
Si man. es el mismo approach que use yo.
es mas, te muestro la clase view. :roll:
Código:
<?php
/**
* http://www.massassi.com/php/articles/template_engines/
* © Brian Lozier 2003 (brian@massassi.net)
* Modified by: Matias Hughes 2007 (tute666@gmail.com)
*/
   class View {
       private $vars; /// Holds all the template variables
   
     /**
        * Constructor
        *
        * @param $file string the file name you want to load
        */
       public function __construct($file = null) {
           $this->file = $file;
       }
   
       /**
        * Set a template variable.
        */
       function set($name, $value) {
           $this->vars[$name] = is_object($value) ? $value->fetch() : $value;
       }
       /**
        * Open, parse, and return the template file.
        * Edited, now renders correctly when $this->vars is empty
        * @param $file string the template file name
        */
       function fetch($file = null) {
      if($file != null)
              $this->file = $file;
      if(count($this->vars) > 0)
              extract($this->vars);          // Extract the vars to local namespace
           ob_start();                    // Start output buffering
           include($this->file);                // Include the file
           $contents = ob_get_contents(); // Get the contents of the buffer
           ob_end_clean();                // End buffering and discard
           return $contents;              // Return the contents
       }
   }
?>

y tenemos templates. automagicamente.
Sigo buscando un diagrama de secuencia que valga la pena. pero ni encuentro.


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 10 Abr 2008 18:01 
root@pcmasmas:~#
Avatar de Usuario

Registrado: 31 Dic 1969 21:00
Mensajes: 24812
Ubicación: London [uK]
que groso esta!

no habia podido mirarlo en su momento

muy bien aplicado dadas las restricciones de php.

golazo :)

ice


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 11 Abr 2008 11:41 
poster a 56 kbps

Registrado: 28 May 2002 20:50
Mensajes: 254
http://www.symfony-project.org/


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 18 Abr 2008 22:48 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
grunjol escribió:
http://www.symfony-project.org/

si, y una lista ANORME de otros.
tu punto?
No voy a usar algo que no se adapta a mis necesidades.


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 19 Abr 2008 03:40 
poster a 1 tbps
Avatar de Usuario

Registrado: 12 Ene 2004 13:15
Mensajes: 1741
Ubicación: localhost
Creo que el cache está mucho mejor resuelto a nivel de aplicación que usando cosas como mod_cache, te permite un control mucho más fino sobre lo que querés hacer y se obtiene mucha más flexibilidad y por lo tanto mayor rendimiento.

Usar mod_rewrite para las URLs no es DRY, eso es un tema, pero también es un tema como changos hacerlo DRY, cosa que en un sitio grande puede ser determinante. No conozco ninguna opción para esto que no sea excesivamente larga de configurar, y a la vez sea suficientemente flexible.

La internacionalización es otro punto en que un framework minimalista pero decente te ahorra mucho trabajo y reinvento de ruedas. Esencialmente creo que un framework web debería darte una receta simple para tener modelos i18n-ables de forma transparente, una receta simple para traducir el código de los templates, y finalmente una serie de variantes de selección del lenguaje a presentar al usuario. "Usa gettext()" no me parece una opción viable.

Por último tiene que haber algún tipo de automatización al generar formularios, que es la tarea por lejos más tediosa de la programación web.

En lo que sí estoy 100% de acuerdo es en que PHP es el mejor lenguaje de templates para PHP.


Saludos ;)


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 19 Abr 2008 14:10 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
estoy armando el scaffolding, por ahora uso una combinacion de describe tabla y ciertros atributos en la clase de model para complicarlo un toque.

No entiendo el tema de mod_rewrite que no es DRY gomox, igual, para clean urls es necesario :S, por lo menos en php.

Por ahora el tema de internacionalizacion, que rara vez uso, se me acaba de ocurrir de cargar constantes que se usan en el template. Y cache eventualmente vere como implementarlo, lamentablemente rara vez implemento sistemas que sean demasiado masivos.


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 19 Abr 2008 14:54 
poster a 1 tbps
Avatar de Usuario

Registrado: 12 Ene 2004 13:15
Mensajes: 1741
Ubicación: localhost
mod_rewrite no es DRY porque vos tenés esencialmente una función de vista (o controlador si prefieren llamarlo así) que recibe parametros a partir de la URL del pedido HTTP del navegador.

De forma canónica es así:
/vista.php?obj_tipo=perro&obj_id=4&accion=editar

Vos con mod_rewrite lo mapeás a:
/perros/4/editar/

Pero después tenés que agregar links a esa página en tu sitio web! Como lo hacés? Ponés "/perros/4/editar/"? Tenés información duplicada ya que en 2 lugares completamente separados y imposibles de relacionar (un .htaccess y tu codigo de plantillas) estás decidiendo cual es la URL "linda" para esa acción.

Una opción es tener un mapeo bidireccional vista <-> URL en algún lugar del sistema, y utilizar los nombres de las vistas (/vista.php?blabla) en los links, con algún middleware que los reemplace por los verdaderos (/perros/4/editar/) antes de enviar las páginas al browser. Esto funciona, pero es muy difícil hacerlo flexible (por ejemplo, que algunas vistas tengan más de una URL, o que se agrupen de alguna manera que no sea estrictamente un arbol de navegación) y aparte es choto como idea y posiblemente sea lento. Aparte si tenés contenido generado por usuarios tenés que hacer tu propio editor WYSIWYG porque obviamente ninguno de los existentes soporta esto de forma amigable, la gente pone los links que ve en el sitio.

No creo que usar mod_rewrite sea obligatorio, o al menos no de esta forma "por URL", si usás una única regla que matchee todos tus requests a un dispatcher.php por decir algo, y ahí parseás la URL usando PHP, podés utilizar soluciones alternativas a definir página por página las URLs en un archivo de configuración de Apache.


i18n con constantes es un poco retrogrado, te recomiendo que uses un paquete de i18n "como la gente" para PHP (que debe haber) ya que con las herramientitas que te trae GNU gettext la vida se hace mucho más simple (make-messages en particular). Es bastante más cómodo que usar constantes y ya está resuelto el tema de los encodings, y además hay editores especiales para este tipo de archivos que pueden resultar útiles.

Saludos ;)


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 19 Abr 2008 16:34 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
Claro, tengo una func Href($controller = "", $action = "", $params = array())
Si tengo soporte mod_rewrite me hace todo lindo, en su defecto me arma las urls como siempre, puedo pasarle params como key/value o values solamente. Hace poco estuve en esta situacion y con cambiar la funcion todo funciono automagicamente. Excepto cuando hardcodie un par de urls :S

Hablando de editores WYSIWYG con mod_rewrite, lo he usado previamente, y por como uso el mod_rewrite, nunca tuve problemas, _por ahora_.
Otra manera de implementar clean url's es redireccionando 404 a el dispatcher, no probe esto todavia, mas que nada porque por lo que vi, no conserva post parameters. tengo que hacer un testcase aver que onda.
Sobre i18n, es algo pendiente.


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 19 Abr 2008 23:36 
poster a 1 tbps
Avatar de Usuario

Registrado: 29 May 2003 22:21
Mensajes: 3967
Ubicación: Lorcalandia
gomox, php es una negrada, no te pongas a pensar...

osea, ya sea como lenguaje o como posibilidades que te da, yo que se, lo veo asi...

_________________
Ascendiste de esta manera: "PRIPPP.... PENALLLLLLLLL PARA RIBERRRRRRRRRRRRRRR"


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 19 Abr 2008 23:38 
poster a 1 tbps
Avatar de Usuario

Registrado: 29 May 2003 22:21
Mensajes: 3967
Ubicación: Lorcalandia
tute666 ojo, no lo digo por el code que pusiste que si bien esta copado, php a mi parecer es un lenguaje de hacks tras hacks

_________________
Ascendiste de esta manera: "PRIPPP.... PENALLLLLLLLL PARA RIBERRRRRRRRRRRRRRR"


Arriba
 Perfil  
 
Desconectado 
 Asunto:
NotaPublicado: 20 Abr 2008 13:45 
poster a 1 tbps

Registrado: 23 Mar 2003 22:56
Mensajes: 2928
pero concuerdo lorca.
Es un lenguaje cabeza.
Pensa que fue una implementacion scripteable de c, practicamente.
Por eso tenes todas las funciones que no son mas que wrappers de las funciones de C. Depues se fue migrando a un modelo OOP, no hay ningun tipo de organizacion, ningun tipo de nomenclatura para funciones ni nada. Es un lenguaje de mierda.
Las posibilidades que te brinda, son considerables. es facil construir sobre el lenguaje.


Arriba
 Perfil  
 
Mostrar mensajes previos:  Ordenar por  
Nuevo tema Responder al tema  [ 15 mensajes ] 


  Imprimir vista Tema previo | Siguiente tema 

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado


Todos los horarios son UTC - 3 horas


No puede abrir nuevos temas en este Foro
No puede responder a temas en este Foro
No puede editar sus mensajes en este Foro
No puede borrar sus mensajes en este Foro
No puede enviar adjuntos en este Foro

Buscar:
Saltar a:  
PC++ Style
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Traducción al español por Huan Manwë