Estas en: Home > actualizar

Entradas etiquetadas con actualizar

Cambiando todo el hardware del ordenador en Debian 7 Wheezy

0

Después de unos cuantos años sin renovar el hardware del pc, este mes tocó renovación, y a lo grande. Principalmente por el final de soporte de Windows XP y que para algunos proyectos (y juegos… ejem, ejem) necesitaba más memoria RAM.

He dedicado bastantes horas a valorar que hardware comprar y que no se me fuese de presupuesto. Al final me decidí por lo siguiente:

Micro AMD FX 8350 Black Edition (8 nucleos)

Placa base ASUS M5A99FX PRO R2.0

Tarjeta gráfica ASUS GeForce NVIDIA GTX 780

– Fuente de alimentación Aerocool Strike-X 800

Y torre nueva: Aerocool Strike-X Advance

Los discos duros, aunque ya han superado su edad de vida media, aun funcionan, así que de momento no se tocan.

La instalación fue relativamente sencilla, aunque como ocurre siempre en un equipo de hace seis años, siempre hay algo que no funciona en el hardware nuevo. Uno de ellos fue uno de los discos duros, que por alguna extraña razón la placa no me lo reconocía. Por suerte solo era un disco para almacenar chorradillas que no se donde meterlas.

Una vez conectados los discos duros y que todo estuviera bien conectado, crucé los dedos y pulse el interruptor de la torre… se encendió a la primera, la placa base, los leds azules de la la torre, los ventiladores, el cooler, la gráfica, los discos duros,… espera… ¿Y ese pantallazo azul?… Mierda, Windows XP ha cascao, seguro que tenía alguna librería en el disco duro que no reconocía la placa, en fin, ¡Larga vida a Debian 7!

La verdad es que no fue un gran problema que Windows XP muriese en el proceso, al fin y al cabo llevaba tiempo queriendo cambiar definitivamente a Debian, así que fue una razón más para abandonar Windows por algo mucho mejor.

Aunque leí que cambiar el hardware en Debian no tenía por qué suponer un problema, es decir, que al entrar en el Sistema Operativo todo funcionaría igual; mi experiencia me decía que esto iba a cascar por todos lados.

Bueno pues me equivoqué a medias: el cambio de hardware hizo que se mostrasen algunos fallos (el módulo del kernel para la tarjeta de red, por ejemplo), pero solo fallo por un lado: la tarjeta gráfica, que impedía que se iniciase el servidor gráfico.

Y es que Debian 7 Wheezy no reconocía la gráfica debido a que los drivers de nvidia en Wheezy solo llegan hasta la 302, y para que me la reconociese necesitaba mínimo la 319, que es la que da soporte a la GTX 780.

¿Solución? Actualizar a Debian 8 Jessie, o lo que es lo mismo: pasar de stable a testing. He de decir que Jessie es bastante estable, y sabiendo que está previsto que se congele la inclusión de nuevos paquetes en esta rama hacia Noviembre de 2014, no había riesgo de que fallase por otro lado.

En primer lugar hay que editar el archivo /etc/apt/sources.list y sustituir la palabra «wheezy» por «jessie«, y «stable» por «testing«.

Hacemos un apt-get update, y si todo ha ido bien ejecutamos apt-get dist-upgrade, y a esperar que se descargue e instale todo.

Una vez instalado todo, seguiremos sin gráfica y sin servidor gráfico. Primero comprobamos que ahora sí reconoce la gráfica escribiendo en la consola el siguiente comando: lspci | grep «VGA».

Este comando nos debe mostrar el modelo de tarjeta gráfica que tenemos.

Y a partir de aquí es hora de configurar la gráfica. Para ello os voy a dejar un artículo que me ha ayudado muchísimo a la hora de configurarla y se merece que le enlace; los pasos a seguir ya sea en Debian 7 Wheezy o Debian 8 Jessie son los mismos, con lo que espero que este tutorial os valga tanto como me ha servido a mí:

Instalar los drivers nvidia privativos en Debian

Logo Cassandra

Cassandra 1.x y PHP para desarrolladores SQL: phpCassa (II)

0

En el anterior post traté las acciones habituales que realizamos con Cassandra: guardar, actualizar y eliminar. Sin embargo aun quedan dos acciones muy útiles por tratar: los contadores y los indices secundarios.

 

CONTADORES

Los contadores son en realidad un tipo especial de validador de Column Family.

 

CREAR UN CONTADOR 

Para crearla procedemos de la siguiente manera:

– Accedemos a Cassandra Cluster Admin:

Página principal de Cassandra Cluster Admin

– Entramos en el keyspace con el que estamos trabajando:

Detalle del keyspace my_keyspace

– Pulsamos en Create New Column Family y escribimos los siguientes datos:

Datos para crear una Column Family con contadores

– En Default Validation Class el texto completo a escribir es:

org.apache.cassandra.db.marshal.CounterColumnType

– Y pulsamos el botón Create Column Family.

Varias cosas sobre los CounterColumn:
– Para crear los CounterColumns es obligatorio indicar en Default Validation Class la clase de validador correcto. Indicado más arriba.
– Los contadores puedes tener números positivos o negativos.
– Los CounterColumns no son un sustituto de el autoincrement de las bases relacionales.

Ahora que ya está creada la Column Family es hora de programar.

 

GUARDAR Y/O ACTUALIZAR UN CONTADOR 

En nuestra clase en cassandra.php creamos el siguiente método:

 

  1. <?php
  2.  
  3. public function guardarContador($name_columnFamily, $key, $column, $value=1, $super_column=NULL){
  4.  
  5. try {
  6. if (!is_null($super_column)){
  7. $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily);
  8. $column_family->add($key, $super_column, $column, $value);
  9. }
  10. else{
  11. $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
  12. $column_family->add($key, $column, $value);
  13. }
  14. return true;
  15. }
  16. catch(Exception $e){
  17. return false;
  18. }
  19. }

 

Con este método podremos incrementar o disminuir el contador.


$name_columnFamily
: Es el nombre de la column family donde se encuentra el contador a modificar.

$key: Clave del registro donde se encuentra el contador.
$column: Nombre del contador.
$value: Valor a añadir al contador.
$super_column: Clave de la super column donde se encuentra el contador.

Añadimos el siguiente código a nuestro archivo test.php:

  1. <?php
  2.  
  3. if ( $cass->guardarContador('column_family_counter', 'post', 'num_total_post', 1)){
  4. print "El contador se ha actualizado correctamente<br />";
  5. }else{
  6. print "Error al actualizar el contador<br />";
  7. }
  8.  
  9. $result = $cass->obtener('column_family_counter', 'post');
  10.  
  11. print_r($result);

Como ves, para recuperar un contador se utiliza el mismo método que para obtener cualquier otro registro. El resultado de este código sería:

El contador se ha actualizado correctamente
 Array ( [num_total_post] => 1 )

 

PONER A CERO EL CONTADOR

Para poner a cero un contador hay que restarle el valor que tenga en ese momento el contador. En test.php escribiríamos lo siguiente:

  1. <?php
  2.  
  3. if ( $cass->guardarContador('column_family_counter', 'post', 'num_total_post', ($result['num_total_post']*-1))){
  4. print "El contador se ha actualizado correctamente<br />";
  5. }else{
  6. print "Error al actualizar el contador<br />";
  7. }
  8.  
  9. $result = $cass->obtener('column_family_counter', 'post');
  10.  
  11. print_r($result);

Y el resultado:

El contador se ha actualizado correctamente
 Array ( [num_total_post] => 0 )

 

INDICES SECUNDARIOS

Los indices secundarios son un objeto especial en Cassandra que nos permite realizar búsquedas por columnas concretas.

Estos índices solo funcionan en las column family standard, con lo que su uso se ve bastante limitado.

 

 

CREAR UN INDICE SECUNDARIO

Para ello vamos a nuestro Cassandra Cluster Admin y en la column family my_column_family_standard pulsamos en Create Secondary Index:

Detalle de la ubicación del botón Create Secondary Index

Detalle de la ubicación del botón Create Secondary Index

– Nos aparecerá el siguiente formulario:

Detalle del formulario para crear un índice secundario

Detalle del formulario para crear un índice secundario

– Para nuestro cometido vamos a crear el siguiente índice secundario:

Formulario con los datos para el ejemplo

Formulario con los datos para el ejemplo

–  Pulsamos en Add Secondary Index.

 

REALIZAR UNA CONSULTA CON UN INDICE SECUNDARIO 

Nos vamos a nuestro archivo cassandra.php y añadimos el siguiente método:

  1. <?php
  2.  
  3. private function getIndexOperator($value){
  4. switch ($value){
  5. case '=':
  6. $operator = 'EQ';
  7. break;
  8. case '>=':
  9. $operator = 'GTE';
  10. break;
  11. case '>':
  12. $operator = 'GT';
  13. break;
  14. case '<=':
  15. $operator = 'LTE';
  16. break;
  17. case '<':
  18. $operator = 'LT';
  19. break;
  20. default:
  21. $operator = 'EQ';
  22. break;
  23. }
  24.  
  25. return $operator;
  26. }

Este método nos permitirá trabajar con operadores diferentes a la igualdad, pudiendo utilizar >,<,>=,<=.

Pero para poder trabajar con índices es necesario incluir en nuestro listado de namespaces dos nuevas clases, tal y como se muestra en el siguiente código:

  1. <?php
  2.  
  3. use phpcassa\Connection\ConnectionPool;
  4. use phpcassa\ColumnFamily;
  5. use phpcassa\SuperColumnFamily;
  6. use phpcassa\ColumnSlice;
  7. use phpcassa\SystemManager;
  8. use phpcassa\Schema\StrategyClass;
  9. use phpcassa\Index\IndexExpression;
  10. use phpcassa\Index\IndexClause;

A continuación creamos el método que generará la consulta con los índices secundarios.

 

  1. <?php
  2.  
  3. public function obtenerPorIndices($name_columnFamily, $arrayColumnsValues, $range_start = "", $range_end = '', $column_count = 100, $invertir_orden = false){
  4.  
  5. try{
  6. // Creamos el objeto
  7. $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
  8.  
  9. // Inicializamos las variables
  10. $index_exp = array();
  11. $registros = array();
  12.  
  13. // Creamos un array de index_expression
  14. foreach($arrayColumnsValues as $key => $value){
  15. if (array_key_exists('operator', $value)){
  16. $op = $this->getIndexOperator($value['operator']);
  17. }
  18. else{
  19. $this->getIndexOperator('=');
  20. }
  21.  
  22. $column = $value['values'];
  23. $key_column = key($column);
  24.  
  25. $index_exp[] = new IndexExpression($key_column, $column[$key_column], $op);
  26. }
  27.  
  28. // Creamos la index_clause
  29. $index_clause = new IndexClause($index_exp, $range_start, $column_count);
  30.  
  31. // Creamos la column_slice
  32. $column_slice = new ColumnSlice($range_start, $range_end, $column_count, $invertir_orden);
  33.  
  34. // Recuperamos los registros
  35. $rows = $column_family->get_indexed_slices($index_clause, $column_slice);
  36.  
  37. foreach($rows as $key => $columns){
  38. if (!array_key_exists($key, $registros)){ $registros[$key] = null; }
  39. $registros[$key] = $columns;
  40. }
  41. return $registros;
  42. }catch (Exception $e){
  43. return false;
  44. }
  45. }

 

Con este método podremos buscar registros con varios índices secundarios.

Lo primero que hacemos en este método es crear el objeto ColumnFamily que nos proveerá de los métodos para hacer la consulta con indices secundarios. A continuación inicializamos varias variables necesarias para el método.

Dentro de un bucle creamos un array de IndexExpression(). Este objeto le indicará a Cassandra qué indices, con qué valores y qué operador se deben buscar los registros.

Seguidamente creamos la iIndexClause(), que nos permite indicarle la key desde la que comenzará a recuperar registros y el número de registros a obtener.

Por último recuperamos los registros utilizando el método get_indexed_slices().

Para probar el método vamos a crear datos de prueba en test.php y haremos la consulta:

 

  1. <?php
  2.  
  3. $data[] = array(
  4. 'title' => 'Apache Cassandra',
  5. 'license' => 'Open Source',
  6. 'category' => 'no-sql',
  7. );
  8.  
  9. $data[] = array(
  10. 'title' => 'MongoDB',
  11. 'license' => 'Open Source',
  12. 'category' => 'no-sql',
  13. );
  14.  
  15. $data[] = array(
  16. 'title' => 'MySQL',
  17. 'license' => 'Open Source',
  18. 'category' => 'sql',
  19. );
  20.  
  21. foreach($data as $key => $value){
  22. $cass->guardar('my_column_family_standard', $key, $value);
  23. }
  24.  
  25. $arrayColumnsValues[] = array(
  26. 'values' => array(
  27. 'category' => 'no-sql'
  28. ),
  29. 'operator' => '='
  30. );
  31.  
  32. $result = $cass->obtenerPorIndices('my_column_family_standard', $arrayColumnsValues);
  33.  
  34. print_r($result);

 

Si ejecutamos el código anterior Cassandra nos devolverá:

Array ( [0] => Array ( [title] => Apache Cassandra [license] => Open Source [category] => no-sql ) [1] => Array ( [title] => MongoDB [license] => Open Source [category] => no-sql ) )

[ci-box type=»warning»]Al utilizar un operador diferente al = puede que Cassandra te devuelva un error. Para evitarlo añade otro indice secundario a la consulta pero con el operador =, siendo este la primera columna que Cassandra procese. Por alguna razón Cassandra devuelve un error si no se hace así. [/ci-box]

Con este post concluye la parte básica de PHPCassa, Cassandra y Cassandra Cluster Admin. En el próximo post y siguientes trataré varios temas que se han quedado un poco colgados o faltan por explicar como ordenar registros, cómo crear claves, mejorar el rendimiento de Cassandra, crear clusters, etc.

 

Logo Cassandra

Cassandra 1.x y PHP para desarrolladores SQL: PHPCassa (I)

0

¡Por fin llego el día! ¡Hoy toca programar!

Para ello vamos a utilizar las clases de abstracción de la base de datos PHPCassa que nos ahorrará bastante tiempo para trabajar con Cassandra. Puedes descargarlo desde https://github.com/thobbs/phpcassa.

Ubicamos PHPCassa en una carpeta dentro de nuestro servidor web y creamos dos archivos. Yo los he llamado test.php y cassandra.php. El segundo será una clase que nos ahorrará algunas lineas de código con las tareas habituales. El primero lo utilizaré para testear la clase y sus respectivos métodos.

Bien empecemos.

 

PRIMEROS PASOS

En primer lugar necesitamos incluir un archivo de PHPCassa en cassandra.php:

  1. <?php
  2.  
  3. // CLASES NECESARIAS PARA CONECTAR CON CASSANDRA
  4. require_once('phpcassa/lib/autoload.php');

He inmediatamente llamamos a los namespace mínimos para trabajar con PHPCassa:

  1. <?php
  2.  
  3. use phpcassa\Connection\ConnectionPool;
  4. use phpcassa\ColumnFamily;
  5. use phpcassa\SystemManager;
  6. use phpcassa\Schema\StrategyClass;

 

Justo debajo creamos la clase:

  1. <?php
  2.  
  3. class cassandra {
  4.  
  5. }

 

CONECTANDO

Para realizar la conexión a la BD, PHPCassa nos pide tan solo un dato obligatorio: el nombre del keyspace con el que vamos a trabajar. También nos permite añadir las ips de los nodos con los que queramos trabajar, aunque por defecto su valor es localhost. Por tanto podemos crear un constructor como el siguiente:

  1. <?php
  2.  
  3. function __construct($keyspace, $nodos = array('localhost')){
  4. if (!empty($keyspace)){
  5. $this->conexion = new ConnectionPool($keyspace, $nodos);
  6. }else{
  7. print "El keyspace está vacío";
  8. }
  9. }

Este constructor nos permite indicarle a la clase el keyspace con el que queremos trabajar y la ip o nombre de servidor donde se encuentre nuestra instancia de Cassandra. Por defecto el puerto al que se va a conectar es el 9160. Si hubieses configurado Cassandra para escuchar en otro puerto deberás especificarlo: localhost:9160.

Este código nos crea una variable llamada conexion que será una instancia del objeto ConnectionPool, necesario para todas las consultas a la BD

 

GUARDANDO REGISTROS

Ahora procedemos a crear el método que guardará los registros. Para ello primero crearemos un objeto ColumnFamily al que le pasaremos el nombre de la column family en la que queremos trabajar:

  1. <?php
  2.  
  3. public function guardar($name_columnFamily, $key, $data = array()){
  4. try {
  5. $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
  6. $column_family->insert($key, $data);
  7. return true;
  8. }catch(Exception $e){
  9. return false;
  10. }
  11. }

Este método nos devolverá true si se ha guardado correctamente el registro, o false en caso de error.
Como puedes ver, al objeto ColumnFamily se le pasa como primer parámetro el objeto ConnectionPool que creamos en el constructor, después se le pasa el nombre de la column family.
Una vez creado el objeto ColumnFamily ya podemos utilizar el método insert para guardar el registro pasándole como parámetros la key y un array con las columnas y sus respectivos valores.

 

RECUPERANDO REGISTROS

Recuperar registros de Cassandra es algo más complejo que guardarlos:

Primero debemos añadir un nuevo namespace que nos permitirá usar una clase que nos será muy útil. El listado de namespaces nos quedaría así:

  1. <?php
  2.  
  3. use phpcassa\Connection\ConnectionPool;
  4. use phpcassa\ColumnFamily;
  5. use phpcassa\ColumnSlice;
  6. use phpcassa\SystemManager;
  7. use phpcassa\Schema\StrategyClass;

A continuación creamos el método en nuestro archivo cassandra.php:

 

  1. <?php
  2.  
  3. public function obtener($name_columnFamily, $key, $column_names= NULL, $range_start = "", $range_end = "", $column_count = 100, $invertir_orden=false){
  4.  
  5. try{
  6. $column_slices = new ColumnSlice($range_start, $range_end, $column_count, $invertir_orden);
  7. $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
  8. $result = $column_family->get($key, $column_slices, $column_names);
  9. }catch(Exception $e){
  10. return false;
  11. }
  12.  
  13. return $result;
  14.  
  15. }

 

Este método tiene algunos parámetros más que al guardar, pero tienen su razón de ser:

$columnFamily: Nombre de la column family donde buscar.
$key: Clave del registro donde buscar.
$columns: Columnas a buscar. No es obligatorio. Por defecto NULL.
$range_start: Key por la que Cassandra debe empezar a recuperar registros. No es obligatorio. Por defecto «».$range_end: Key por la que Cassandra dejará de recuperar registros. No es obligatorio. Por defecto «».
$column_count: Número de registros a obtener, Por defecto 100.
$invertir_orden: Invierte el orden en el que se recuperar los registros. De mayor a menor o viceversa, de la A-Z o viceversa, etc.

Como ves tienes bastantes opciones para recuperar registros. Este método devuelve un array con los registros.

 

PROBANDO LA CLASE

Vamos a probar el código a ver que tal funciona. Nos vamos al archivo test.php y escribimos el siguiente código:

  1. <?php
  2.  
  3. include_once "cassandra.php";
  4.  
  5. $cass = new cassandra('my_keyspace', array('192.168.1.10'));
  6.  
  7. $data = array(
  8. 'nombre' => 'pepito',
  9. 'ciudad' => 'Madrid',
  10. 'vehiculo' => 'coche',
  11. );
  12.  
  13. if ( $cass->guardar('my_column_family_standard', $key=1, $data)){
  14. print "El registro se ha guardado correctamente<br />";
  15. }else{
  16. print "Error al guardar el registro<br />";
  17. }
  18.  
  19. $result = $cass->obtener('my_column_family_standard', $key=1);
  20.  
  21. print_r($result);
  22. ?>

Explico un poco el código anterior:

  1. Incluimos la clase en el archivo.
  2. Creamos el objeto indicándole el keyspace con el que trabajar (my_keyspace), y dentro de un array, la ip donde se encuentra en nodo de Cassandra. Si tuvieses Cassandra instalado en localhost no sería necesario indicar el segundo parámetro.
  3. Creamos el array que contendrá los datos a guardar.
  4. Creamos un condicional que guardará los datos en Cassandra y nos indicará si se han guardado correctamente o ha habido algún error.
  5. Guardamos en una variable ($result) los registros que recuperamos a través del método obtener del objeto $cass. A este método le indicamos la column family a buscar y la key a obtener.
  6. Mostramos los registros.

Si todo ha salido correctamente verás un texto como el siguiente cuando ejecutes el script:

El registro se ha guardado correctamente
 Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche )

Si te aparecen más registros es posible que no vaciases las column family con la que trabajas. Simplemente ves a Cassandra Cluster Admin, entra en la column family y pulsa en Truncate Column Family. Así eliminarás todos los datos de la column family.

 

ACTUALIZAR UN REGISTRO

Ahora que ya funciona nuestra clase podemos ampliarla con nuevas características.
Aunque pienses que para actualizar un registro es necesario un nuevo método, en Cassandra no es necesario, simplemente utilizaremos el método guardar indicandole la key a modificar y el array con los datos a guardar.

Justo debajo del código que ya tenemos en el archivo test.php escribimos lo siguiente:

  1. <?php
  2.  
  3. $data = array(
  4. 'ciudad' => 'Barcelona',
  5. );
  6.  
  7. if ( $cass->guardar('my_column_family_standard', $key=1, $data)){
  8. print "El registro se ha guardado correctamente<br />";
  9. }else{
  10. print "Error al guardar el registro<br />";
  11. }
  12.  
  13. $result = $cass->obtener('my_column_family_standard', $key=1);
  14.  
  15. print_r($result);

Como observarás el array no tiene todos los datos de la key que vamos a modificar, ya que no es necesario, tan solo pasaremos los datos que queremos actualizar. El resultado de este código es el siguiente:

El registro se ha guardado correctamente
 Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche )
 El registro se ha guardado correctamente
 Array ( [ciudad] => Barcelona [nombre] => pepito [vehiculo] => coche )

La columna ciudad a cambiado, el resto sigue igual, la razón está en que cuando le pasas a Cassandra una key que ya existe, lo que hace es actualizar las columnas que se correspondan con las keys del array. Si en ese array hubiera keys que no existen como columnas en el registro, Cassandra simplemente las crearía nuevas.

 

GUARDANDO UNA SUPER COLUMN

Aquí tampoco nos hace falta crear un nuevo método ya que nos sirve perfectamente el método guardar, pero deberemos hacerle algunas modificaciones.

En primer lugar, para trabajar con column families super es necesario añadir una llamada al namespace concreto. La lista de namespaces quedaría de la siguiente manera:

  1. <?php
  2.  
  3. use phpcassa\Connection\ConnectionPool;
  4. use phpcassa\ColumnFamily;
  5. use phpcassa\SuperColumnFamily;
  6. use phpcassa\ColumnSlice;
  7. use phpcassa\SystemManager;
  8. use phpcassa\Schema\StrategyClass;

Ahora debemos modificar el método guardar y añadirle el parámetro $is_super_column, que nos permitirá crear un objeto SuperColumnFamily o ColumnFamily según corresponda. El método nos quedaría así:

  1. <?php
  2.  
  3. public function guardar($name_columnFamily, $key, $data = array(), $is_super_column = false){
  4.  
  5. try {
  6. if ($is_super_column){
  7. $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily);
  8. }
  9. else{
  10. $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
  11. }
  12.  
  13. $column_family->insert($key, $data);
  14. return true;
  15. }catch(Exception $e){
  16. return false;
  17. }
  18. }

Como ambas clases comparten el método insert no nos hace falta incluir esa linea dentro del condicional.

A continuación modificamos el método obtener con el mismo parámetro y utilizando el mismo sistema para crear el objeto correspondiente:

  1. <?php
  2.  
  3. public function obtener($name_columnFamily, $key, $is_super_column=false, $column_names= NULL, $range_start = "", $range_end = "", $column_count = 100, $invertir_orden=false){
  4.  
  5. try{
  6. if ($is_super_column){
  7. $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily);
  8. }
  9. else{
  10. $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
  11. }
  12. $column_slices = new ColumnSlice($range_start, $range_end, $column_count, $invertir_orden);
  13. $result = $column_family->get($key, $column_slices, $column_names);
  14. }catch(Exception $e){
  15. return false;
  16. }
  17.  
  18. return $result;
  19.  
  20. }

Ahora podemos añadir el siguiente código a nuestro archivo test.php:

  1. <?php
  2.  
  3. $data = array('vecino_1' => array(
  4. 'nombre' => 'pepito',
  5. 'ciudad' => 'Madrid',
  6. 'vehiculo' => 'coche',
  7. ));
  8.  
  9. if ( $cass->guardar('my_column_family_super', $key=1, $data, $is_super_column=true)){
  10. print "El registro se ha guardado correctamente<br />";
  11. }else{
  12. print "Error al guardar el registro<br />";
  13. }
  14.  
  15. $result = $cass->obtener('my_column_family_super', $key=1, $is_super_column=true);
  16.  
  17. print_r($result);

El único cambio además del nombre de la column family donde vamos a guardar el registro, se encuentra en el array con los datos. Este tiene un elemento que es la key de la super column, y como valor, el array de las columns a guardar.

Si ejecutamos el código anterior nos devolverá lo siguiente:

El registro se ha guardado correctamente
 Array ( [vecino_1] => Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche ) )

[ci-box type=»warning»]Al probar el código, PHP me devolvió el siguiente aviso:
Strict Standards: Declaration of phpcassa\SuperColumnFamily::add() should be compatible with that of phpcassa\ColumnFamily::add() in /var/www/prueba_cassandra/phpcassa/lib/phpcassa/SuperColumnFamily.php on line 491. 

No te preocupes no afecta ni a los ejemplos ni a la clase que funcionan correctamente.[/ci-box]

ACTUALIZANDO UNA SUPER COLUMN

La actualización de una super column se limita a las columnas que contienen los valores del registro no a su key. Si modificáramos la key , lo que en realidad estaríamos haciendo sería crear una nueva super column. Añadimos el siguiente código a nuestro archivo test.php:

  1. <?php
  2.  
  3. $data = array('vecino_1' => array(
  4. 'nombre' => 'pepito',
  5. 'ciudad' => 'Barcelona',
  6. 'vehiculo' => 'coche',
  7. ));
  8.  
  9. if ( $cass->guardar('my_column_family_super', $key1, $data, $is_super_column=true)){
  10. print "El registro se ha guardado correctamente<br />";
  11. }else{
  12. print "Error al guardar el registro<br />";
  13. }
  14.  
  15. $result = $cass->obtener('my_column_family_super', $key=1, $is_super_column=true);
  16.  
  17. print_r($result);

Y el resultado es:

El registro se ha guardado correctamente
 Array ( [vecino_1] => Array ( [ciudad] => Barcelona [nombre] => pepito [vehiculo] => coche ) )

 

ELIMINAR REGISTROS

Sí, aquí toca crear un nuevo método para nuestra clase en cassandra.php, aunque tampoco nos vamos a matar programando:

 

  1. <?php
  2.  
  3. public function eliminar($name_columnFamily, $key, $is_super_column = false){
  4.  
  5. try{
  6. if ($is_super_column){
  7. $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily);
  8. }
  9. else{
  10. $column_family = new ColumnFamily($this->conexion, $name_columnFamily);
  11. }
  12. $column_family->remove($key);
  13. return true;
  14. }catch(Exception $e){
  15. return false;
  16. }
  17. }

 

El método es bastante sencillo: se le pasan tres parámetros que ya conocemos.

Dentro del método se crea un objeto ColumnFamily y se utiliza el método remove para eliminar el registro pasándole la key correspondiente, y si fuese una super column, la key de este.
El método remove tiene un segundo parámetro que por defecto tiene un valor null, en él se pueden añadir como array los nombres de las columnas a eliminar. Como no es habitual ese proceso he creído adecuado no utilizarlo.

Una vez añadido esté método a nuestra clase modificamos el archivo test.php con el siguiente código:

  1. <?php
  2.  
  3. if ( $cass->eliminar('my_column_family_standard', $key=1)){
  4. print "El registro se ha eliminado correctamente<br />";
  5. }else{
  6. print "Error al eliminar el registro<br />";
  7. }
  8.  
  9. $result = $cass->obtener('my_column_family_standard', $key=1);
  10.  
  11. print_r($result);

Y el resultado es:

El registro se ha eliminado correctamente

 

De momento con esto es suficiente, dejo en tus manos estos métodos para que juegues con ellos todo lo que quieras y te familiarices con PHPCassa.

En el próximo post trataré las Counter Columns que nos servirán para contar registros, los Secondary Index que nos permitirán realizar búsquedas por columnas concretas, y algunas cosas más.

Logo Cassandra

Cassandra y PHP para desarrolladores SQL: phpCassa (II)

0

En el anterior post traté las acciones habituales que realizamos con Cassandra: guardar, actualizar y eliminar. Sin embargo aun quedan dos acciones muy útiles por tratar: los contadores y los indices secundarios.

 

CONTADORES

Los contadores son en realidad un tipo especial de validador de Column Family.

 

CREAR UN CONTADOR 

Para crearla procedemos de la siguiente manera:

– Accedemos a Cassandra Cluster Admin:

Página principal de Cassandra Cluster Admin

– Entramos en el keyspace con el que estamos trabajando:

Detalle del keyspace my_keyspace

– Pulsamos en Create New Column Family y escribimos los siguientes datos:

Datos para crear una Column Family con contadores

– En Default Validation Class el texto completo a escribir es:

org.apache.cassandra.db.marshal.CounterColumnType

– Y pulsamos el botón Create Column Family.

Varias cosas sobre los CounterColumn:
– Para crear los CounterColumns es obligatorio indicar en Default Validation Class la clase de validador correcto. Indicado más arriba.
– Los contadores puedes tener números positivos o negativos.
– Los CounterColumns no son un sustituto de el autoincrement de las bases relacionales.

Ahora que ya está creada la Column Family es hora de programar.

 

GUARDAR Y/O ACTUALIZAR UN CONTADOR 

En nuestra clase en cassandra.php creamos el siguiente método:

  1. <?php
  2.  
  3. public function guardarContador($columnFamily, $key, $column, $value=1, $super_column=NULL){
  4.  
  5. try {
  6. $column_family = new ColumnFamily($this->conexion, $columnFamily);
  7. $column_family->add($row_key, $column, $value, $super_column);
  8. return true;
  9. }
  10. catch(Exception $e){
  11. return false;
  12. }
  13. }

Con este método podremos incrementar o disminuir el contador.


$columnFamily
: Es el nombre de la column family donde se encuentra el contador a modificar.

$key: Clave del registro donde se encuentra el contador.
$column: Nombre del contador.
$value: Valor a añadir al contador.
$super_column: Nombre de la super column donde se encuentra el contador.

Añadimos el siguiente código a nuestro archivo test.php:

  1. <?php
  2.  
  3. if ( $cass->guardarContador('column_family_counter', 'post', 'num_total_post', 1)){
  4. print "El contador se ha actualizado correctamente<br />";
  5. }else{
  6. print "Error al actualizar el contador<br />";
  7. }
  8.  
  9. $result = $cass->obtener('column_family_counter', 'post');
  10.  
  11. print_r($result);

Como ves, para recuperar un contador se utiliza el mismo método que para obtener cualquier otro registro. El resultado de este código sería:

El contador se ha actualizado correctamente
Array ( [num_total_post] => 1 )

 

PONER A CERO EL CONTADOR

Para poner a cero un contador hay que restarle el valor que tenga en ese momento el contador. En test.php escribiríamos lo siguiente:

  1. <?php
  2.  
  3. if ( $cass->guardarContador('column_family_counter', 'post', 'num_total_post', ($result['num_total_post']*-1))){
  4. print "El contador se ha actualizado correctamente<br />";
  5. }else{
  6. print "Error al actualizar el contador<br />";
  7. }
  8.  
  9. $result = $cass->obtener('column_family_counter', 'post');
  10.  
  11. print_r($result);

Y el resultado:

El contador se ha actualizado correctamente
Array ( [num_total_post] => 0 )

 

INDICES SECUNDARIOS

Los indices secundarios son un objeto especial en Cassandra que nos permite realizar búsquedas por columnas concretas.

Estos índices solo funcionan en las column family standard, con lo que su uso se ve bastante limitado.

 

 

CREAR UN INDICE SECUNDARIO

Para ello vamos a nuestro Cassandra Cluster Admin y en la column family my_column_family_standard pulsamos en Create Secondary Index:

Detalle de la ubicación del botón Create Secondary Index

Detalle de la ubicación del botón Create Secondary Index

– Nos aparecerá el siguiente formulario:

Detalle del formulario para crear un índice secundario

Detalle del formulario para crear un índice secundario

– Para nuestro cometido vamos a crear el siguiente índice secundario:

Formulario con los datos para el ejemplo

Formulario con los datos para el ejemplo

–  Pulsamos en Add Secondary Index.

 

REALIZAR UNA CONSULTA CON UN INDICE SECUNDARIO 

Nos vamos a nuestro archivo cassandra.php y añadimos el siguiente método:

  1. <?php
  2.  
  3. public function obtenerPorIndices($columnFamily, $arrayColumnsValues, $rangeStart = "", $columnCount = 100, $ordenar = true){
  4.  
  5. try{
  6. // Creamos el objeto
  7. $column_family = new ColumnFamily($this->conexion, $columnFamily);
  8.  
  9. // Inicializamos las variables
  10. $index_exp = array();
  11. $registros = array();
  12.  
  13. // Creamos un array de index_expression
  14. foreach($arrayColumnsValues as $key => $value){
  15. $index_exp[] = CassandraUtil::create_index_expression($key, $value);
  16. }
  17.  
  18. // Creamos la index_clause
  19. $index_clause = CassandraUtil::create_index_clause($index_exp, $rangeStart, $columnCount);
  20.  
  21. // Recuperamos los registros
  22. $rows = $column_family->get_indexed_slices($index_clause, NULL, $rangeStart, '', $ordenar, $columnCount);
  23.  
  24. return $rows;
  25. }catch (Exception $e){
  26. return false;
  27. }
  28. }

Con este método podremos buscar registros con varios índices secundarios.

Lo primero que hacemos en este método es crear el objeto ColumnFamily que nos proveerá de los métodos para hacer la consulta con indices secundarios. A continuación inicializamos varias variables necesarias para el método.

Dentro de un bucle creamos un array de index_expression(). Este objeto le indicará a Cassandra qué indices y con qué valores se deben buscar los registros.

Seguidamente creamos la index_clause(), que nos permite indicarle la key desde la que comenzará a recuperar registros y el número de registros a obtener.

Por último recuperamos los registros utilizando el método get_indexed_slices().

Para probar el método vamos a crear datos de prueba en test.php y haremos la consulta:

  1. <?php
  2.  
  3. $data[] = array(
  4. 'title' => 'Apache Cassandra',
  5. 'license' => 'Open Source',
  6. 'category' => 'no-sql',
  7. );
  8.  
  9. $data[] = array(
  10. 'title' => 'MongoDB',
  11. 'license' => 'Open Source',
  12. 'category' => 'no-sql',
  13. );
  14.  
  15. $data[] = array(
  16. 'title' => 'MySQL',
  17. 'license' => 'Open Source',
  18. 'category' => 'sql',
  19. );
  20.  
  21. foreach($data as $key => $value){
  22. $cass->guardar('my_column_family_standard', $key, $value);
  23. }
  24.  
  25. $arrayColumnsValues = array(
  26. 'category' => 'no-sql',
  27. );
  28.  
  29. $result = $cass->obtenerPorIndices('my_column_family_standard', $arrayColumnsValues);
  30.  
  31. print_r($result);

Si ejecutamos el código anterior Cassandra nos devolverá:

Array ( [0] => Array ( [title] => Apache Cassandra [license] => Open Source [category] => no-sql ) [1] => Array ( [title] => MongoDB [license] => Open Source [category] => no-sql ) )

Con este post concluye la parte básica de phpCassa, Cassandra y Cassandra Cluster Admin. En el próximo post y siguientes trataré varios temas que se han quedado un poco colgados o faltan por explicar como ordenar registros, cómo crear claves, mejorar el rendimiento de Cassandra, crear clusters, etc.

 

Logo Cassandra

Cassandra y PHP para desarrolladores SQL: PHPCassa (I)

10

¡Por fin llego el día! ¡Hoy toca programar!

Para ello vamos a utilizar el cliente de alto nivel PHPCassa que nos ahorrará bastante tiempo para trabajar con Cassandra. Puedes descargarlo desde https://github.com/thobbs/phpcassa.

Ubicamos phpCassa en una carpeta dentro de nuestro servidor web y creamos dos archivos. Yo los he llamado test.php y cassandra.php, El segundo será una clase que nos ahorrará algunas lineas de código con las tareas habituales. El primero lo utilizaré para testear la clase y sus respectivos métodos.

Bien empecemos.

 

PRIMEROS PASOS

En primer lugar necesitamos incluir dos archivos de phpCassa en cassandra.php:

  1. <?php
  2.  
  3. // CLASES NECESARIAS PARA CONECTAR CON CASSANDRA
  4. require_once('phpcassa/connection.php');
  5. require_once('phpcassa/columnfamily.php');

El primero de ellos dispone de los métodos para conectar con Cassandra a través de Thirft; el segundo tiene los métodos para trabajar con las column families.

Justo debajo creamos la clase:

  1. <?php
  2.  
  3. class cassandra {
  4.  
  5. }

 

CONECTANDO

Para realizar la conexión a la BD, phpCassa nos pide tan solo un dato obligatorio: el nombre del keyspace con el que vamos a trabajar. También nos permite añadir las ips de los nodos con los que queramos trabajar, aunque por defecto su valor es localhost. Por tanto podemos crear un constructor como el siguiente:

  1. <?php
  2.  
  3. function __construct($keyspace, $nodos = array('localhost')){
  4. if (!empty($keyspace)){
  5. $this->conexion = new ConnectionPool($keyspace, $nodos);
  6. }else{
  7. print "El keyspace está vacío";
  8. }
  9. }

Este constructor nos permite indicarle a la clase el keyspace con el que queremos trabajar y la ip o nombre de servidor donde se encuentre nuestra instancia de Cassandra. Por defecto el puerto al que se va a conectar es el 9160. Si hubieses configurado Cassandra para escuchar en otro puerto deberás especificarlo: localhost:9160.

Este código nos crea una variable llamada conexion que contendrá el objeto ConnectionPool, necesario para todas las consultas a la BD

 

GUARDANDO REGISTROS

Ahora procedemos a crear el método que guardará los registros. Para ello primero crearemos un objeto ColumnFamily al que le pasaremos el nombre de la column family en la que queremos trabajar:

  1. <?php
  2.  
  3. public function guardar($columnFamily, $key, $data = array()){
  4. try {
  5. $column_family = new ColumnFamily($this->conexion, $columnFamily);
  6. $column_family->insert($key, $data);
  7. return true;
  8. }catch(Exception $e){
  9. return false;
  10. }
  11. }

Este método nos devolverá true si se ha guardado correctamente el registro, o false en caso de error.
Como puedes ver, al objeto ColumnFamily se le pasa como primer parámetro el objeto ConnectionPool que creamos en el constructor, después se le pasa el nombre de la column family.
Una vez creado el objeto ColumnFamily ya podemos utilizar el método insert para guardar el registro pasándole como parámetros la key y un array con las columnas y sus respectivos valores.

 

RECUPERANDO REGISTROS

Recuperar registros de Cassandra es algo más complejo que guardarlos:

  1. <?php
  2.  
  3. public function obtener($columnFamily, $key, $super_column=NULL, $columns= NULL, $range_start = "", $column_count = 100, $invertir_orden=false){
  4.  
  5. try{
  6. $column_family = new ColumnFamily($this->conexion, $columnFamily);
  7. $result = $column_family->get($key, $columns, $range_start, "", $invertir_orden, $column_count, $super_column);
  8. }catch(Exception $e){
  9. return false;
  10. }
  11.  
  12. return $result;
  13.  
  14. }

Este método tiene algunos parámetros más que al guardar, pero tienen su razón de ser:

$columnFamily: Nombre de la column family donde buscar.
$key: Clave del registro donde buscar.
$super_column: Key o clave de la super column que se debe buscar. No es obligatorio. Por defecto NULL.
$columns: Columnas a buscar. No es obligatorio. Por defecto NULL.
$range_start: Key por la que Cassandra debe empezar a recuperar registros. No es obligatorio. Por defecto «».
$column_count: Número de registros a obtener, Por defecto 100.
$invertir_orden: Invierte el orden en el que se recuperar los registros. De mayor a menor o viceversa, de la A-Z o viceversa, etc.

Como ves tienes bastantes opciones para recuperar registros. Este método devuelve un array con los registros.

 

PROBANDO LA CLASE

Vamos a probar el código a ver que tal funciona. Nos vamos al archivo test.php y escribimos el siguiente código:

  1. <?php
  2.  
  3. include_once "cassandra.php";
  4.  
  5. $cass = new cassandra('my_keyspace', array('192.168.1.10'));
  6.  
  7. $data = array(
  8. 'nombre' => 'pepito',
  9. 'ciudad' => 'Madrid',
  10. 'vehiculo' => 'coche',
  11. );
  12.  
  13. if ( $cass->guardar('my_column_family_standard', 1, $data)){
  14. print "El registro se ha guardado correctamente<br />";
  15. }else{
  16. print "Error al guardar el registro<br />";
  17. }
  18.  
  19. $result = $cass->obtener('my_column_family_standard', 1);
  20.  
  21. print_r($result);
  22. ?>

Explico un poco el código anterior:

  1. Incluimos la clase en el archivo.
  2. Creamos el objeto indicándole el keyspace con el que trabajar (my_keyspace), y dentro de un array, la ip donde se encuentra en nodo de Cassandra. Si tuvieses Cassandra instalado en localhost no sería necesario indicar el segundo parámetro.
  3. Creamos el array que contendrá los datos a guardar.
  4. Creamos un condicional que guardará los datos en Cassandra y nos indicará si se han guardado correctamente o ha habido algún error.
  5. Guardamos en una variable ($result) los registros que recuperamos a través del método obtener del objeto $cass. A este método le indicamos la column family a buscar y la key a obtener.
  6. Mostramos los registros.

Si todo ha salido correctamente verás un texto como el siguiente cuando ejecutes el script:

El registro se ha guardado correctamente
Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche )

Si te aparecen más registros es posible que no vaciases las column family con la que trabajas. Simplemente ves a cassAdmin, entra en la column family y pulsa en Truncate Column Family. Así eliminarás todos los datos de la column family.

 

ACTUALIZAR UN REGISTRO

Ahora que ya funciona nuestra clase podemos ampliarla con nuevas características.
Aunque pienses que para actualizar un registro es necesario un nuevo método, en Cassandra no es necesario, simplemente utilizaremos el método guardar indicandole la key a modificar y el array con los datos a guardar.

Justo debajo del código que ya tenemos en el archivo test.php escribimos lo siguiente:

  1. <?php
  2.  
  3. $data = array(
  4. 'ciudad' => 'Barcelona',
  5. );
  6.  
  7. if ( $cass->guardar('my_column_family_standard', 1, $data)){
  8. print "El registro se ha guardado correctamente<br />";
  9. }else{
  10. print "Error al guardar el registro<br />";
  11. }
  12.  
  13. $result = $cass->obtener('my_column_family_standard', 1);
  14.  
  15. print_r($result);

Como observarás el array no tiene todos los datos de la key que vamos a modificar, ya que no es necesario, tan solo pasaremos los datos que queremos actualizar. El resultado de este código es el siguiente:

El registro se ha guardado correctamente
Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche )
El registro se ha guardado correctamente
Array ( [ciudad] => Barcelona [nombre] => pepito [vehiculo] => coche )

La columna ciudad a cambiado, el resto sigue igual, la razón está en que cuando le pasas a Cassandra una key que ya existe, lo que hace es actualizar las columnas que se correspondan con las keys del array. Si en ese array hubiera keys que no existen como columnas en el registro, Cassandra simplemente las crearía nuevas.

 

GUARDANDO UNA SUPER COLUMN

Aquí tampoco nos hace falta crear un nuevo método ya que nos sirve perfectamente el método guardar.

Añadimos el siguiente código a nuestro archivo test.php:

  1. <?php
  2.  
  3. $data = array('vecino_1' => array(
  4. 'nombre' => 'pepito',
  5. 'ciudad' => 'Madrid',
  6. 'vehiculo' => 'coche',
  7. ));
  8.  
  9. if ( $cass->guardar('my_column_family_super', 1, $data)){
  10. print "El registro se ha guardado correctamente<br />";
  11. }else{
  12. print "Error al guardar el registro<br />";
  13. }
  14.  
  15. $result = $cass->obtener('my_column_family_super', 1);
  16.  
  17. print_r($result);

El único cambio además del nombre de la column family donde vamos a guardar el registro, se encuentra en el array con los datos. Este tiene un elemento que es la key de la super column, y como valor, el array de las columns a guardar.

Si ejecutamos el código anterior nos devolverá lo siguiente:

El registro se ha guardado correctamente
Array ( [vecino_1] => Array ( [ciudad] => Madrid [nombre] => pepito [vehiculo] => coche ) )

 

ACTUALIZANDO UN SUPER COLUMN

La actualización de una super column se limita a las columnas que contienen los valores del registro no a su key. Si modificáramos la key , lo que en realidad estaríamos haciendo sería crear una nueva super column. Añadimos el siguiente código a nuestro archivo test.php:

  1. <?php
  2.  
  3. $data = array('vecino_1' => array(
  4. 'nombre' => 'pepito',
  5. 'ciudad' => 'Barcelona',
  6. 'vehiculo' => 'coche',
  7. ));
  8.  
  9. if ( $cass->guardar('my_column_family_super', 1, $data)){
  10. print "El registro se ha guardado correctamente<br />";
  11. }else{
  12. print "Error al guardar el registro<br />";
  13. }
  14.  
  15. $result = $cass->obtener('my_column_family_super', 1);
  16.  
  17. print_r($result);

Y el resultado es:

El registro se ha guardado correctamente
Array ( [vecino_1] => Array ( [ciudad] => Barcelona [nombre] => pepito [vehiculo] => coche ) )

 

ELIMINAR REGISTROS

Sí, aquí toca crear un nuevo método para nuestra clase en cassandra.php, aunque tampoco nos vamos a matar programando:

  1. <?php
  2.  
  3. public function eliminar($columnFamily, $key, $super_column = null){
  4.  
  5. try{
  6. $column_family = new ColumnFamily($this->conexion, $columnFamily);
  7. $column_family->remove($key, null, $super_column);
  8. return true;
  9. }catch(Exception $e){
  10. return false;
  11. }
  12. }

El método es bastante sencillo: se le pasan tres parámetros que ya conocemos.

Dentro del método se crea un objeto ColumnFamily y se utiliza el método remove para eliminar el registro pasándole la key correspondiente, y si fuese una super column, la key de este.
Observarás que el segundo parámetro del método remove tiene un valor null, en él se pueden añadir como array los nombres de las columnas a eliminar. Como no es habitual ese proceso he creído adecuado dejarlo como null.

Una vez añadido esté método a nuestra clase modificamos el archivo test.php con el siguiente código:

  1. <?php
  2.  
  3. if ( $cass->eliminar('my_column_family_standard', 1)){
  4. print "El registro se ha eliminado correctamente<br />";
  5. }else{
  6. print "Error al eliminar el registro<br />";
  7. }
  8.  
  9. $result = $cass->obtener('my_column_family_standard', 1);
  10.  
  11. print_r($result);

Y el resultado es:

El registro se ha eliminado correctamente

 

De momento con esto es suficiente, dejo en tus manos estos métodos para que juegues con ellos todo lo que quieras y te familiarices con phpCassa.

En el próximo post trataré las Counter Columns que nos servirán para contar registros, los Secondary Index que nos permitirán realizar búsquedas por columnas concretas, y algunas cosas más.

Symfony: El modelo (II)

0

Cuando Symfony construye el modelo, crea una clase de objeto base para cada una de las tablas definidas en schema.yml. Cada una de estas clases contiene una serie de constructores y accesores por defecto en función de la definición de cada columna: los métodos new, getXXX() y setXXX() (donde XXX es el nombre del campo) permiten crear y obtener las propiedades de los objetos:

  1. <?php
  2.  
  3. $articulo = new Articulo();
  4. $articulo->setTitulo('Mi primer artículo');
  5. $articulo->setContenido('Este es mi primer artículo. \n Espero que te guste.');
  6.  
  7. $titulo = $articulo->getTitulo();
  8. $contenido = $articulo->getContenido();

 

Para establecer el valor de varios campos a la vez, se puede utilizar el método fromArray(), que también se genera para cada clase objeto:

  1. <?php
  2.  
  3. $articulo->fromArray(array(
  4. 'titulo' => 'Mi primer artículo',
  5. 'contenido' => 'Este es mi primer artículo. \n Espero que te guste.'
  6. ));
  1. <?php
  2.  
  3. // Relación de "muchos a uno"
  4. echo $comentario->getArticulo()->getTitulo();
  5. => Mi primer artículo
  6. echo $comentario->getArticulo()->getContenido();
  7. => Este es mi primer artículo.
  8. Espero que te guste.
  9.  
  10. // Relación "uno a muchos"
  11. $comentarios = $articulo->getComentarios();

La columna articulo_id de la tabla blog_comentario define implícitamente una clave externa a la tabla blog_articulo. Cada comentario está relacionado con un artículo y un artículo puede tener muchos comentarios. Las clases generadas contienen 5 métodos que traducen esta relación a la forma orientada a objetos, de la siguiente manera:

  • $comentario->getArticulo(): para obtener el objeto Articulo relacionado
  • $comentario->getArticuloId(): para obtener el ID del objeto Articulo relacionado
  • $comentario->setArticulo($articulo): para definir el objeto Articulo relacionado
  • $comentario->setArticuloId($id): para definir el objeto Articulo relacionado a partir de un ID
  • $articulo->getComentarios(): para obtener los objetos Comentario relacionados
  1. <?php
  2.  
  3. $comentario = new Comentario();
  4. $comentario->setAutor('Steve');
  5. $comentario->setContenido('¡Es el mejor artículo que he leído nunca!');
  6.  
  7. // Añadir este comentario al anterior objeto $articulo
  8. $comentario->setArticulo($articulo);
  9.  
  10. // Sintaxis alternativa
  11. // Solo es correcta cuando el objeto artículo ya
  12. // ha sido guardado anteriormente en la base de datos
  13. $comentario->setArticuloId($articulo->getId());

El método getArticulo() devuelve un objeto de tipo Articulo, que permite utilizar el método accesor getTitulo(). Se trata de una alternativa mucho mejor que realizar la unión de las tablas manualmente, ya que esto último necesitaría varias líneas de código (empezando con la llamada al método $comment->getArticuloId()).

La variable $comentarios contiene un array de objetos de tipo Comentario. Se puede mostrar el primer comentario mediante $comentarios[0] o se puede recorrer la colección entera mediante foreach ($comentarios as $comentario).

Al utilizar el constructor new se crea un nuevo objeto, pero no un registro en la tabla blog_articulo. Si se modifica el objeto, tampoco se reflejan esos cambios en la base de datos. Para guardar los datos en la base de datos, se debe invocar el método save() del objeto.

  1. <?php
  2.  
  3. $articulo->save();
  1. <?php
  2.  
  3. foreach ($articulo->getComentarios() as $comentario)
  4. {
  5. $comentario->delete();
  6. }

Si se conoce la clave primaria de un registro concreto, se puede utilizar el método retrieveByPk() de la clase peer para obtener el objeto relacionado.

  1. <?php
  2.  
  3. $articulo = ArticuloPeer::retrieveByPk(7);

En algunos casos, la clave primaria está formada por más de una columna. Es esos casos, el método retrieveByPK() permite indicar varios parámetros, uno para cada columna de la clave primaria.

También se pueden obtener varios objetos a la vez mediante sus claves primarias, invocando el método retrieveByPKs(), que espera como argumento un array de claves primarias.

 

Cuando se quiere obtener más de un registro, se debe utilizar el método doSelect() de la clase peer correspondiente a los objetos que se quieren obtener. Por ejemplo, para obtener objetos de la clase Articulo, se llama al método ArticuloPeer::doSelect().

El primer parámetro del método doSelect() es un objeto de la clase Criteria, que es una clase para definir consultas simples sin utilizar SQL, para conseguir la abstracción de base de datos.

Un objeto Criteria vacío devuelve todos los objetos de la clase.

  1. <?php
  2.  
  3. $c = new Criteria();
  4. $articulos = ArticuloPeer::doSelect($c);
  5.  
  6. // Genera la siguiente consulta SQL
  7. SELECT blog_articulo.ID, blog_articulo.TITLE, blog_articulo.CONTENIDO,
  8. blog_articulo.CREATED_AT
  9. FROM blog_articulo;

Para las selecciones más complejas de objetos, se necesitan equivalentes a las sentencias WHERE, ORDER BY, GROUP BY y demás de SQL. El objeto Criteria dispone de métodos y parámetros para indicar todas estas condiciones. Por ejemplo, para obtener todos los comentarios escritos por el usuario Steve y ordenados por fecha:

  1. <?php
  2.  
  3. $c = new Criteria();
  4. $c->add(ComentarioPeer::AUTOR, 'Steve');
  5. $c->addAscendingOrderByColumn(ComentarioPeer::CREATED_AT);
  6. $comentarios = ComentarioPeer::doSelect($c);
  7.  
  8. // Genera la siguiente consulta SQL
  9. SELECT blog_comentario.ARTICULO_ID, blog_comentario.AUTOR, blog_comentario.CONTENIDO,
  10. blog_comentario.CREATED_AT
  11. FROM blog_comentario
  12. WHERE blog_comentario.autor = 'Steve'
  13. ORDER BY blog_comentario.CREATED_AT ASC;

as constantes de clase que se pasan como parámetros a los métodos add() hacen referencia a los nombres de las propiedades. Su nombre se genera a partir del nombre de las columnas en mayúsculas. Por ejemplo, para indicar la columna contenido de la tabla blog_articulo, se utiliza la constante de clase llamada ArticuloPeer::CONTENIDO.

Otro ejemplo del uso de Criteria con condiciones múltiples. En el ejemplo se obtienen todos los comentarios del usuario Steve en los artículos que contienen la palabra enjoy y además, ordenados por fecha.

 

  1. <?php
  2.  
  3. $c = new Criteria();
  4. $c->add(ComentarioPeer::AUTOR, 'Steve');
  5. $c->addJoin(ComentarioPeer::ARTICULO_ID, ArticuloPeer::ID);
  6. $c->add(ArticuloPeer::CONTENIDO, '%enjoy%', Criteria::LIKE);
  7. $c->addAscendingOrderByColumn(ComentarioPeer::CREATED_AT);
  8. $comentarios = ComentarioPeer::doSelect($c);
  9.  
  10. // Genera la siguiente consulta SQL
  11. SELECT blog_comentario.ID, blog_comentario.ARTICULO_ID, blog_comentario.AUTOR,
  12. blog_comentario.CONTENIDO, blog_comentario.CREATED_AT
  13. FROM blog_comentario, blog_articulo
  14. WHERE blog_comentario.AUTOR = 'Steve'
  15. AND blog_articulo.CONTENIDO LIKE '%enjoy%'
  16. AND blog_comentario.ARTICULO_ID = blog_articulo.ID
  17. ORDER BY blog_comentario.CREATED_AT ASC

Además del método doSelect(), todas las clases peer tienen un método llamado doCount(), que simplemente cuenta el número de registros que satisfacen las condiciones pasadas como parámetro y devuelve ese número como un entero.

Las clases peer también incluyen métodos doDelete(), doInsert() y doUpdate() (todos ellos requieren como parámetro un objeto de tipo Criteria).

Por último, si solo se quiere obtener el primer objeto, se puede reemplazar el método doSelect() por doSelectOne(). Es muy útil cuando se sabe que las condiciones de Criteria solo van a devolver un resultado, y su ventaja es que el método devuelve directamente un objeto en vez de un array de objetos.

A veces, no es necesario obtener los objetos, sino que solo son necesarios algunos datos calculados por la base de datos. Por ejemplo, para obtener la fecha de creación de todos los artículos, no tiene sentido obtener todos los artículos y después recorrer el array de los resultados.

Para realizar consultas a la base de datos con PDO, es necesario realizar los siguientes pasos:

  • Obtener la conexión con la base de datos.
  • Construir la consulta.
  • Crear una sentencia con esa consulta.
  • Iterar el result set que devuelve la ejecución de la sentencia.
  1. <?php
  2.  
  3. conexion = Propel::getConnection();
  4. $consulta = 'SELECT MAX(%s) AS max FROM %s';
  5. $consulta = sprintf($consulta, ArticuloPeer::CREATED_AT, ArticuloPeer::TABLE_NAME);
  6. $sentencia = $conexion->prepare($consulta);
  7. $sentencia->execute();
  8. $resultset = $sentencia->fetch(PDO::FETCH_OBJ);
  9. $max = $resultset->max;

Normalmente, cuando una tabla tiene una columna llamada created_at, se utiliza para almacenar un timestamp de la fecha de creación del registro. La misma idea se aplica a las columnas updated_at, cuyo valor se debe actualizar cada vez que se actualiza el propio registro.

La buena noticia es que Symfony reconoce estos nombres de columna y se ocupa de actualizar su valor de forma automática. No es necesario establecer manualmente el valor de las columnas created_at y updated_at; se actualizan automáticamente. Lo mismo se aplica a las columnas llamadas created_on y updated_on.

  1. <?php
  2.  
  3. $comentario = new Comentario();
  4. $comentario->setAutor('Steve');
  5. $comentario->save();
  6.  
  7. // Muestra la fecha de creación
  8. echo $comentario->getCreatedAt();
  9. => [fecha de la operación INSERT de la base de datos]

Además, los getters de las columnas de fechas permiten indicar el formato de la fecha como argumento:

  1. <?php
  2.  
  3. echo $comentario->getCreatedAt('Y-m-d');

 

Ir arriba