Felicidades, ¡ya terminamos la programación de nuestra agenda CSV con PHP!

Ya casi hemos terminado nuestra agenda de contactos, ¡ánimo! Hoy vamos a ver cómo funciona la clase People que encapsula la lógica de negocio.

Diploma

Primero de todo, fíjate que People.php está dentro de la carpeta vendors. Esta carpeta sirve para poner plugins y otros componentes desarrollados por terceros, para no tener que reinventar la rueda cada vez que necesitamos incorporar una nueva funcionalidad a nuestras apps. Aquí podemos poner, por ejemplo, componentes para enviar emails por SMTP, para crear PDFs, subir archivos al servidor, etc.

Entonces, nosotros ponemos el componente AgendaPHPGuay en vendors porque nuestro objetivo a medio y largo plazo es desarrollar una agenda modular para poderla incorporar en cualquier aplicación.

Veamos cómo funciona el código de People.php

Te recuerdo que el código está disponible en este repo de GitHub.

<?php
namespace AgendaPHPGuay;
/**
 * People
 * 
 * Clase sencilla que implementa los métodos CRUD sobre un archivo CSV de 
 * personas con el siguiente formato:
 * 
 *      name,surname,email
 *      Marta,González,marta@hotmail.com
 *      Luis,Martín,luis@gmail.com
 *      Antonio,García,antonio@gmail.com
 *      María,López,maria@tuweb.com
 * 
 * La clave primara de estos datos es el campo email.
 * 
 * Esta clase pertenece al curso de programación PHP guay. Los objetivos son 
 * practicar Programación Orientada a Objetos y gestión de archivos CSV.
 *
 * @author Jordi Bassagañas <info@programarivm.com>
 * @copyright 2014 Jordi Bassagañas
 * @link http://programarivm.com
 */
class People
{
    /**
     * @var People Instancia Singleton
     */
    protected static $instance;
    /**
     * @var stdClass Representación del archivo CSV en memoria
     */
    protected $csv;
    /**
     * Método Singleton que devuelve la instancia de clase
     * @return People
     */
    static function getInstance($path)
    {
        if (!isset(self::$instance))
        {
            self::$instance = new self($path);            
        }
        return self::$instance;
    }
    /**
     * Método Singleton que impide la clonación del objeto
     */
    function __clone() {
        trigger_error( "Cannot clone instance of Singleton pattern.", E_USER_ERROR );
    }
    /**
     * Constructor que inicializa el CSV en memoria
     * @param string $path
     */
    protected function __construct($path)
    {        
        $this->csv = new \stdClass;
        $this->csv->path = $path;
        // Cargamos la cabecera y las personas del archivo CSV en memoria
        $fp = @fopen($this->csv->path, 'r') or die('The file cannot be opened');
        while (($row = fgetcsv($fp, 1024, ",")) !== false)
        {
            !isset($this->csv->header) 
                ? $this->csv->header = $row 
                : $this->csv->people[] = array_combine($this->csv->header, $row);
        }
        fclose($fp);   
    }
    /**
     * Devuelve el CSV cargado en memoria
     * @return array
     */
    function getCsv()
    {
        return $this->csv;
    }
    /**
     * Añade un nuevo contacto
     * @param array $person
     */
    function add(array $person)
    {        
        $this->csv->people[] = $person;
        return $this;
    }
    /**
     * Actualiza los datos de un contacto
     * @param array $person
     */
    function update(array $person)
    {        
        foreach($this->csv->people as $key => &$value)
        {
            if($value['email'] == $person['email'])
            {
                $value = $person;
                break;
            }
        }
        return $this;
    }
    /**
     * Borra un contacto
     * @param string $email
     */
    function delete($email)
    {
        foreach($this->csv->people as $key => &$value)
        {
            if($value['email'] == $email)
            {
                unset($this->csv->people[$key]);
                break;
            }
        }
        return $this;
    }
    /**
     * Escribe en el archivo CSV los datos cargados en memoria
     */
    function write()
    {
        if(!isset($this->csv->header)) 
            die('Write a CSV header in the file before adding a new contact');
        $fp = @fopen($this->csv->path, 'w') or die('The file cannot be opened');
        fputcsv($fp, $this->csv->header);
        foreach($this->csv->people as $person)
        {
            fputcsv($fp, $person);
        }
        fclose($fp);
    }
}

Jordi, ya he visto el código, ¿pero qué es eso de ahí que pone namespace?

Eso es la declaración de un espacio de nombres. Lo primero que hacemos es definir la clase dentro del espacio de nombres AgendaPHPGuay para que el nombre de nuestra clase People no interfiera con ningún otro nombre que pueda llamarse también así en la aplicación. Si no sabes muy bien cómo funcionan los namespaces PHP te recomiendo que veas este video.



Jordi, en el video has hablado de Singleton, ¿pero qué es eso?

Singleton es un patrón de diseño de software que sirve para asegurarnos que en cualquier momento de la ejecución del script solo habrá una instancia de la clase People.

Las partes del código que forman parte de la implementación Singleton son:

  • El atributo $instance.
  • El método getInstance.
  • El método __clone.

El atributo $instance guarda la instancia de People, que siempre podemos obtener por medio del método getInstance, como vimos en el video anterior.

getInstance es como una pregunta: ¿existe ya una instancia de People en memoria? Si la respuesta es afirmativa, el código la devuelve; en cambio, si no hay ninguna instancia de People, se crea en la misma llamada del método getInstance.

El método __clone es para impedir que se puedan clonar objetos de tipo People, por consistencia con Singleton, que dice que solo puede haber 1 objeto.

En todo caso, como hemos dicho solo puede haber 1 instancia de People durante la ejecución del script.

¿Qué es el atributo $csv?

Es un objeto stdClass (clase estándar de PHP) que almacena en memoria el contenido del archivo CSV. El contenido se carga en el método constructor de la clase.

Fíjate que $csv->header es un array que almacena los datos de la cabecera del archivo (nombre, apellido y email), y $csv->people es un array que guarda los datos de los contactos.

La idea es ir gestionando los datos en el array que está en la memoria (añadir, modificar y borrar contactos), a medida que lo necesita el programador, y luego al final escribir la información en el archivo CSV. Para esto último está el método write, que primero escribirá la cabecera, y luego los datos de los contactos.

Bien amigos, pues esto es todo por hoy. Os recuerdo que el código está disponible en GitHub. Si os gustó este artículo os invito a compartirlo con vuestros amig@s. Muchas gracias, ¡hasta otra!