Mostrando entradas con la etiqueta php. Mostrar todas las entradas
Mostrando entradas con la etiqueta php. Mostrar todas las entradas

domingo, 5 de octubre de 2014

Codeigniter Multilenguaje

Codeigniter soporta por sí mismo el multilenguaje, sin embargo tiene un problema en cuanto a los motores de búsqueda, y es que sólo indexarán vuestra página en el lenguaje por defecto. 

Para que indexen en cada uno de los lenguajes que tengamos disponibles, deberíamos crear la típica estructura url amigable que estáis hartos de ver navegando por ahí:

Ej:

http://mytube.honor.es/es/login    ==>  'Español'
http://mytube.honor.es/en/login   ==>  'Inglés'
http://mytube.honor.es/ca/login   ==>  'Catalán'


Internationalization (i18n) for CodeIgniter 2.x

Esta utilidad que reside aquí, permite hacer exactamente esto. Podéis seguir las instrucciones en inglés o bien descargaros los archivos ya creados aquí y seguir leyendo en castellano cómo configurarlo. 

Los programas

Si no lo habéis hecho en el párrafo anterior, nos descargamos los programas de aquí.

Hay tres archivos:

MY_Lang.php
MY_Config.php
MY_language_helper.php   (Este programa falta en muchos paquetes que os podáis descargar por ahí)

Copiaremos los dos primeros en:

./application/core

y el helper en:

./application/helpers


No obstante, deberemos realizar una pequeña modificación en el fichero MY_Lang.php que consistirá en indicar en qué carpeta alojaremos cada lengua.


Siguiendo el ejemplo de las URL amigables al principio del artículo la modificación a realizar justo al principio del archivo, sería:

// languages

var $languages = array(

'en' => 'en',
'ca' => 'ca',
'es' => 'es'
);


Es importante reseñar que las abreviaciones de las lenguas no son triviales y corresponden a una normativa ISO, así que busca primero aquí cómo se representan las lenguas que vayas a usar.

Quitar el index.php

Si os fijáis, en las estructuras de ejemplo que hemos puesto arriba no aparece el index.php por ninguna parte, cosa que favorece la indexación en los motores de búsqueda. Hay mucha información en la web sobre esto y no voy a profundizar al no ser el cometido de este artículo. Yo lo he resuelto creando un archivo de nombre .htaccess en la raíz de mi site.

<Ifmodule mod_rewrite.c> 
     RewriteEngine On 
     RewriteCond %{REQUEST_FILENAME} !-f 
     RewriteCond %{REQUEST_FILENAME} !-d 
     RewriteRule ^(.*)$ /index.php/$1 [L] 
</IfModule>



<Ifmodule mod_rewrite.c> 

    ErrorDocument 404 /index.php
</IfModule>

Modificar archivos de configuración

Por una parte debemos realizar una modificación en el archivo config.php ubicado en la carpeta ./application/config consistente en precisamente eliminar el archivo index.php.

$config['index_page'] = '';

Por otro lado debemos modificar el archivo routes.php también ubicado en la misma carpeta, añadiendo a lo que tengamos las líneas siguientes con el fin de redireccionar la carpeta correspondiente. Fijaos que se refieren a los lenguajes que vamos a usar y seguimos utilizando la normativa ISO.


// URLs como '/es/login' -> usarán el controlador 'login'.

$route['^(es|ca|en)/(.+)$'] = "$2";



// '/es', '/ca' y '/en' URLs -> usarán el controlador por defecto.

$route['^(es|ca|en)$'] = $route['default_controller'];

Crear los archivos de lenguas

A partir de ahora debemos pensar en que ya no volveremos a usar textos en nuestras views, deberemos referenciar en su lugar una variable única para cada uno de los textos y crear un fichero  de traducción para cada lengua.

Por lo tanto, primero creamos la estructura de carpetas que vamos a usar dentro de ./application/language. 

En el ejemplo de las tres lenguas que usamos en el artículo, deberíamos crear:

./application/language/es/
./application/language/en/
./application/language/ca/

Según las características de nuestra aplicación nos puede convenir más crear un archivo de traducciones para cada controlador, uno general o hacer una cosa mixta. En el ejemplo crearemos uno general al que llamaremos global_lang.php. El nombre que le demos es indiferente con la única excepción de que debe terminar con el sufijo _lang. Este fichero lo debemos copiar en todas las carpetas de language.

./application/language/es/global_lang.php
./application/language/en/global_lang.php
./application/language/ca/global_lang.php

Este fichero deberá contener una entrada por variable con la siguiente estructura:

$lang['identificador_texto']='Texto_en_el_idioma_correspondiente';

Volviendo a nuestro ejemplo:

./application/language/es/global_lang.php

<?php
$lang['usuario']='Usuario';

$lang['registro']='Regístrate gratis';

?>

./application/language/en/global_lang.php


<?php
$lang['usuario']='User';
$lang['registro']='Sign up for free';
?>


./application/language/ca/global_lang.php


<?php
$lang['usuario']='Usari';
$lang['registro']='Registre gratuït';
?>



Creación del controlador

Sólo necesitaremos asegurarnos de llamar al helper language y cargar el formato del fichero antes de llamar al view. Esto sería un ejemplo para un posible login, usando nuestro fichero global_lang.php anterior:

function index()
 {

  $this->load->helper('language');
  $this->load->helper('url');

  // Carga el fichero de idioma. ATENCIÓN!!!  NO PONEMOS EL SUFIJO _lang!!!
  $this->lang->load('global');

  $this->load->view('login/login_view');

 }


Uso en las vistas

Es muy sencillo. Allí donde pondríamos el texto de nuestro ejemplo 'Regístrate Gratis', pondremos en su lugar:

<?php echo lang('registro'); ?>

Fijaos que es el nombre de la variable definida en el fichero global_lang.php


Remate final

Con todo lo que hemos visto ya funcionará el multilenguaje sólo!!!!

Pero como apunte final y colofón, dos utilidades que nos pueden ser (y lo serán) útiles.

Para saber en algún momento en qué lenguaje estamos:

$lenguaje = $this->lang->lang()

Esto lo podemos usar, por ejempo, para definir la lengua en nuestra vista:

<html lang="<?php echo $this->lang->lang();?>">

Otra utilidad interesante a tener en cuenta es el enlace necesario, para cambiar de lengua. Por ejemplo en una banderita con la bandera de la pérfida albión pondríamos:

anchor($this->lang->switch_uri('en'),'Muestra la página actual en inglés');




sábado, 1 de febrero de 2014

Introducción a CakePHP (III): Ver el contenido de un registro

Si llegáis por primera vez a esta especie de minitutorial de aficionado, os aconsejo que empecéis por el principio por aquí. Vimos en el capítulo anterior cómo ver los datos de una tabla. Ahora lo que intentaremos es acceder al detalle de un registro... la verdad es que misterio poco... vamos a verlo...

Vamos a incluir esto en nuestro ArticuloController.

public function ver($id = null) {
$this->Articulo->id = $id;
$this->set('articulo', $this->Articulo->read());

}

Vemos que la acción ver recibe un parámetro que asignará al modelo Artículo.
Después mediante set y bajo las variable artículo pasamos a la vista ver (recordemos que tiene el mismo nombre que la acción), el resultado de Articulo->read().

read(), si lo pasamos sin parámetros, devuelve un array con el registro que hemos seleccionado.

Es decir, con la base de datos de ejemplo que creamos en el primer capítulo, si llamáramos a lo siguiente http://misitio/cake20/articulos/ver/2 nos devolverá:

Array
        (
            [Articulo] => Array
                (
                    [id] => 2
                    [title] => Un título otra vez
                    [body] => Y sigue el cuerpo del artículo.
                    [created] => 2014-01-27 23:36:46
                    [modified] => 
                )

        )

Por otro lado... ya sabemos del capítulo anterior, que realmente esto tal como está daría error. Debemos definir la vista.

En nuestra carpeta /app/View/Articulos, creamos el archivo ver.ctp:

<!-- File: /app/View/Articulos/ver.ctp -->

<h1><?php echo $articulo['Articulo']['title'];?> </h1>
<p><small>Creado: <?php echo $articulo['Articulo']['created'];?></small></p>
<p><?php echo $articulo['Articulo']['body'];?></p>

Ahora ya si hacemos:
http://misitio/cake20/articulos/ver/2


Podremos ver lo que hemos cometido:

Un título otra vez

Creado: 2014-01-30 17:28:48
Y sigue el cuerpo del artículo.

HtmlHelpers

Los helpers son clases que nos ayudan a completar acciones habituales como realizar un link, crear un formulario, formatear texto y números, utilizar Javascript y AJAX...

Cuando queramos generar html de manera dinámica, podemos hacerlo como siempre: con echos de las etiquetas o dejar que CakePHP lo genere por nosotros. Para ello usaremos el HtmlHelper.

¿Qué queremos hacer?  Pues convertiremos el título de nuestro artículo en un enlace que nos llevará a otra pantalla en la que veremos el detalle del registro. Hemos visto una líneas más arriba que podíamos llamar al detalle de un registro con esto:  http://misitio/cake20/articulos/ver/id. Lo que tenemos que hacer es entonces que el enlace se genere dinámicamente referenciando al registro sobre el que se posiciona.

Para acometer este reto usaremos HtmlHelper::link

El formato es el siguiente:

link(cadena a mostrar,  destino, array de opciones)

El array de opciones son los parámetros que de por sí tiene link en html, por ejemplo:
Mención a parte requiere el destino. Podemos como en el ejemplo de arriba poner la url absoluta o relativa o un routing array.


Routing array

No se si a estas alturas merece la pena entrar al detalle con esto... creo que se verá mejor con un ejemplo de uso...

Recordamos de unas líneas más arriba que accedíamos al detalle de un registro así:
http://misitio/cake20/articulos/ver/id

Como ya sabemos la peculiar estructura de carpetas y nomenclaturas en CakePHP nos indica en la URL anterior que articulos es el controlador, view la acción e id el parámetro que está esperando la acción. Esto en nuestro array sería así:

array('controller' => 'articulos', 'action' => 'ver', $articulo['Articulo']['id']));

Fijaos que en este caso hemos obviado el tercer parámetro.

index.ctp

Finalmente... sintetizamos esto en nuestro index.ctp (que recordamos mostraba la tabla)...

<!-- File: /app/View/Articulos/index.ctp -->

<h1>Artículos del Blog</h1>

<table>
    <tr>
        <th>Identificador</th>
        <th>Título</th>
        <th>Creado</th>
    </tr>

<?php foreach ($articulos as $articulo): ?>
    <tr>
        <td><?php echo $articulo['Articulo']['id']; ?></td>
        <td><?php echo $this->Html->link($articulo['Articulo']['title'],                       array('controller' => 'articulos', 'action' => 'ver', $articulo['Articulo']['id'])); ?></td>
        <td><?php echo $articulo['Articulo']['created']; ?></td>
    </tr>
<?php endforeach; ?>

</table> 


Ahora sí...
http://misitio/cake20/articulos

Artículos del Blog

IdentificadorTítuloCreado
1El título2014-01-27 23:36:46
2Un título otra vez2014-01-27 23:36:46
3El título vuelve2014-01-27 23:36:46

Y con esto y un bizcocher...

jueves, 30 de enero de 2014

Introducción a CakePHP (II): Mostrar datos en una tabla

Suponemos que tenemos CakePHP instalado con una base de datos en la que hemos dado de entrada unos registros de prueba con la tabla articulos como indica aquí.

Bien, veamos el contenido de nuestra tabla articulos:

http://misitio/cake20/articulos

Error: ArticulosController could not be found.

Claro, no hemos definido el controlador para nuestro modelo Articulo. De hecho ni siquiera hemos definido el modelo!  Aunque este paso lo ha hecho CakePHP por nosotros heredando de la clase AppController. ¿Una buena praxis? En absoluto.

Definiendo el controlador

En el capítulo anterior dijimos que los controladores se crean en la carpeta app/Controller de CakePHP. Así que crearemos el controlador con la acción que queremos darle: ver_tabla.

En app/Controller creamos el fichero ArticulosController.php, y le damos el siguiente contenido:

<?php
class ArticulosController extends AppController {
public function ver_tabla() {
$this->set('articulos', $this->Articulo->find('all'));
}
?>

Probemos:
http://misitio/cake20/articulos

Error: The action index is not defined in controller ArticulosController

Increíble. Parece que el modelo que aún no hemos definido y que lo ha hecho CakePHP por nosotros, está esperando la acción index. Para que no desespere cambiamos el nombre a nuestra acción.

<?php
class ArticulosController extends AppController {
public function index() {
$this->set('articulos', $this->Articulo->find('all'));
}
}
?>

¿Qué hace el método set?
Dijimos que para mostrar los datos CakePHP usa algo llamado vistas. Set pasa a la vista una variable (primer parámetro) y su valor (segundo parámetro). 

En este caso le pasa el resultado del método find('all') de nuestro modelo Articulo, que lo que hace es generar una tabla con el contenido de todos los registros de la tabla articulos. ¿Y dónde le hemos dicho que coja esa tabla y no otra? En ningún sitio. Es por eso que es tan importante atenerse a la convención en la nomenclatura de las cosas.  :-)

Veamos pues que sucede:
http://misitio/cake20/articulos

Error: The view for ArticulosController::index() was not found.


Maldición... olvidamos crear la vista. Además si os fijáis en el mensaje de error, lo que nos pide CakePHP es una vista para la acción index.

Dijimos que las vistas se colocaban en la carpeta /app/View al que nosotros añadiremos otro nivel de carpetas para tener todas las vistas de cada controlador separadas.  Eso significa que crearemos una vista llamada index.ctp en la carpeta /app/View/Articulos.

Comentamos que el método set del controlador pasaba el contenido de una variable a la vista, ¿no?. Pues bien como contenido de la vista pongamos lo siguiente:

<pre>
     <?php print_r($articulos); ?>
</pre>

Podemos ver cómo sobre la variable artículo habíamos recibido un array con la estructura y contenido de la tabla articulos de la base de datos:

Array
(
    [0] => Array
        (
            [Articulo] => Array
                (
                    [id] => 1
                    [title] => El título
                    [body] => Esto es el cuerpo del artículo.
                    [created] => 2014-01-27 23:36:46
                    [modified] => 
                )

        )

    [1] => Array
        (
            [Articulo] => Array
                (
                    [id] => 2
                    [title] => Un título otra vez
                    [body] => Y sigue el cuerpo del artículo.
                    [created] => 2014-01-27 23:36:46
                    [modified] => 
                )

        )

    [2] => Array
        (
            [Articulo] => Array
                (
                    [id] => 3
                    [title] => El título vuelve
                    [body] => Esto es realmente excitante! No.
                    [created] => 2014-01-27 23:36:46
                    [modified] => 
                )

        )

)

Para acabar... si en la vista recibimos la tabla... nada nos impide cambiar el contenido de la vista por esto:

<!-- File: /app/View/Articulos/index.ctp -->

<h1>Artículos del Blog</h1>

<table>
    <tr>
        <th>Identificador</th>
        <th>Título</th>
        <th>Creado</th>
    </tr>

<?php foreach ($articulos as $articulo): ?>
    <tr>
        <td><?php echo $articulo['Articulo']['id']; ?></td>
        <td><?php echo $articulo['Articulo']['title']; ?></td>
        <td><?php echo $articulo['Articulo']['created']; ?></td>
    </tr>
<?php endforeach; ?>

</table> 

Ahora sí...
http://misitio/cake20/articulos


Artículos del Blog

IdentificadorTítuloCreado
1El título2014-01-27 23:36:46
2Un título otra vez2014-01-27 23:36:46
3El título vuelve2014-01-27 23:36:46

Lo flipasssssssssss....

martes, 28 de enero de 2014

Introducción a CakePHP (I)

CakePHP es un framework que pretende facilitarnos la vida programando en php. Por poner un ejemplo, se ha terminado el hacer consultas a la base de datos...
Insisto en este artículo, que el propósito de este blog no es más que plasmar mis propias anotaciones sobre los sistemas que ensayo, aunque siendo conocedor que no voy a ser el único que se aproveche de ello, me gusta darle apariencia de tutorial y dirigirme a un posible público como 'profesor' simplemente como diversión y porque me gusta escribir.
Aclarado esto, una vez me he metido en harina en este sistema que estoy probando, me he dado cuenta que el tutorial es un absoluto desastre, por lo que lo voy a reescribir a mi manera.

Instalación

1.- Descargamos CakePHP de la página oficial y lo descomprimimos.
2.- Ahora crearemos una carpeta que llamaremos por ejemplo /cake20 en la raíz de nuestro servidor web (ya sea un hosting en la red o un servidor web en nuestro PC como EasyPHP)
3.- Copiamos o subimos al servidor los archivos descomprimidos en la carpeta que hemos creado anteriormente.
4.- Creamos una base de datos.
5.- Configuramos la base de datos en CakePHP.
Para ello nos dirigimos a la carpeta /app/Config y copiamos el fichero database.php.default y lo renombramos simplemente como database.php.
Editamos el fichero y configuramos la base de datos:
public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'localhost',
    'port' => '',
    'login' => 'cakeBlog',
    'password' => 'c4k3-rUl3Z',
    'database' => 'cake_blog_tutorial',
    'schema' => '',
    'prefix' => '',
    'encoding' => ''
);
 6.- Configuramos la encriptación, más que nada porque si no CakePHP se quejará.

Editamos el fichero core.php que se encuentra en la carpeta /app/Config.

Buscamos la línea Configure::write('Security.salt', 'pl345e-P45s_7h3*S@l7!'); y cambiamos la parte que he marcado en fosforito por la cadena de caracteres que nos de la gana.

Así mismo buscamos Configure::write('Security.cipherSeed', '7485712659625147843639846751'); y cambiamos los números por otra numeració cualquiera.

Y con esto ya hemos acabado.

Como funciona CakePHP

Pues funciona sólo. De hecho, en el manual se habla varias veces de la magia de CakePHP y en ocasiones parece que sea así.
De hecho para saber lo que tiene que hacer CakePHP usa una serie de convenciones en la nomenclatura y la estructura de carpetas y lo veremos con un ejemplo: una lista de artículos (o lo que viene a ser un blog)

Así que lo primero que haremos será rellenar la base de datos con tres artículos para probar. Así que usando nuestro gestor de base de datos (p. ej. PhpMyAdmin) ejecutaremos los siguientes comandos:

/* tabla para nuestros artículos */
CREATE TABLE articulos (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(50),
    body TEXT,
    created DATETIME DEFAULT NULL,
    modified DATETIME DEFAULT NULL
);

/* algunos valores de test */
INSERT INTO articulos (title,body,created)
    VALUES ('El título', 'Esto es el cuerpo del artículo.', NOW());
INSERT INTO articulos (title,body,created)
    VALUES ('Un título otra vez', 'Y sigue el cuerpo del artículo.', NOW());
INSERT INTO articulos (title,body,created)
    VALUES ('El título vuelve', 'Esto es realmente excitante! No?', NOW());

Pues bien, aquí viene la primera convención. Fijaos que hemos llamado a la tabla articulos en minúscula. Es más si hubiera sido nombre compuesto la hubiéramos llamado en minúscula y con un underscore ( _ ) entre palabras.

Esta tabla podríamos considerar que es una entidad, un objeto o como llama CakePHP, un modelo.

Los modelos se nombran en mayúscula y en singular y se guardan en la carpeta /app/model. En nuestro caso tendríamos un fichero llamado Articulo.php en esa carpeta. En ese archivo tendremos la declaración del modelo y sus validaciones.

Sólo por usar esa nomenclatura, CakePHP supondrá que en la carpeta /app/Controller, tendremos un fichero llamado ArticulosController.php. Como podemos imaginar, este tipo de objeto se llamará genéricamente controlador y gestionará la lectura y escritura de los datos.

Finalmente necesitaremos un formato de salida en pantalla, un template para entendernos. Sin embargo, no necesitaremos el mismo si mostramos una tabla para seleccionar un registro o el registro en sí, de lo que deduciremos que podremos tener varios. Estos archivos, que llamaremos vistas, llevan extensión '*.ctp' y se alojan en la carpeta /app/View/Nombre_controlador. En nuestro caso /app/View/Articulos/  (Artículos en plural). Los archivos con extensión '*.ctp' pueden tener cualquier nombre.

Con estas 4 cosas y unas pocas líneas de código, podemos desarrollar un mantenimiento CRUD completo. Pero esto, ya lo iremos viendo...

La importancia de las convenciones

Como ya se ha apuntado si seguimos una rígida normativa, CakePHP hará muchas cosas por nosotros.
La normativa para los modelos es que se escriben en singular y en UpperCamelCase si son compuestas.
La normativa para las tablas de la base de datos es que se ecriben en plural y con underscores ( _ ) en lugar de espacios si son compuestas.

Esto significa que si tenemos un modelo llamado Articulo, CakePHP manejará automáticamente la tabla articulos, y si tenemos un modelo llamado ArticuloLargoCakePHP gestionará automáticamente la tabla articulo_largos. (Sí, ya se que en la lengua de Espronceda queda un poco raro, pero hay que hacer un esfuerzo)

Pero aún hay más! Si nuestra tabla tiene el campo name o title las usará como etiquetas en ciertas ocasiones (manda title sobre name) y si tenemos creados los campos created o modified se estamparán las fechas automáticamente! Y es más! (aunque yo no lo he conseguido) pero en principio si el campo id es de tipo int, se rumorea que CakePHP lo gestiona también y si es de tipo char(36) gestiona un identificador UUID)

Y eso es todo por ahora...  hasta la próxima.