Como Bootear desde en una Maquina Virtual VirtualBox

Como Bootear desde en una Maquina Virtual VirtualBox


Si llegaste hasta aqui es porque, seguro que no encontraste la forma de seleccionar tu pendrive en el orden de booteo. Ademas parece que VB no da soporte aun en los BIOS virtuales…

Por eso, podemos probar esto:

1) Crea una nueva Maquina Virtual
b) En la seccion “Floppy” del panel derecho, ingresa.
c) Activa “Mount Floppy Drive”, y de la lista desplegable “Host Floppy Device”, selecciona la letra o ruta de tu pendrive (e: en windows, por ej:; en linux puede ser /dev/sdxx)

Listo!.
Saludos

Publicado en Software Libre, Tecnología IT | Deja un comentario

Quini 6

¿ Querés saber si vas a ganar ?

Es Facil, escribi en un papel seis numeros del 00 al 45.

Entonces visita : http://puentesdiaz.com.ar/azar/quini.php

y con la tecla F5, podes simular otro sorteo, y probar si tus numeros traen suerte!!!

==============================================

[quini6]

Si tenes 6 o 5 o 4 aciertos en la primer serie, hay premio.

Si tenes 6 o 5 o 4 aciertos en la segunda serie, hay premio.

Si tenes 6 aciertos en la tercer serie (Revancha), hay premio.

En el SIEMPRE SALE, la cuarta serie, siempre hay ganadores:

Si hay ganadores, con 6 aciertos, se reparte entre ellos, y no importa los de 5, 4, 3 aciertos y asi….

Si no hay ganadores, con 6 aciertos, buscamos ganadores con 5, sino con 4 y asi…

Los 18 depurados. Si en el ultimo listado, estan tus seis numeros elegidos, tambien hay premio

Como veras, hay muchas posibilidades :p

Eso quisieras!, regresa a tus labores!

Cr. Puentes Diaz

MP 10.12726.9

Córdoba – Argentina

Linux User n° 441474

Ubuntu/Symfony/Eclipse Rocks!

Publicado en Deporte & Salud, General | Deja un comentario

Symfony 1.2 Bondades de Doctrine

Un Gran Agradecimiento

Una gran cantidad de cosas impresionantes, se han añadido recientemente a la proxima gran entrega de symfony 1.2. Fabien ha trabajado muy duro para agregar sin dudas las más sofisticadas características que cualquier otro framework PHP pudiera tener hoy en día. No sólo son características agradables sino que fueron implementadas Orientada a Objeto por lo que ha sido sencillo para mi implmentar algunas características con otro ORM, Doctrine.Todo esto se hizo con muy poco trabajo de mi parte. Por lo tanto, doy muchas gracias a él y disfruta de este artículo.

Ejemplo del mundo real

En este artículo voy a empezar desde el principio con un nuevo proyecto symfony 1.2 para que puedas ponerte en marcha con Doctrine. Vamos a utilizar un esquema típico de tu sistema de gestión de contenidos. El esquema consta de los artículos, los autores y categorías donde los artículos son internacionalizados.

Comienza tu Proyecto

En primer lugar necesitas inicializar un nuevo proyecto symfony 1.2 y inicializar un app backend. Asegúrate de que estás utilizando el último código del svn pues beta1 no incluye esta funcionalidad de Doctrine.

Generar tu proyecto

mkdir cms
cd cms
symfony generate:project cms

Generar la aplicación backend

symfony generate:app backend

Todo el mundo encienda su Doctrine

Ahora tenemos que habilitar Doctrine y desactivar Propel :) Edita tu config/ProjectConfiguration.class.php y agregue el código siguiente a tu función setup().

public function setup()
{
  $this->enablePlugins(array('sfDoctrinePlugin'));
  $this->disablePlugins(array('sfPropelPlugin'));
}

Ahora que Doctrine está habilitado podemos enumerar las tareas disponibles de Doctrine:

./symfony list doctrine

Available tasks for the "doctrine" namespace:
  :build-all                   Generates Doctrine model, SQL and initializes the database (doctrine-build-all)
  :build-all-load              Generates Doctrine model, SQL, initializes database, and load data (doctrine-build-all-load)
  :build-all-reload            Generates Doctrine model, SQL, initializes database, and load data (doctrine-build-all-reload)
  :build-all-reload-test-all   Generates Doctrine model, SQL, initializes database, load data and run all test suites (doctrine-build-all-reload-test-all)
  :build-db                    Creates database for current model (doctrine-build-db)
  :build-filters               Creates filter form classes for the current model
  :build-forms                 Creates form classes for the current model (doctrine-build-forms)
  :build-model                 Creates classes for the current model (doctrine-build-model)
  :build-schema                Creates a schema from an existing database (doctrine-build-schema)
  :build-sql                   Creates SQL for the current model (doctrine-build-sql)
  :data-dump                   Dumps data to the fixtures directory (doctrine-dump-data)
  :data-load                   Loads data from fixtures directory (doctrine-load-data)
  :dql                         Execute a DQL query and view the results (doctrine-dql)
  :drop-db                     Drops database for current model (doctrine-drop-db)
  :generate-admin              Generates a Doctrine admin module
  :generate-migration          Generate migration class (doctrine-generate-migration)
  :generate-migrations-db      Generate migration classes from existing database connections (doctrine-generate-migrations-db, doctrine-gen-migrations-from-db)
  :generate-migrations-models  Generate migration classes from an existing set of models (doctrine-generate-migrations-models, doctrine-gen-migrations-from-models)
  :generate-module             Generates a Doctrine module (doctrine-generate-crud, doctrine:generate-crud)
  :generate-module-for-route   Generates a Doctrine module for a route definition
  :insert-sql                  Inserts SQL for current model (doctrine-insert-sql)
  :migrate                     Migrates database to current/specified version (doctrine-migrate)
  :rebuild-db                  Creates database for current model (doctrine-rebuild-db)

El Esquema

Ahora empieza la diversión. Tenemos Doctrine habilitado por lo que la primera cosa que necesitamos es definir nuestro esquema del CMS en config/doctrine/schema.yml.

---
Article:
  actAs:
    Timestampable:
    I18n:
      fields: [title, content]
  columns:
    author_id: integer
    status:
      type: enum
      values: [Draft, Published]
      notnull: true
    title:
      type: string(255)
      notnull: true
    content:
      type: clob
      notnull: true
    is_on_homepage: boolean
    published_at: timestamp
  relations:
    Author:
      foreignAlias: Articles
    Categories:
      class: Category
      refClass: ArticleCategory
      foreignAlias: Articles
 
Category:
  columns:
    name:
      type: string(255)
      notnull: true
 
Author:
  columns:
    name:
      type: string(255)
      notnull: true
    about: string(1000)
 
ArticleCategory:
  columns:
    article_id: integer
    category_id: integer
  relations:
    Article:
      foreignAlias: ArticleCategories
    Category:
      foreignAlias: ArticleCategories
 

Datos Fixtures

Tenemos nuestro esquema, ahora necesitamos algunos datos para ponerlo a prueba por lo que copia de los siguientes YAML en data/fixtures/data.yml

---
Article:
  Article_1:
    Author: jwage
    status: Published
    is_on_homepage: true
    published_at: ''
    Categories: [article, ontheedge]
    Translation:
      en:
        title: symfony 1.2 and Doctrine
        content: Article about the new Doctrine integration in symfony 1.2
      fr:
        title: symfony 1.2 et doctrine
        content: Article sur l'intégration de Doctrine dans symfony 1.2

Author:
  jwage:
    name: Jonathan H. Wage
    about: Jonathan is the lead developer of the Doctrine project and is also a core contributor to the symfony project.

Category:
  article:
    name: Article
  tutorial:
    name: Tutorial
  ontheedge:
    name: Living on the edge
 

Desarrollo y Pruebas

Ahora que tenemos nuestro esquema y los datos tenemos todo lo que necesitamos para inicializar nuestra base de datos, modelos, formularios, datos, etc. Esto puede ser hecho con el muy simplemente comando siguiente:

./symfony doctrine:build-all-reload --no-confirmation
>> doctrine  dropping databases
>> doctrine  creating databases
>> doctrine  generating model classes
>> doctrine  generating sql for models
>> doctrine  generating form classes
>> doctrine  generating filter form classes
>> doctrine  created tables successfully
>> doctrine  loading data fixtures from "/Us...ymfony12doctrine/data/fixtures"

Eso fue demasiado fácil, cuando se va a poner difícil? Ahora vamos a hacer la inspección con DQL para ver los datos que se cargaron correctamente.

./symfony doctrine:dql "FROM Article a, a.Author a2, a.Translation t"
>> doctrine  executing dql query
DQL: FROM Article a, a.Author a2, a.Translation t
found 1 results
-
  id: '1'
  author_id: '1'
  status: Published
  is_on_homepage: true
  published_at: '2008-11-06 04:37:11'
  created_at: '2008-11-06 16:37:11'
  updated_at: '2008-11-06 16:37:11'
  Author:
    id: '1'
    name: 'Jonathan H. Wage'
    about: 'Jonathan is the lead developer of the Doctrine project and is also a core contributor to the symfony project.'
  Translation:
    en:
      id: '1'
      title: 'symfony 1.2 and Doctrine'
      content: 'Article about the new Doctrine integration in symfony 1.2'
      lang: en
    fr:
      id: '1'
      title: 'symfony 1.2 et doctrine'
      content: 'Article sur l''intégration de Doctrine dans symfony 1.2'
      lang: fr

Esto puede ser su primer gusto del Doctrine Query Language, también conocido como DQL. Se parece mucho a SQL no? Cierre la boca, que estás babeando.

Para aquellos de ustedes que no quieran escribir cadenas de DQL, no te preocupes tenemos un completo objeto Doctrine_Query para la construcción de tus consultas.

$q = Doctrine_Query::create()
  ->from('Article a, a.Author a2, a.Translation t');
$articles = $q->execute();

Generadores de Admin

Ahora que tenemos todo construido, podemos empezar a generar algunas cosas con la magia symfony. Vamos a empezar por la definición de la Colecciones de Rutas para la gestión de nuestros artículos, autores y categorías. Abre apps/backend/config/routing.yml en tu editor y pega las siguientes rutas dentro.

articles:
  class:         sfDoctrineRouteCollection
  options:
    model:       Article
    module:      articles
    with_show:   true
    collection_actions: { filter: post, batch: post }

categories:
  class:         sfDoctrineRouteCollection
  options:
    model:       Category
    module:      categories
    with_show:   true
    collection_actions: { filter: post, batch: post }

authors:
  class:         sfDoctrineRouteCollection
  options:
    model:       Author
    module:      authors
    with_show:   true
    collection_actions: { filter: post, batch: post }

Estas rutas nos permitirán generar un módulo generador de administrador para la gestión de los datos a través de cada uno de los modelos de Doctrine. Ejecute los siguientes comandos para generar los tres módulos.

./symfony doctrine:generate-admin backend articles
$ ./symfony doctrine:generate-admin backend categories
$ ./symfony doctrine:generate-admin backend authors

Ahora, cuando tiene acceso al modulo categories desde el backend deberías ver lo siguiente.

New Admin Generators

Ahora deseas, perrsonalizar un poco los artículos generados de admin para mostrar sólo una serie de campos en la lista y los filtros del formulario. Puedes hacerlo editando el generator.yml situado en apps/backend/modules/categories/config/generator.yml.

config:
  list:
    display:  [title, published_at, is_on_homepage, status]
  filter:
    class:    ArticleFormFilter
    display:  [author_id, status, is_on_homepage, published_at, categories_list]

Puedes personalizar los otros módulos de la misma forma.

Ahora, si cambia la URL ?sf_culture=fr en su URL el título se mostrará la versión en francés. Debería ver lo siguiente en su navegador cuando levantes hacia arriba el módulo de artículos.

New Admin Generators

Edición de Traducciones

Ahora, ¿cómo trabaja la edición de esas traducciones? Si te acuerdas de esto con los antiguos generadores de admin, era casi imposible. Ahora, se trata de una cuestión de añadir una línea de código a nuestro ArticleForm. Todo que tenemos que hacer es embeber/integrar/fusionar el formulario ArticleTranslation. Esto se puede hacer editando lib/form/doctrine/ArticleForm.class.php y añadiendo el código siguiente al configure()

public function configure()
{
  $this->embedI18n(array('en', 'fr'));
}

Ahora, cuando editas un artículo, verás que tienes la capacidad de editar directamente las traducciones dentro del artículo.

New Admin Generators I18n

Ahora que está muy bien pero que si deseas editar el Author directamente dentro del Article como así y que se cree un nuevo Author si no existe y el uso del actual Author si ese nombre existe. Esto es simple.

Editar / Añadir autor

Con el fin de añadir la funcionalidad descrita anteriormente tenemos que añadir un poco de código en tres lugares diferentes. En primer lugar necesitas embeber el formulario Author en el formulario Article editando lib/form/doctrine/ArticleForm.class.php y agregue el código siguiente.

public function configure()
{
  unset($this['author_id']);
  $authorForm = new AuthorForm($this->getObject()->getAuthor());
  unset($authorForm['about']);
  $this->embedForm('Author', $authorForm);

  $this->embedI18n(array('en', 'fr'));
}

Ahora, al ver la la edición y la creación de un artículo verá el formulario incorporado para el autor con la información existente.

New Admin Generators Embedded Author

Ahora el último paso es decir a Doctrine para que busque objetos existentes de Author la hora de establecer el nombre para que un nombre duplicado de Author no sea creado. Edita lib/model/doctrine/Author.class.php y sobreescribe el name mutator añadiendo el siguiente código.

public function setName($name)
{
  $name = trim($name);
  $found = Doctrine_Query::create()
    ->select('a.id')
    ->from('Author a')
    ->where('a.name = ?', $name)
    ->fetchOne(array(), Doctrine::HYDRATE_ARRAY);
  if ($found)
  {
    $this->assignIdentifier($found['id']);
  } else {
    $this->_set('name', $name);
  }
}

El código anterior será para verificar si un Author con el nombre pasado ya existe, Si existe se asignará el identificador del registro encontrado de lo contrario es lo que normalmente haría, establecer el nombre para el objeto.

Los métodos _set() y _get() deben utilizarse para evitar un bucle infinito cuando se sobrescriben accessors y mutators.

Wow, lo que realmente acaba de construir todo un backend para gestionar el contenido de un simple sistema de gestión de contenido en menos de una hora? Estamos seguros de que sí. Pruébalo y disfruta el desarrollo de ricas funcionalidad basada en web utilizando symfony y Doctrine.

La presente, es una traducción al castellano realizada por Roberto G. Puentes Diaz,
sobre el artículo new-in-symfony-1-2-doctrine-goodies de Jonathan Wage.

Publicado en Software Libre, Symfony | Deja un comentario

Symfony 1.2 : Dios salve a los formularios anidados

En symfony 1.1, introducimos el nuevo sub-framework de formularios. un gran paso para symfony, aun cuando la curva de aprendizaje sea un poco empinada.

Trabajamos mucho para hacerlo aun mejor
para symfony 1.2, y mas importante mas simple para los mas novatos.

Una de las fortalezas del framework de formularios es la capacidad de tratar con formularios anidados.
Un formulario que puede ser embebido en otro formulario el cual también puede ser embebido en otro formulario (y así sucesivamente):

$article = ArticlePeer::doSelectOne(new Criteria());

 
$articleForm = new ArticleForm($article);
$authorForm = new AuthorForm($article->getAuthor());

$companyForm = new AuthorForm($article->getAuthor()->getCompany());

 
$authorForm->embedForm('company', $companyForm);
$articleForm->embedForm('author', $authorForm);

 

El articleForm se muestra como sigue:

Embedded forms

Otra gran característica del framework de formularios es la capacidad de serializar formularios automaticamente. Como los formularios anteriores son de Propel, una simple llamada a $articleForm->save() automaticamente actualizara el objeto $article con los valores enviados y validados para grabarlos en la base de datos.

Pero habia un problema en symfony 1.1. Los objetos author y company
no eran guardados automáticamente. Entonces, tenias que sobreescribir el método save() para poder validar y actualizar los objetos manualmente.
Nada imposible de lograr, pero realmente molesto si tenemos un framework
que ya tiene toda la información necesaria para hacerlo automáticamente.

Esto ha sido implementado en symfony 1.2 y esta disponible desde la beta 2. Eso es, una única llamada a $form->save() ahora actualizara los objetos articulo, autor, y compania. Es una gran noticia, pero hay otra mas: El nuevo generador de admin también tiene en cuenta esta nueva característica.

La presente, es una traducción al castellano realizada por Roberto G. Puentes Diaz,
sobre el artículo new-in-symfony-1-2-god-save-the-nested-forms de Fabien Potencier.

Publicado en General | Deja un comentario

Que Feliz que Soy

Argentina Pais Generoso.
Hasta cuando te ven la cara debes poner una sonrisa.

Desde aqui, un abrazo solidario para aquellos que siguen siendo rehenes, de estos personajes.

Publicado en General, Sociedad, Software Libre | Deja un comentario

Symfony 1.2: El Generador Admin

Hoy, hemos fusionado la rama new_admin dentro de 1.2, lo que significa que symfony 1.2 ahora juega con el nuevo generador de admin, basado en el framework de formularios.

En este artículo, Sólo voy a describir los conceptos generales del nuevo generador de admin.
El capítulo sobre el generador de admin
en el libro symfony ya se ha actualizado, de modo que puedes comenzar a leerlo de inmediato.

La primera buena noticia es que el nuevo generador de admin es muy similar al anterior. Incluso siendo que no es muy compatible hacia atrás en el sentido de que utiliza el nuevo framework de formularios, la configuración sigue siendo manejada por el archivo de configuración generator.yml, y las posibilidades de configuración son bastante similares.
También he tratado de mantener la misma filosofía para ayudar a los usuarios actuales a aprender la nueva herramienta con más facilidad.

Un simple CMS como ejemplo

Para ilustrar este artículo, Tomemos el ejemplo que ya hemos utilizado en un artículo anterior:

database schema

propel:
  demo_article:
    id:             ~
    author_id:      { type: integer, foreignReference: id, foreignTable: demo_author, onDelete: cascade, onUpdate: cascade, required: true }
    status:         { type: varchar(255), required: true }
    title:          { type: varchar(255), required: true }
    content:        { type: longvarchar, required: true }
    is_on_homepage: boolean
    published_at:   timestamp
    created_at:     timestamp
    updated_at:     timestamp
 
  demo_category:
    id:          ~
    name:        varchar(255)
 
  demo_author:
    id:          ~
    name:        varchar(255)
 
  demo_tag:
    id:          ~
    name:        varchar(255)
 
  demo_tag_article:
    tag_id:      { type: integer, primaryKey: true, foreignReference: id, foreignTable: demo_tag, onDelete: cascade, onUpdate: cascade, required: true }
    article_id:  { type: integer, primaryKey: true, foreignReference: id, foreignTable: demo_article, onDelete: cascade, onUpdate: cascade, required: true }
 
  demo_category_article:
    category_id: { type: integer, primaryKey: true, foreignReference: id, foreignTable: demo_category, onDelete: cascade, onUpdate: cascade, required: true }
    article_id:  { type: integer, primaryKey: true, foreignReference: id, foreignTable: demo_article, onDelete: cascade, onUpdate: cascade, required: true }
 

Este es un esquema clásico de un simple CMS. Los artículos tienen un autor y puede tener muchas etiquetas y categorías.

Una arquitectura REST

El nuevo administrador generador se basa en una arquitectura REST. Esto significa que usted necesitas crear una colección de rutas REST para el nuevo modulo admin. Aquí hay un ejemplo para el modelo DemoArticle con todas las opciones necesarias:

# apps/frontend/config/routing.yml
articles:
  class:   sfPropelRouteCollection
  options:
    model:       DemoArticle
    module:      article
    with_show:   false
    collection_actions: { filter: post, batch: post }
 

La anterior ruta genera las siguientes rutas:

route name method pattern
articles_filter POST /articles/filter.:sf_format
articles_batch POST /articles/batch.:sf_format
articles GET /articles.:sf_format
articles_new GET /articles/new.:sf_format
articles_create POST /articles.:sf_format
articles_edit GET /articles/:id/edit.:sf_format
articles_update PUT /articles/:id.:sf_format
articles_delete DELETE /articles/:id.:sf_format
articles_show GET /articles/:id.:sf_format

Sobre la base de esta definición de ruta, symfony es capaz de generar el correspondiente módulo de admin:

$ php symfony propel:generate-admin backend articles

La tarea propel:generate-admin crea un modulo article en la aplicacion backend y dentro del directorio modules.

Podemos hacer lo mismo para generar un módulo para el modelo DemoCategory:

categories:
  class:   sfPropelRouteCollection
  options:
    model:       DemoCategory
    module:      category
    with_show:   false
    collection_actions: { filter: post, batch: post }
 
$ php symfony propel:generate-admin backend categories

Mas de Fabrica

Incluso antes de la configuración de los módulos generados, Vamos a echar un vistazo a las características que están disponibles desde fabrica/caja (significa antes de cualquier personalización).

Default category list

La lista Category tiene varias características interesantes:

  • Cada categoría id es un enlace a la vista edit
  • El enlace ‘New’ va a la vista new para crear un nueva categoría
  • Cada categoría tiene un enlace ‘Edit’ y uno ‘Delete’
  • La posibilidad de suprimir categorías seleccionando de varias categorías a la vez

Default article filters

La captura de pantalla anterior es el filtro por defecto creado para el modelo Article. Observe que el nuevo generador de admin ha creado automáticamente filtros para las foreign-keys y las relaciones muchos a muchos.

Default article edit form

La vista edit también es muy interesante ya que todos los campos son editables, incluso las relaciones muchos a muchos entre los modelos Article, Tag y Category.

En esta vista usa la clase form por defecto generada por la clase Article, la validación también esta activada por defecto:

Default errors for the article edit form

Para una mejor usabilidad para el usuario final, el nuevo generador de admin también utiliza un montón de mensajes flash en las vistas list y edit:

Flash when saving a record
Flash when deleting a record
Flash when deleting records
Flash when an error occured

Más configurable

De fabrica, los módulos generados ya son muy potente, pero el poder real del generador de admin siempre ha sido su configurabilidad, la forma en que puedes cambiar la pantalla del admin sin escribir una sola línea de código. El nuevo generador de admin no es diferente. Veamos algunas opciones que puedes usar en el archivo de configuración generator.yml.

En primer lugar, el archivo generator.yml es más seguro que antes symfony ahora valida el formato del archivo. Se le ahorrará un montón de tiempo en el caso de un error o un mal sangrado. Para que esta validación funcione, hemos pasado toda la configuración bajo la entrada de config. Aquí está el archivo de configuración por defecto generator.yml para el modulo category:

generator:
  class: sfPropelGenerator
  param:
    model_class:           DemoCategory
    theme:                 admin
    non_verbose_templates: true
    with_show:             false
    singular:              ~
    plural:                ~
    route_prefix:          categories
    with_propel_route:     1
 
    config:
      actions: ~
      fields:  ~
      list:    ~
      filter:  ~
      form:    ~
      edit:    ~
      new:     ~
 

Debes haber notado el new. El nuevo generador implementa una de la características más solicitada, la posibilidad de tener una configuración diferente para la vista edit y la new. Sí, eso es ahora posible, y ambas opiniones heredan de una vista virtual form:

config:
  form:
    display:
      NONE:    [author_id, status, published_at, demo_category_article_list, demo_tag_article_list]
      Content: [title, content, is_on_homepage]
 
  new:
    title: New Article
 
  edit:
    title: Editing Article %%title%% (#%%id%%)
 

Por lo tanto, el generador de admin tiene ahora siete principales entradas:

  • actions: Para definir los atributos de todas las acciones, y, en particular, las credenciales
  • fields: Para definir los campos de configuración por defecto
  • list: Para definir la configuración de la vista lista
  • filter: El filtro tiene ahora su propia entrada para su configuración
  • form: Esta es una vista virtual ya que sólo se utiliza como la configuración por omisión para las configuraciones de new y edit
  • new: Para definir la configuración de vista new
  • edit: Para definir la configuración de vista edit

El archivo de configuración generator.yml implementa algunas reglas de herencia entre estas entradas:

  • new and edit heredan de form la cual hereda de fields
  • list heredan de fields
  • filter heredan de fields

Aquí hay un ejemplo para la definición de campos:

config:
  fields:
    title:     { label: Article Title }
    content:   { label: Body }
 

  list:
    fields:
      title:   { label: Title }
 
  form:
    fields:
      content: { label: Body of the article }
 

Si utilizas el generador de admin de symfony 1.0, te darás cuenta de que la clave name ha sido renombrada a label.

Todas las características del viejo archivo de configuración están aun soportadas (mira el Capítulo 14 para más detalles).

También, incluso si el archivo de configuración generator.yml es el método recomendado para personalizar los módulos, el nuevo generador de admin también puede ser totalmente personalizado con código PHP para una configuración más dinámica, (apps/backend/modules/article/lib/articleGeneratorConfiguration.class.php). Para tener una idea de lo que es posible, sólo echa un vistazo a la clase generada BaseArticleGeneratorConfiguration en el cache (cache/backend/dev/modules/autoArticle/lib/BaseArticleGeneratorConfiguration.class.php). Puedes incluso mezclar configuración via el archivo generator.yml y la clase articleGeneratorConfiguration.

Extensibilidad

El nuevo generador de admin realmente brilla cuando se trata de ampliar el comportamiento por defecto. Es mucho más flexible y extensible que antes.

Primero, hay más plantillas parciales que antes, y cada parcial es mucho más simple, lo que te permite afinar cada parte del sistema fácilmente:

_assets.php
_filters.php
_filters_field.php
_flashes.php
_form.php
_form_actions.php
_form_field.php
_form_fieldset.php
_form_footer.php
_form_header.php
_list.php
_list_actions.php
_list_batch_actions.php
_list_field_boolean.php
_list_footer.php
_list_header.php
_list_td_actions.php
_list_td_batch_actions.php
_list_td_stacked.php
_list_td_tabular.php
_list_th_stacked.php
_list_th_tabular.php
_pagination.php
editSuccess.php
indexSuccess.php
newSuccess.php

La plantilla para la acción se ha dividido en un montón de parciales para una mejor legibilidad y extensibilidad:

actionsConfiguration.php
batchAction.php
configuration.php
createAction.php
deleteAction.php
editAction.php
fieldsConfiguration.php
filterAction.php
filtersAction.php
filtersConfiguration.php
indexAction.php
newAction.php
paginationAction.php
paginationConfiguration.php
processFormAction.php
sortingAction.php
sortingConfiguration.php
updateAction.php

Si desea modificar el admin generador para crear su propio tema, o para empaquetar tus extensiones en un plugin, encontrarás que es mucho más fácil ahora:

  • No es necesario copiar todos los archivos del tema por defecto para crear una nuevo. Sólo tienes que copiar los ficheros que necesita para sobreescribir.
  • Varios eventos se han añadido para agregar comportamientos sin la necesidad de crear un nuevo tema. Esto permite que varios plug-ins puedan agregar o cambiar el comportamiento por defecto:

    • admin.pre_execute: Este evento es notificado antes de cualquier acción sea ejecutada. Este es un gran lugar para modificar la configuración o comprobar algo antes de que algo sea ejecutado.
    • admin.build_criteria: Este evento filtra el Criteria usado por la vista list.
    • admin.save_object: Este evento es notificado inmediatamente después de que un objeto sea guardado.
    • admin.delete_object: Este evento es notificado justo antes de un objeto se eliminado.
  • El módulo generadod de acciones ha sido refactoreado para dar métodos más útiles:

    • getFilters()
    • setFilters()
    • getPager()
    • getPage()
    • setPage()
    • buildCriteria()
    • addSortCriteria()
    • getSort()
    • setSort()

La mejor manera de aprender cómo se puede empujar los límites del nuevo generador de admin es examinar los módulos generados en la memoria caché. Encontrarás una gran cantidad de la bondades (¡Echa un vistazo a la clase helper por ejemplo).

Internacionalización

El nuevo generador de admin soporta internacionalización de formularios de forma nativa (de fabrica), gracias a la utilización del nuevo framework de formularios.

La interface del generador de adminis también esta traducida en varios idiomas. En menos de 24 horas, ya tenemos traducciones para 21 idiomas:

  • English
  • Bulgarian
  • German
  • Danish
  • Spanish
  • Spanish (Argentina)
  • French
  • Italian
  • Japanese
  • Dutch
  • Novergian
  • Polish
  • Brasilian
  • Russian
  • Chinese simplified
  • Slovak
  • Romanian
  • Indonesian
  • Turkish
  • Finnish
  • Portuguese

Si deseas contribuir con una traducción de tu idioma, el proceso es muy fácil y te llevará unos 10 minutos:

  • Descarga el archivo en Frances y sustituye todas las cadenas del francés con tus traducciones (el archivo contiene también la cadenas de Inglés)
  • Cambie el nombre del archivo con tu código ISO de idioma
  • Enviar el archivo traducido a mi dirección de correo electrónico

Aprovecha el nuevo framework de formularios

Las vistas filters, new, y edit son generadas por el nuevo framework de formularios, lo que significa que puedes aprovechar todas las características del nuevo framework de formularios para modificar tus módulos de admin generados.

Esto fue una muy rápida descripción general y técnica del nuevo generador de admin. Si deseas aprender más, puedes leer el capítulo generador del libro de symfony.

La presente, es una traducción al castellano realizada por Roberto G. Puentes Diaz,
sobre el artículo new-in-symfony-1-2-the-admin-generator de Fabien Potencier.

Publicado en General | 1 comentario

Eclipse: Escribiendo Código rapido

Gracias a nuestro aclamado Eclipse PDT, el desarrollo de PHP, nunca fue tan facil.

Si bien, gracias a symfony y al autocompletado, se hace todo muy intuitivo. Con Eclipse podemos hacernos nuestros propios atajos de codigo.

Menu  > Window > Preferences > PHP  > Templates

Nos ofrecera la posibilidad de editar los existentes o de crear uno nuevo. Le damos a NEW y debemos tener algo asi:

Captura de como crear un template de código PHP en Eclipse PDT

Captura de como crear un template de código PHP en Eclipse PDT

Publicado en General, Software Libre, Symfony | Deja un comentario

Generando el Modelo, a mi manera

(El presente es un ensayo de como ire descubriendo como hacer cada cosa, por lo que tendría modificaciones sucesivas, sin embargo la idea es que lo que leas sirva y funcione)

Es quizás muy petulante el título, pero esa es la idea. Osea Generar el Modelo. :)

Como seguro ya se darían cuenta, con anteriores artículos y traducciones, estoy estudiando symfony 1.2 para mi proyecto.

Una de las cosas que hice primero fue hacer un ambiente para mis pruebas, con el fin de tener un ámbito para jugar a lo que se me ocurra. Osea que mi schema tiene muchas cosas, pero como es de pruebas … que va!

Una de las cosas que siempre me gusto es lo del método mágico __toString() de las clases del modelo generado. El poder luego redefinirlo en la clase personalizada, solicitando que devuelva un getXXX() y poder ver el dato de la base en los ABM / CRUD del administrador en lugar de los PrimaryKey, es realmente mas lindo.

Pero tener que redefinir en cada clase, puede ser molesto …
Vamos, soy de los que se pierden haciendos “xxxxxx_id” por todos lados en el modelo … :) Por lo que tengo que redefinir muchos __toString() .

Entonces porque no poder en el schema, definir un atributo tostring a true o especificar el nombre del campo a utilizar por el método magico, para que el generador/builder/constructor del modelo lo haga por mi ya desde la BaseClase.php ?

Mi instalacion de Symfony 1.2 esta en /Symfony1.2.
Digamos que en otro equipo distinto del que estamos trabajando, hice una descarga por SVN del la versión 1.2, y luego la copie a este DIR.
Imagino que esto no tiene ningun tipo de incidencia.

Veamos un poco el schema:

propel:
   category:
    _attributes:    { phpName: Category, phpToString: Name }
    name:        varchar(255)

La idea central, es definir un atributo phpToString que nos permita definir un texto, en este caso Name, y que en este caso tambien hace referencia al campo name declarado en la linea debajo.
La finalidad es lograr que se genere un código / método toString() para esta clase, como el siguiente :

    /**
     * Magic Method __toString will return the value of some field
     * if you setup the attributes of your schema for this object/table
     */
    public function __toString()
    {
        return $this->getName();

    }

Note que por esta razón, puse Name, con la N en mayúsculas. Ya vere despues como hacer la transformación camelcase…
El generador al $this->get le agregará a continuación lo que hallamos definido

Entiendo que iniciamos el script por generar de cada BaseClase.php, desde SfObjectBuilder. A continuación un extracto de como las clases se van heredando, según su definición:

class SfObjectBuilder extends PHP5ObjectBuilder {

class PHP5ObjectBuilder extends ObjectBuilder {

abstract class ObjectBuilder extends OMBuilder {

abstract class OMBuilder extends DataModelBuilder {

Hagamos un salto al objeto OMBuilder (/Symfony1.2/lib/plugins/sfPropelPlugin/lib/vendor/propel-generator/classes/propel/engine/builder/om/OMBuilder.php)

	 /**
	 * Builds the PHP source for current class and returns it as a string.
	 *
	 * This is the main entry point and defines a basic structure that classes should follow.
	 * In most cases this method will not need to be overridden by subclasses.  This method
	 * does assume that the output language is PHP code, so it will need to be overridden if
	 * this is not the case.
	 *
	 * @return     string The resulting PHP sourcecode.
	 */
	public function build()
	{
		$this->validateModel();

		$script = "<" . "?php\n"; // intentional concatenation
		$this->addIncludes($script);
		$this->addClassOpen($script);
		$this->addClassBody($script);
		$this->addClassClose($script);
		return $script;
	}

Estos metodo tan interesantes los podemos encontrar implementado en (/Symfony1.2\lib\plugins\sfPropelPlugin\lib\vendor\propel-generator\classes\propel\engine\builder\om\php5\PHP5ObjectBuilder.php) el objeto PHP5ObjectBuilder (use la flechita que esta a la derecha de la barra siguiente para ver los metodos)

	/**
	 * Adds the include() statements for files that this class depends on or utilizes.
	 * @param      string &$script The script will be modified in this method.
	 */
	protected function addIncludes(&$script)
	{
	} // addIncludes()

	/**
	 * Adds class phpdoc comment and openning of class.
	 * @param      string &$script The script will be modified in this method.
	 */
	protected function addClassOpen(&$script)
	{

		$table = $this->getTable();
		$tableName = $table->getName();
		$tableDesc = $table->getDescription();
		$interface = $this->getInterface();

		$script .= "
/**
 * Base class that represents a row from the '$tableName' table.
 *
 * $tableDesc
 *";
		if ($this->getBuildProperty('addTimeStamp')) {
			$now = strftime('%c');
			$script .= "
 * This class was autogenerated by Propel " . $this->getBuildProperty('version') . " on:
 *
 * $now
 *";
		}
		$script .= "
 * @package    ".$this->getPackage()."
 */
abstract class ".$this->getClassname()." extends ".ClassTools::classname($this->getBaseClass())." ";

		$interface = ClassTools::getInterface($table);
		if ($interface) {
			$script .= " implements " . ClassTools::classname($interface);
		}

		$script .= " {

";
	}

	/**
	 * Specifies the methods that are added as part of the basic OM class.
	 * This can be overridden by subclasses that wish to add more methods.
	 * @see        ObjectBuilder::addClassBody()
	 */
	protected function addClassBody(&$script)
	{
		$script = "\n" . $script;
		$table = $this->getTable();
		if (!$table->isAlias()) {
			$this->addConstants($script);
			$this->addAttributes($script);
		}

		$this->addConstructor($script);
		$this->addApplyDefaultValues($script);

		// NUEVO CODIGO // NEW CODE
		if ($this->getPhpToString() != false) {
			$this->addToString($script);
		}

		$this->addColumnAccessorMethods($script);
		$this->addColumnMutatorMethods($script);

		$this->addHasOnlyDefaultValues($script);

		$this->addHydrate($script);
		$this->addEnsureConsistency($script);

		$this->addManipulationMethods($script);
		$this->addValidationMethods($script);

		if ($this->isAddGenericAccessors()) {
			$this->addGetByName($script);
			$this->addGetByPosition($script);
			$this->addToArray($script);
		}

		if ($this->isAddGenericMutators()) {
			$this->addSetByName($script);
			$this->addSetByPosition($script);
			$this->addFromArray($script);
		}

		$this->addBuildCriteria($script);
		$this->addBuildPkeyCriteria($script);
		$this->addGetPrimaryKey($script);
		$this->addSetPrimaryKey($script);

		$this->addCopy($script);

		if (!$table->isAlias()) {
			$this->addGetPeer($script);
		}

		$this->addFKMethods($script);
		$this->addRefFKMethods($script);
		$this->addClearAllReferences($script);
	}

	/**
	 * Closes class.
	 * @param      string &$script The script will be modified in this method.
	 */
	protected function addClassClose(&$script)
	{
		$script .= "
} // " . $this->getClassname() . "
";
	}

Note la nueva porción de código

		// NUEVO CODIGO // NEW CODE
		if ($this->getPhpToString() != false) {
			$this->addToString($script);
		}

Quien se encarga de analizar el schema sea YML o XML, es la clase sfPropelDatabaseSchema (E:\wamp\apps\symfony\1.2\lib\plugins\sfPropelPlugin\lib\addon\sfPropelDatabaseSchema.class.php)

La Clase Abstracta XMLElement (/Symfony1.2/lib/plugins/sfPropelPlugin/lib/vendor/propel-generator/classes/propel/engine/database/model/XMLElement.php) representa a los elementos de un archivo XML. Es el método loadFromXML() quien toma esos atributos

	/**
	 * This is the entry point method for loading data from XML.
	 * It calls a setupObject() method that must be implemented by the child class.
	 * @param      array $attributes The attributes for the XML tag.
	 */
	public function loadFromXML($attributes)
	{
		$this->attributes = array_change_key_case($attributes, CASE_LOWER);
		$this->setupObject();
	}

La misma es heredada por otras como Table y Database.

A la clase Table, debemos agregarle estas modificaciones. Es quien hereda de XMLElement e implementa IDMethod.
(/Symfony1.2/lib/plugins/sfPropelPlugin/lib/vendor/propel-generator/classes/propel/engine/database/model/Table.php
)

Un atributo $phpToString

    /**
     * The field name for the magic method __toString().
     *
     * @var        string
     */
    private $phpToString;

Cargamos los valores al objeto, entre ellos $this->phpToString

	/**
	 * Sets up the Rule object based on the attributes that were passed to loadFromXML().
	 * @see        parent::loadFromXML()
	 */
	public function setupObject()
	{
		$this->name = $this->getAttribute("name");
		$this->phpName = $this->getAttribute("phpName");
		$this->idMethod = $this->getAttribute("idMethod", $this->getDatabase()->getDefaultIdMethod());
		$this->allowPkInsert = $this->booleanValue($this->getAttribute("allowPkInsert"));

		// retrieves the method for converting from specified name to a PHP name.
		$this->phpNamingMethod = $this->getAttribute("phpNamingMethod", $this->getDatabase()->getDefaultPhpNamingMethod());

		$this->skipSql = $this->booleanValue($this->getAttribute("skipSql"));
		$this->readOnly = $this->booleanValue($this->getAttribute("readOnly"));

		$this->phpToString = $this->getAttribute("phpToString");
		$this->pkg = $this->getAttribute("package");
		$this->abstractValue = $this->booleanValue($this->getAttribute("abstract"));
		$this->baseClass = $this->getAttribute("baseClass");
		$this->basePeer = $this->getAttribute("basePeer");
		$this->alias = $this->getAttribute("alias");

		$this->heavyIndexing = ( $this->booleanValue($this->getAttribute("heavyIndexing"))
		|| ("false" !== $this->getAttribute("heavyIndexing")
		&& $this->getDatabase()->isHeavyIndexing() ) );
		$this->description = $this->getAttribute("description");
		$this->enterface = $this->getAttribute("interface"); // sic ('interface' is reserved word)
		$this->treeMode = $this->getAttribute("treeMode");

		$this->reloadOnInsert = $this->booleanValue($this->getAttribute("reloadOnInsert"));
		$this->reloadOnUpdate = $this->booleanValue($this->getAttribute("reloadOnUpdate"));
	}

Los Getter y Setter

    /**
     * Get the value of phpToString.
     * @return     value of phpToString.
     */
    public function getPhpToString()
    {
        return $this->phpToString;
    }

    /**
     * Set the value of phpToString.
     * @param      v  Value to assign to phpToString.
     */
    public function setPhpToString($v)
    {
        $this->phpToString = $v;
    }

Y tambien debemos adaptar la clase Database
(/Symfony1.2/lib/plugins/sfPropelPlugin/lib/vendor/propel-generator/classes/propel/engine/database/model/Database.php)

Un atributo $phpToString

	private $phpToString;

Cargamos los valores al objeto, entre ellos $this->phpToString

	/**
	 * Sets up the Database object based on the attributes that were passed to loadFromXML().
	 * @see        parent::loadFromXML()
	 */
	protected function setupObject()
	{
		$this->name = $this->getAttribute("name");
		$this->phpToString = $this->getAttribute("phpToString");
		$this->pkg = $this->getAttribute("package");
		$this->baseClass = $this->getAttribute("baseClass");
		$this->basePeer = $this->getAttribute("basePeer");
		$this->defaultIdMethod = $this->getAttribute("defaultIdMethod", IDMethod::NATIVE);
		$this->defaultPhpNamingMethod = $this->getAttribute("defaultPhpNamingMethod", NameGenerator::CONV_METHOD_UNDERSCORE);
		$this->defaultTranslateMethod = $this->getAttribute("defaultTranslateMethod", Validator::TRANSLATE_NONE);
		$this->heavyIndexing = $this->booleanValue($this->getAttribute("heavyIndexing"));
	}

Los Getter y Setter

    /**
     * Get the value of phpToString.
     * @return     value of phpToString.
     */
    public function getPhpToString()
    {
        return $this->phpToString;
    }

    /**
     * Set the value of phpToString.
     * @param      v  Value to assign to phpToString.
     */
    public function setPhpToString($v)
    {
        $this->phpToString = $v;
    }

Ahora el XML

	/**
	 * @see        XMLElement::appendXml(DOMNode)
	 */
	public function appendXml(DOMNode $node)
	{
		$doc = ($node instanceof DOMDocument) ? $node : $node->ownerDocument;

		$dbNode = $node->appendChild($doc->createElement('database'));

		$dbNode->setAttribute('name', $this->name);

        if ($this->phpToString) {
            $dbNode->setAttribute('phpToString', $this->phpToString);
        }

		if ($this->pkg) {
			$dbNode->setAttribute('package', $this->pkg);
		}

		if ($this->defaultIdMethod) {
			$dbNode->setAttribute('defaultIdMethod', $this->defaultIdMethod);
		}

		if ($this->baseClass) {
			$dbNode->setAttribute('baseClass', $this->baseClass);
		}

		if ($this->basePeer) {
			$dbNode->setAttribute('basePeer', $this->basePeer);
		}

		if ($this->defaultPhpNamingMethod) {
			$dbNode->setAttribute('defaultPhpNamingMethod', $this->defaultPhpNamingMethod);
		}

		if ($this->defaultTranslateMethod) {
			$dbNode->setAttribute('defaultTranslateMethod', $this->defaultTranslateMethod);
		}

		/*

		FIXME - Before we can add support for domains in the schema, we need
		to have a method of the Column that indicates whether the column was mapped
		to a SPECIFIC domain (since Column->getDomain() will always return a Domain object)

		foreach ($this->domainMap as $domain) {
		$domain->appendXml($dbNode);
		}
		*/
		foreach ($this->vendorInfos as $vi) {
			$vi->appendXml($dbNode);
		}

		foreach ($this->tableList as $table) {
			$table->appendXml($dbNode);
		}

	}

Con estas dos clases modificadas, estamos en condiciones de usar estos cambios para la clase OMBuilder que hereda de DataModelBuilder. Pero esta ultima clase no sera necesario modificarla. (/Symfony1.2/lib/plugins/sfPropelPlugin/lib/vendor/propel-generator/classes/propel/engine/builder/om/OMBuilder.php). Solo hay que :

    /**
     * Gets the field name for the magic method __toString.
     * @return     string
     */
    public function getPhpToString()
    {
        $phpToString = ($this->getTable()->getPhpToString() ? $this->getTable()->getPhpToString() : $this->getDatabase()->getPhpToString());
        if (!$phpToString) {
            $phpToString = false;
        }
        return $phpToString;
    }

Como vimos la clase hija de la anterior OMBuilder, es PHP5ObjectBuilder.
(/Symfony1.2/lib/plugins/sfPropelPlugin/lib/vendor/propel-generator/classes/propel/engine/builder/om/php5/PHP5ObjectBuilder.php)

Publicado en Software Libre, Symfony | 2 comentarios

Prueba tus Aplicaciones

Prueba tus Aplicaciones, es otro articulo de Fabien Potencier,creador del framework Symfony.

Esta vez, se analiza las nuevas clases del framework para el testing.
De mas esta decir que Fabien esta muy entusiasmado con estos tópicos :)
Las clases son fáciles de usar.

Prueba tus Aplicaciones

Publicado en General, Software Libre, Symfony | Deja un comentario

Mas sabor para tus formularios con algunos lindos widgets y validadores

Mas sabor para tus formularios con algunos lindos widgets y validadores, es otro articulo de Fabien Potencier,creador del framework Symfony.

En el mismo nos sigue mostrando varios trucos de sfFormExtraPlugin y el uso de ReCaptcha.
Los métodos son muy sencillos e intuitivos.

Mas sabor para tus formularios con algunos lindos widgets y validadores

Publicado en General, Software Libre, Symfony | Deja un comentario