Esta es la presentación sobre Yupp Framework PHP hecha en las Jornadas de Informática e investigación Operativa de la Facultad de Ingeniería de Montevideo, Uruguay, que la disfruten.
También puede ser descargada aquí.
Blog sobre tecnología, innovación y desarrollo, con un eje central en el YUPP Framework (MVC) PHP.
Esta es la presentación sobre Yupp Framework PHP hecha en las Jornadas de Informática e investigación Operativa de la Facultad de Ingeniería de Montevideo, Uruguay, que la disfruten.
También puede ser descargada aquí.
El soporte para layouts es una característica bien importante para cualquier framework MVC y Yupp Framework no se podría quedar atrás, así que empecé a buscar información sobre implementación de layouts, patrones de diseño, y frameworks especializados en layouts y templates.
Un sistema de layout ayuda a ahorrar código en las vistas, de forma que varias vistas puedan compartir código común que está en un único archivo externo.
En un momento, luego de leer un rato sobre las posibles formas de implementarlo, más algunas ideas que tenía en mente, probé una pequeña implementación de un sistema de layout, y luego de un par de horas (y para mi sorpresa) lo teníaandando integrado con el framework. En este post mostraré como es que se utilizaría esta implementación de layouts.
La idea principal era no tener que modificar demasiado las vistas de forma que las vistas ya creadas sigan funcionando bien aunque no tengan referencia a un layout. Por lo tanto inventé una tag que sirve para crear la referencia desde una vista:
<layout name="blog" />
Esta tag debe ser incluída luego de <html> y antes de <head>,
para hacer más clara la referencia y más fácil de implementar el procesamiento de esa tag.
El procesamiento debía ser muy rápido y casi no afectar la velocidad de procesamiento actual, de esta forma probé hacer un procesamiento de layout mediante expresiones regulares y mediante operaciones con strings, y la velocidad con las operaciones con strings fue muchísimo mejor que con expresiones regulares, y muchísimo mejor me refiero a varios órdenes por debajo:
El layout tiene la estructura de una vista pero no hace referencia al modelo y tiene dos variables disponibles para poder mostrar el contenido de la vista de la cual es layout, estas son $head y $body, que representan el contenido del <head> y del <body> de la vista.
Este es un ejemplo de un layout:
<html>
<head>
<style type="text/css">
...
</style>
<?php echo $head; ?>
</head>
<body>
<div style="padding:10px; background-color:#6af;" align="right">
<?php echo h('locale_chooser'); ?>
</div>
<div style="padding:10px;">
<?php echo $body; ?>
</div>
</body>
</html>
Por último quien hace el proceso de la vista es una clase llamada LayoutManager que se
encarga de resolver referencias a layouts y mostrar la vista generada. Si la vista no contiene una referencia a un layout, simplemente muestra la vista igual que antes.
Si bien esta solución funciona bien, se puede mejorar en varios aspectos:
Una nueva característica que vino con la versión 0.1.2 del framework es la de no necesitar explicitar la vista que se va a utilizar. Por ejemplo con la acción edit, la forma de especificar la vista a utlizar se hace mediante el retorno de llamar al método “render” de YuppController:
class EntradaBlogController extends YuppController {
public function editAction()
{
$id = $this->params['id'];
$obj = EntradaBlog::get( $id );
$this->params['object'] = $obj;
return $this->render("entradaBlog/edit", &$this->params);
}
}
Esta es la única forma de especificar la vista previo a la versión 0.1.2, con Yupp Framework PHP v0.1.2 se puede retornar solo el modelo y la vista se resuelve de forma automática por Yupp Framework:
class EntradaBlogController extends YuppController {
public function editAction()
{
$id = $this->params['id'];
$obj = EntradaBlog::get( $id );
$this->params['object'] = $obj;
return $this->params;
}
}
En este caso, el framework buscará una vista llamada “edit”, igual al nombre de la acción, dentro del directorio de vistas del controller “EntradaBlog”. También se podría retornar NULL o nada en caso de no querer mostrar modelo. En una próxima versión no será necesario tampoco retornar el modelo, ya que como “params” es un campo de “YuppController” puede ser accedido sin necesidad de retornarlo de forma explícita.
La idea fundamental de estas pequeñas características es reducir la cantidad de código que es necesario escribir para implementar cierta funcionalidad y tener varias formas consistentes de hacer lo mismo de forma que cada usuario programe como más le guste y que el framework no restrinja esa libertad.
Hemos publicado un documento que explica los pasos necesarios para empezar a desarrollar aplicaciones web utilizando Yupp Framework PHP.
El mismo trata el ejemplo de desarrollo de un sistema simple de blog, donde los usuarios serán capaces de crear entradas y agregar comentarios. Dicho ejemplo viene implementado junto con la descarga de Yupp Framework v0.1.
Para descargarlo puedes acceder aquí.
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
Lo descrito anteriormente sucede porque PHP resuelve el nombre de la clase por la clase a la cual pertenece el método que se está invocando, lo que tal vez se puede ver como una violación al polimorfismo, es decir, que esperamos que el código anterior devuelva el nombre de la clase sobre la cual es invocado el método, pero no es así.
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // Here comes Late Static Bindings
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
function getFileNames($path, $match = null, $groups = null)
{
if (is_dir($path))
{
$res = array();
$d = dir($path);
while (false !== ($entry = $d->read()))
{
if (is_file($path . "/" . $entry))
{
$matches = null;
if ($match)
{
if (preg_match($match, $entry, $matches))
{
if (!$groups) $res[] = $entry;
else
{
$gentry = "";
foreach($groups as $i)
{
$gentry .= $matches[$i];
}
$res[] = $gentry;
}
}
}
else // Si no paso match, le entrego derecho la entrada.
{
$res[] = $entry;
}
}
}
$d->close();
return $res;
}
else
{
throw new Exception("El directorio: $path no existe.");
}
}
function getFileNames($path, $match = null, $groups = null)
if (is_dir($path))Verifica si path es un directorio válido, si no lo es lanza una excepción.
$res = array();Se crea la lista de nombres a devolver, todos los nombres de archivos que coincidan con los criterios serán incluidos en res.
$d = dir($path);Se abre el directorio para comenzar a leer sus entradas. Para entender como trabaja dir() visita el manual.
while (false !== ($entry = $d->read()))Recorre cada entrada del directorio, estas son archivos y subdirectorios, entry es el nombre del archivo o subdirectorio actual en la recorrida.
Si match no es null, verifico que entry coincida con él. Para entender como trabaja preg_match, visita el manual. En matches se guardan los grupos definidos en match que coincidieron con entry, y si groups no es null los voy a usar para armar los nombres que voy a devolver.
if ($match)
{
if (preg_match($match, $entry, $matches))
if (!$groups) $res[] = $entry;Si groups es null, simplemente agrego entry a la solución, o sea, devuelvo el nombre del archivo así como está y se que ese nombre coincide con la expresión regular match.
else
{
$gentry = "";
foreach($groups as $i)
{
$gentry .= $matches[$i];
}
$res[] = $gentry;
}
else // Si no paso match, le entrego derecho la entrada.Si match es null, simplemente agrego a la solución el nombre del archivo sin procesarlo.
{
$res[] = $entry;
$d->close();Cierra el directorio y devuelve la solución.
return $res;