php php5 symfony framework ====== Symfony ====== Marco de trabajo para desarrollar en php. Actualmente la versión 1.2. Se trata de una colección de archivos php que una vez descomprimidos, permiten automatizar las tareas más frecuentes en el desarrollo de cualquier aplicación web. Para que se entienda vamos a ver con un ejemplo, que seguiremos a lo largo de este manual, las posibilidades de instalar symfony. Existen dos posibilidades: * Instalación compartida de symfony | /tmp/symfony | Directorio de instalación de symfony | | /tmp/proyectos_symfony/proyecto_1 | Directorio donde residirá el proyecto 1 | | /tmp/proyectos_symfony/proyecto_2 | Directorio donde residirá el proyecto 2 | Luego habrá que enlazar /tmp/symfony para que sea accesible para los dos proyectos * Instalación individual de symfony | /tmp/proyectos_symfony/proyecto_1 | Directorio donde residirá el proyecto 1 | | /tmp/proyectos_symfony/proyecto_1/symfony_1_2_8 | Directorio donde residirá symfony solo para el proyecto 1 | | /tmp/proyectos_symfony/proyecto_2 | Directorio donde residirá el proyecto 2 | | /tmp/proyectos_symfony/proyecto_2/symfony_1_2_8 | Directorio donde residirá symfony solo para el proyecto 2 | Me decanto por esta opción ===== Instalación ===== 1. Descargar las fuentes http://www.symfony-project.org/installation/1_2 wget -c --tries=0 http://www.symfony-project.org/get/symfony-1.2.8.tgz 2. Descomprimir: tar xvfz symfony-1.2.8.tgz 3. Descargar un guión para comprobar dependencias: wget -c --tries=0 http://sf-to.org/1.2/check.php 4. Ejecutar el guión desde una web, pues el php.ini de php-cli (cuando ejecutamos php desde linea de comandos) es distinto de cuando ejecutamos php como módulo de php): http://localhost/mi_ruta/check_configuration.php En mi caso el resultado fue: ******************************** * * * symfony requirements check * * * ******************************** php.ini used by PHP: /etc/php5/cli/php.ini ** WARNING ** * The PHP CLI can use a different php.ini file * than the one used with your web server. * If this is the case, please launch this * utility from your web server. ** WARNING ** ** Mandatory requirements ** OK PHP version is at least 5.2.4 ** Optional checks ** OK PDO is installed [[WARNING]] PDO has some drivers installed: : FAILED *** Install PDO drivers (mandatory for Propel and Doctrine) *** OK PHP-XML module is installed [[WARNING]] XSL module is installed: FAILED *** Install the XSL module (recommended for Propel) *** OK The token_get_all() function is available OK The mb_strlen() function is available OK The iconv() function is available OK The utf8_decode() is available [[WARNING]] A PHP accelerator is installed: FAILED *** Install a PHP accelerator like APC (highly recommended) *** [[WARNING]] php.ini has short_open_tag set to off: FAILED *** Set it to off in php.ini *** [[WARNING]] php.ini has magic_quotes_gpc set to off: FAILED *** Set it to off in php.ini *** OK php.ini has register_globals set to off OK php.ini has session.auto_start set to off OK PHP version is not 5.2.9 Por partes: **PDO** Si hago un: php -m Obtengo: ... pcre PDO posix ... Por lo que entiendo que SI está habilitado **XLS** aptitude install php5-xsl **Acelerador** aptitude install php-apc **short_open_tag** Editar el fichero de configuración de php: nano /etc/php5/apache2/php.ini Y dejar la linea tal que así: short_open_tag = Off **magic_quotes_gpc** Editar el fichero de configuración de php: nano /etc/php5/apache2/php.ini Y dejar la linea tal que así: magic_quotes_gpc = Off Tras los cambios en php.ini: apache2ctl restart Como yo me decanto por la instalación individual de symfony, lo copiamos a su ubicación: cp -Rv /ruta/fuente/symfony /tmp/proyectos_symfony/proyecto_1/symfony_1_2_8 ===== Crear proyecto ===== Como me he decantado por la instalación individual de symfony, tenemos la siguiente estructura: | /tmp/proyectos_symfony/proyecto_1 | Directorio donde residirá el proyecto 1 | | /tmp/proyectos_symfony/proyecto_1/symfony_1_2_8 | Directorio donde residirá symfony solo para el proyecto 1 | De esa forma, tanto 'proyecto_1' como 'proyecto_2' comparten la version 1.2 de symfony: mkdir /tmp/proyectos_symfony/proyecto_1 /tmp/proyectos_symfony/proyecto_2 cp -Rv /ruta/fuente/symfony/* /tmp/symfony/symfony_1_2_8/ Y por último creamos 'proyecto_1': cd /tmp/proyectos_symfony/proyecto_1 php symfony_1_2_8/data/bin/symfony generate:project proyecto_1 Ha creado la siguiente estructura dentro de '/tmp/proyectos_symfony/proyecto_1': drwxr-xr-x 2 root root 4096 sep 11 01:47 apps drwxrwxrwx 2 root root 4096 sep 11 01:47 cache drwxr-xr-x 2 root root 4096 sep 11 01:47 config drwxr-xr-x 3 root root 4096 sep 11 01:47 data drwxr-xr-x 2 root root 4096 sep 11 01:47 doc drwxr-xr-x 2 root root 4096 sep 11 01:47 lib drwxrwxrwx 2 root root 4096 sep 11 01:47 log drwxr-xr-x 2 root root 4096 sep 11 01:47 plugins -rwxrwxrwx 1 root root 446 sep 11 01:47 symfony drwxr-xr-x 7 root root 4096 sep 11 01:45 symfony_1_2_8 drwxr-xr-x 5 root root 4096 sep 11 01:47 test drwxr-xr-x 6 root root 4096 sep 11 01:47 web Para conocer donde está el 'core' de symfony de ese proyecto, una vez en el directorio del proyecto: php symfony -V symfony version 1.2.8 (/tmp/proyectos_symfony/proyecto_1/symfony_1_2_8/lib) ===== Crear frontend ===== Nos aseguramos estar dentro de '/tmp/proyectos_symfony/proyecto_1': cd /tmp/proyectos_symfony/proyecto_1 php symfony generate:app --escaping-strategy=on --csrf-secret=UniqueSecret frontend Esto ha creado la siguiente estructura, dentro de '/tmp/proyectos_symfony/proyecto_1/apps/frontend/': drwxr-xr-x 2 root root 4096 sep 14 10:37 config drwxr-xr-x 2 root root 4096 sep 14 10:37 i18n drwxr-xr-x 2 root root 4096 sep 14 10:37 lib drwxr-xr-x 2 root root 4096 sep 14 10:37 modules drwxr-xr-x 2 root root 4096 sep 14 10:37 templates ===== Crear módulo ===== Nos aseguramos estar dentro de '/tmp/proyectos_symfony/proyecto_1': cd /tmp/proyectos_symfony/proyecto_1 php symfony generate:module frontend modulo_1 Esto ha creado la siguiente estructura, dentro de '/tmp/proyectos_symfony/proyecto_1/apps/frontend/modules/modulo_1': drwxr-xr-x 2 javi javi 4096 oct 6 18:31 actions drwxr-xr-x 2 javi javi 4096 oct 6 18:31 templates ^ Archivo ^ Url ^ | /tmp/proyectos_symfony/proyecto_1/apps/frontend/modules/modulo_1/actions | http://localhost/proyecto_1/web/frontend_dev.php/modulo_1/index | ===== Permisos ===== cd /tmp/proyectos_symfony/proyecto_1 chmod 777 cache/ log/ Si se usa subversion conviene eludir estos directorios a la hora de exportar: [[informatica:linux:subversion#ignorar_cambios_en_directorios|Igonrar determinados directorios]] ===== Ruta ===== Si en lugar de dejarse el núcleo de symfony en un directorio 'estático' se hubiese incluido dentro del proyecto, para mover el proyecto a cualquier otro directorio: 1. Editar el fichero: nano /tmp/proyectos_symfony/proyecto_1/config/ProjectConfiguration.class.php 2. Dejar el fichero así (siguiendo el ejemplo): require_once dirname(__FILE__).'/../symfony_1_2_8/lib/autoload/sfCoreAutoload.class.php'; sfCoreAutoload::register(); class ProjectConfiguration extends sfProjectConfiguration { public function setup() { // for compatibility / remove and enable only the plugins you want $this->enableAllPluginsExcept(array('sfDoctrinePlugin', 'sfCompat10Plugin')); } } 3. Crear un enlace simbólico: cd /tmp/proyectos_symfony/proyecto_1/web ln -s ../symfony_1_2_8/data/web/sf/ . De esta forma hemos optado por la instalación individual de symfony: moviendo el directorio '/tmp/proyectos_symfony/proyecto_1' tenemos nuestro proyecto entero, al coste de que pesa, vacío, 25 Mb ===== Configurar la bd ===== En este ejemplo vamos a usar mysql. Desde dentro del proyecto: ^ ORM ^ SGBD ^ Comando ^ | Propel | MySQL | php symfony configure:database "mysql:host=localhost;dbname=blog" root mYsEcret | | Propel | Sqlite | php symfony configure:database "sqlite://%SF_DATA_DIR%/sqlite/bd_sqlite.bd" | | Doctrine | MySQL | php symfony configure:database --name=doctrine --class=sfDoctrineDatabase "mysql:host=localhost;dbname=jobeet" root mYsEcret | | Doctrine | Sqlite | php symfony configure:database --name=doctrine --class=sfDoctrineDatabase "sqlite:///%SF_DATA_DIR%/sqlite/bd_sqlite.bd" | ===== Configurar el servidor de páginas web ===== Ejemplo de configuración para este ejemplo en el caso de que optemos por una instalación compartida de symfony, que no es el caso: ServerName mi_pagina.mine.nu DocumentRoot /tmp/proyectos_symfony/proyecto_1/web AllowOverride All Allow from All Alias /sf /tmp/symfony/data/web/sf AllowOverride All Allow from All Ahora la web (ojo, con estilos e imagen de fondo) debería verse desde: http://mi_pagina.mine.nu Teóricamente también deberíamos ver el frontend en desarrollo: http://mi_pagina.mine.nu/frontend_dev.php Pero a mí me sale el siguiente mensaje: You are not allowed to access this file. Check frontend_dev.php for more information. El motivo es que por defecto está configurado para que solo se pueda acceder a ese entorno desde la misma máquina (127.0.0.1) que aloja symfony. Para hacer accesible ese entorno a cualquiera: 1. Editar el fichero: nano /tmp/proyectos_symfony/proyecto_1/web/frontend_dev.php 2. Y dejarlo tal que así: dispatch(); ===== Diagramas ===== **Flujo de trabajo de symfony** {{informatica:linux:php:01.png|}} **Organización de código** {{informatica:linux:php:02.png|}} **Directorios** apps/ frontend/ backend/ cache/ config/ data/ sql/ doc/ lib/ model/ log/ plugins/ test/ bootstrap/ unit/ functional/ web/ css/ images/ js/ uploads/ **Directorio 'Applications'** apps/ [application name]/ modules/ [module name]/ actions/ actions.class.php config/ lib/ templates/ indexSuccess.php **Capa vista** {{informatica:linux:php:03.png|}} ===== Conceptos ===== | Parameter holder | $request->getParameterHolder()->set('foo', 'bar'); echo $request->getParameterHolder()->get('foo'); // The 'foobar' parameter is not defined, so the getter returns an empty value echo $request->getParameter('foobar'); => null // A default value can be used by putting the getter in a condition if ($request->hasParameter('foobar')) { echo $request->getParameter('foobar'); } else { echo 'default'; } => default // But it is much faster to use the second getter argument for that echo $request->getParameter('foobar', 'default'); => default // Uso de namespaces $user->setAttribute('foo', 'bar1'); $user->setAttribute('foo', 'bar2', 'my/name/space'); echo $user->getAttribute('foo'); => 'bar1' echo $user->getAttribute('foo', null, 'my/name/space'); => 'bar2' // Añadir Parameter Holder a una clase class MyClass { protected $parameterHolder = null; public function initialize($parameters = array()) { $this->parameterHolder = new sfParameterHolder(); $this->parameterHolder->add($parameters); } public function getParameterHolder() { return $this->parameterHolder; } } | | Constantes | // Instead of PHP constants, define('FOO', 'bar'); echo FOO; // symfony uses the sfConfig object sfConfig::set('foo', 'bar'); echo sfConfig::get('foo'); | | Autocarga de clases | $myObject = new MyClass(); | | Helper | Listing 4-11 - The link_to(), and url_for() Helpers

Hello, world!

= 18): ?>

Or should I say good evening? It is already .

| | Partial | {{http://www.symfony-project.org/images/book/1_2/F0702.png}} | | Componente | {{http://www.symfony-project.org/images/book/1_2/F0703.png}} | | Slot | {{http://www.symfony-project.org/images/book/1_2/F0704.png}} | | Component slot | http://www.symfony-project.org/book/1_2/07-Inside-the-View-Layer | ===== Comandos ===== **NOTA** supongo que antes de lanzar cada comando, es conveniente limpiar la caché (teóricamente en entornos 'dev'... la caché se genera cada vez) * Limpiar la caché php symfony cc * Configurar la conexión a la base de datos con PROPEL** # Ejemplo MySQL php symfony configure:database "mysql:host=localhost;dbname=blog" root mYsEcret # Ejemplo Sqlite php symfony configure:database "sqlite://%SF_DATA_DIR%/sqlite/bd_sqlite.bd" O editar el archivo: /mi_proyecto/config/databases.yml * Crear el modelo de objetos con PROPEL php symfony propel:build-model Luego hay que limpiar la caché: php symfony cache:clear * Crear el diagrama entidad-relación a partir del modelo .yml con PROPEL php symfony propel:build-sql Genera el siguiente archivo: /mi_proyecto/data/sql/lib.model.sql * Habilitar los activos (assets) asociados a un plugin que acaba de ser habilitado php symfony plugin:publish-assets * Crear la bd a partir del archivo '/mi_proyecto/data/sql/schema.sql' con PROPEL php symfony propel:insert-sql --no-confirmation **NOTA** Todo lo marcado con 'con PROPEL' se puede hacer con doctrine sustituyendo en el comando 'propel' por 'doctrine' y viceversa * Cargar los datos a partir de '/mi_proyecto/data/fixtures/'fixtures con DOCTRINE php symfony doctrine:data-load **TODOS los comandos anteriores para PROPEL** php symfony doctrine:build-all-reload --no-confirmation php symfony cc * Listar rutas de una aplicación php symfony app:routes frontend * Mostrar el detalle de una ruta php symfony app:routes frontend job_edit ===== Errores ===== **Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 71 bytes) in /mnt/disco_1/datos/www/privado/inmobiliaria2/symfony_1_2_8/lib/plugins/sfPropelPlugin/lib/vendor/phing/util/StringHelper.php on line 136 ** Al intentar crear el modelo de datos: php symfony propel:build-all Aparece el siguiente error: Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 71 bytes) in /mnt/disco_1/datos/www/privado/inmobiliaria2/symfony_1_2_8/lib/plugins/sfPropelPlugin/lib/vendor/phing/util/StringHelper.php on line 136 **SOLUCION** 1) (Todo como root) Incrementar el máximo de memoria RAM que puede consumir un guión php (es decir, ejecutado desde su CLI): nano /etc/php5/cli/php.ini Y dejar el siguiente valor, por ejemplo, así: memory_limit = 40M ; Maximum amount of memory a script may consume (32MB) 2) Grabar y salir **SQLSTATE[HY000]: General error: 26 file is encrypted or is not a database** El problema es que la bd sqlite se creó con sqlite 2.x. Para comprobar que es así: cat /mi_proyecto/data/mi_bd_sqlite.db La primera linea tiene que ser parecida a: This file contains an SQLite 2.1 database... **Solución** 1. (Como root) Instalar sqlite3: aptitude update && aptitude install sqlite3 2. Volver a crear la bd con el comando: sqlite3 /mi_proyecto/data/mi_bd_sqlite.db 3. (No sé si es necesario si la ubicación y nombre de la bd es exacta) Volver a crear el modelo... (desde la raíz del proyecto): php symfony cache:clear php symfony configure:database "sqlite://%SF_DATA_DIR%/mi_bd_sqlite.db" php symfony propel:build-model **Fatal error: Class 'sfProjectConfiguration' not found in /mnt/disco_1/datos/proyectos_symfony/jobeet/config/ProjectConfiguration.class.php on line 10** En el archivo '/mi_proyecto/config/ProjectConfiguration.class.php': * No se ha modificado la ruta para que incluya el archivo correctamente * Se ha comentado por error la linea 'sfCoreAutoload::register();' **Fatal error: Class 'sfPropelDatabase' not found in /mnt/disco_1/datos/proyectos_symfony/jobeet/cache/frontend/dev/config/config_databases.yml.php on line 6** Se está intentando crear las sentencias sql con doctrine: php symfony doctrine:build-sql Pero en el archivo de configuración: /mi_proyecto/apps/frontend/config/databases.yml Todavía quedan residuos de propel que hay que eliminar: dev: propel: param: classname: DebugPDO test: propel: param: classname: DebugPDO all: propel: class: sfPropelDatabase param: classname: PropelPDO dsn: 'mysql:dbname=jobeet;host=localhost' username: root password: null encoding: utf8 persistent: true pooling: true doctrine: class: sfDoctrineDatabase param: dsn: 'sqlite:///%SF_DATA_DIR%/sqlite/bd_sqlite.bd' username: root password: null Debería quedar tal que así: all: doctrine: class: sfDoctrineDatabase param: dsn: 'sqlite:///%SF_DATA_DIR%/sqlite/bd_sqlite.bd' username: root password: null