Conectar Symfony2 con OpenERP

1. Que es Symfony y su instalación

Symfony es un framework de muy potente para desarrollo de aplicaciones web en el lenguaje de programación Php. Esta basado en el patrón Modelo Vista Controlador y proporciona un conjunto de herramientas para facilitar los desarrollos web complejos.
El siguiente documento muestra como realizar una instalación de Symfony nueva y realizar la conexión a Openerp.

1.1. Instalación de LAMP

LAMP son las siglas de linux apache mysql php. Symfony necesita de un servidor LAMP para poder funcionar. A continuación veremos como instalar un servidor LAMP en nuestro sistema. En primer lugar instalaremos apache:

$ sudo apt-get install apache2

Posteriomente instalamos php:

$ sudo apt-get install php5 libapache2-mod-php5 php-cli php-mysql

y reiniciamos apache:

$ sudo service apache2 restart

por último instalamos mysql:

$ sudo apt-get install mysql-server mysql-client libmysqlclient-dev

durante el proceso de instalación nos pedirá que asignemos contraseña al usuario root de mysql.

Adicionalmente, podemos instalar también phpmyadmin para ayudarnos con la configuración de mysql:

$ sudo apt-get install phpmyadmin

y creamos un enlace simbólico para acceder:

$ sudo ln -s /usr/share/phpmyadmin /var/www

Ahora podremos acceder mediante la url 192.168.0.122/phpmyadmin.

1.2. Instalación de composer

Composer es un gestor de dependencias para un proyecto php. Para instalar composer primero debemos instalar curl

$ sudo apt-get install curl

Posteriomente instalamos composer:

$ curl -s https://getcomposer.org/installer | php

Si todo ha funcionado bien, en el directorio donde te encuentras veras un nuevo fichero llamado composer.phar. Para comprobar que se ha instalado correctamente, ejecuta el siguiente comando que muestra el menú de opciones de Composer:

$ php composer.phar

Instalar Composer de esta manera es correcto, pero te obliga a realizar una nueva instalación para cada proyecto Symfony2. Si tienes muchos proyectos, es mucho mejor que instales Composer de forma global en tu ordenador, para que todos los proyectos utilicen la misma versión de Composer.

Para instalar Composer globalmente, mueve el archivo composer.phar a algún directorio ejecutable del sistema, como por ejemplo:

$ sudo mv composer.phar /usr/local/bin/composer

Comprueba que todo funciona bien ejecutando el comando composer sin opciones desde cualquier directorio del sistema. La instalación global de Composer también facilita su mantenimiento, ya que sólo hay que ejecutar el siguiente comando para actualizar la versión de Composer de todos los proyectos:

$ sudo composer self-update

1.3. Instalación de Symfony

Gracias a composer la instalación de Symfony se reduce a un simple comando de consola:

php composer.phar create-project symfony/framework-standard-edition nuestra_ruta/ 2.3.6

por ejemplo:

php composer.phar create-project symfony/framework-standard-edition /home/user/openerp/ 2.3.6

En caso de haber instalado composer globalmente:

composer create-project symfony/framework-standard-edition nuestra_ruta/ 2.3.6

El proceso de instalación nos ira pidiendo los datos de configuración de nuestro servidor. Podemos introducirlos en el momento o introducirlos a mano en el fichero app/config/parameters.yml

Una vez instalado, hay que borrar el bundle AcmeDemo:

Eliminar carpeta AcmeBundle de src
Eliminar $bundles[] = new AcmeDemoBundleAcmeDemoBundle(); del fichero app/AppKernel.php
Eliminar bloque referente AcmeDemo en app/config/routing_dev.yml

2. Conectar Symfony con OpenErp

Ya tenemos instalado Symfony en nuestro sistema, ahora vamos a ver como realizar la conexión con nuestro OpenErp.

2.1. Crear bundle conexión OpenERP

Un bundle se Symfony es el equivalente de un módulo de OpenERP, contiene todos los ficheros que proporcionan una nueva funcionalidad a nuestra aplicación web.

Para generar un bundle, debemos ejecutar en el directorio de nuestro proyecto Symfony:

$ php app/console generate:bundle

Esto nos mostrara un asistente para generar nuestro bundle:

Bundle Namespace: Openerp/ConnectBundle
Bundle Name: ConnectBundle
Target directory: Pulsamos enter (valor por defecto)
Configuration format: yml
Do you want to generate the whole directory structure?: pulsamos enter (valor por defecto)
Do you confirm generator?: pulsamos enter (valor por defecto)
Confirm automatic update of your kernel?: Pulsamos enter (valor por defecto)

Si vamos a la carpeta src de nuestro proyecto, podremos ver como se ha generado el nuevo Bundle, OpenERP.

connect

2.2. Generar entidad datos OpenERP

Una opción de configuración que podemos utilizar para no tener que introducir los datos de conexión en cada acceso, es generar una entidad de conexión a OpenERP para almacenar los parámetros de conexión. Una entidad es un fichero php que se encarga de interactuar con la base de datos de nuestro proyecto.

Para generar esta entidad debemos ejecutar en el directorio de nuestro proyecto Symfony el siguiente comando:

$ php app/console doctrine:generate:entity

Esto nos mostrara un asistente para generar nuestra entidad:

The Entity shortcut name: ConnectBundle:OpenERP
Configuration format (yml, xml, php, or annotation) [annotation]: pulsamos enter 

New field name (press  to stop adding fields): server
Field type [string]: pulsamos enter
Field length [255]: 100

New field name (press  to stop adding fields): bda
Field type [string]: pulsamos enter
Field length [255]: 100

New field name (press  to stop adding fields): username
Field type [string]: pulsamos enter
Field length [255]: 100

New field name (press  to stop adding fields): password
Field type [string]: pulsamos enter
Field length [255]: 255

New field name (press  to stop adding fields): pulsamos enter

Do you want to generate an empty repository class [no]? No 

Do you confirm generation [yes]? Yes

Con esto ya hemos generado el código de nuestra endidad, el cual podremos ver en la carpeta Entity de nuestro bundle.

Si queremos mapear esta entidad con nuestra base de datos, debemos ejecutar el siguiente comando en la consola:

$ php app/console doctrine:schema:create

Una vez creada la entidad, podemos crear datos de conexión para nuestra entidad mediante el phpmyadmin indicando la url de nuestro servidor, la base de datos a la cual nos vamos a conectar, el usuario y la contraseña.

2.3. Generar controlador OpenERP

Un controlador es un fichero que incluye la funcionalidad de nuestro bundle. Normalmente un controlador accede a la entidad de nuestro bundle, para acceder a la información de nuestra base de datos, y devuelve una vista, que muestra en pantalla esta información. Vamos a generar un controlador nuevo para conectar a OpenERP.

El primer paso sería descargar la liberia de conexion a OpenERP de la siguiente url https://github.com/tejastank/openerp-php-connector e incluirla en la carpeta controller de nuestro bundle.

require_once __DIR__.'/openerp/openerp.class.php';

En este ejemplo la libreria de conexión a OpenERP se ha guardado en la carpeta openerp del controlador.

Con todo esto, podemos desarrollar nuestra conexión simple mediante el siguiente controlador:

<?php
    namespace OpenerpConnectBundleController;

    use SymfonyBundleFrameworkBundleControllerController;
    use OpenerpConnectBundleEntityOpenerp;
    use SymfonyComponentHttpFoundationRequest;

   require_once __DIR__.'/openerp/openerp.class.php';

   class DefaultController extends Controller
   {

       public function indexAction($name)
        {
           return $this->render('ConnectBundle:Default:index.html.twig', array('name' => $name));
       }

       public function loginAction(Request $request)
       {

           $openerp = new Openerp();
           $form = $this->createFormBuilder($openerp)
             ->add('username', 'text')
             ->add('password', 'password')
             ->getForm();

           if ($request->isMethod('POST')) 
           {
                $form->bind($request);
              if ($form->isValid()) 
              {
                    $em = $this->getDoctrine()->getManager();
                    $shop = $em->getRepository('ConnectBundle:Openerp')->findOneBy(array('id' => 1));
                 $rpc = new OpenERP();
                 $uid = $rpc->login($shop->getUsername(), $shop->getPassword(), $shop->getBda());
                 $name = $rpc->read(array($uid), array('name'), 'res.users');
                 return $this->render('ConnectBundle:Default:welcome.html.twig', array(
                    'name' => $name[0]['name'],));
              }
           }
          return $this->render('ConnectBundle:Default:login.html.twig', array(   
          'form' => $form->createView(),
            ));
       }
    }

Este controlador genera un formulario simple para introducir el usuario y contraseña de un usuario de OpenERP. Una vez validado el formulario, busca el nombre del usuario que se ha conectado y devuelve una página con el mensaje “Bienvenido” mas el nombre de este usuario.

Las vistas para este controlador son las que se devuelven en el return:

return $this->render('ConnectBundle:Default:login.html.twig', array('form' => $form->createView(),));
return $this->render('ConnectBundle:Default:welcome.html.twig', array('name' => $name[0]['name'],));

Y se deben crear en la carpeta Resources/views del bundle, conteniendo el siguiente código:

<!-- login.html.twig -->
<form action="{{ path('portada')}}" method="post" {{ form_enctype(form)}}>
{{ form_widget(form)}}
<input type="submit"/>
</form>
<!-- welcome.html.twig -->
<h1>Bienvenido {{ name}}</h1>

Por último, hay que crear el path del controlador. Para ello hay que añadir las siguientes líneas en el fichero routing.yml que se encuentra en la carpeta app/config de nuestro proyecto:

portada:
path: /
defaults: { _controller: ConnectBundle:Default:login}

Ahora si accedemos a 192.168.0.122/symfony/web/app_dev.php podremos ver nuestro formularío de acceso.

Con todo esto hemos conseguido generar un bundle de conexión a OpenERP que puede ser incluido en otros bundles facilitando con esto acceder a los datos de OpenERP.

3. Conexión OpenERP con Symfony

Symfony funciona como un servicio rest, el cual nos permite acceder a la información mediante una url que accede a un método definido en un controlador. A continuación veremos un ejemplo de como conectar OpenERP con Symfony.

En primer lugar vamos a crear un módulo de OpenERP que genere una vista con un boton que nos permita enviar todos los productos de nuestro sistema a Symfony.

Definimos la clase:

class symfony(osv.osv_memory):
 _name = 'symfony'
symfony()

Con su vista asociada:

<?xml version="1.0" encoding="UTF-8"?>
    <openerp>
        <data>
            <record id="sync_products_form" model="ir.ui.view">
                <field name="name">sync.products.form</field>
                <field name="model">symfony</field>
                <field name="type">form</field>
                <field name="arch"type="xml">
                    <form string = "Sync Products">
                        <button name="sync_products" string="Sync" type="object" icon="gtk-apply"/>
                    </form>
                </field>
           </record>
         <record id="action_sync_products" model="ir.actions.act_window">
              <field name="name">Sync Products</field>
              <field name="type">ir.actions.act_window</field>
              <field name="res_model">symfony</field>
              <field name="view_type">form</field>
              <field name="view_mode">form</field>
              <field name="view_id" ref="sync_products_form"/>
              <field name="target">new</field>
          </record>
          <menuitem id="menu_sync_product" name="Sync Products"
          parent="stock.menu_stock_product" sequence="6"
          action="action_sync_products"/>
      </data>
    </openerp>

Y el metódo de sincronización:

def sync_products(self, cr, uid, ids, context = None):
   product_obj = self.pool.get("product.template")
      product_ids = product_obj.search(cr, uid, [], context = context)
   products = []

   for product in product_obj.browse(cr, uid, product_ids, context = context):
       product_dict = {}
        product_dict['name'] = product.name
                product_dict['list_price'] = product.list_price
                product_dict['standard_price'] = product.standard_price
                product_dict['description'] = product.description
                products.append(product_dict)

    products_json = json.dumps(products)
    url = "http://192.168.0.122/symfony/web/app_dev.php/get_products"
        f = urllib2.urlopen(url, products_json)
    response = f.read()
    f.close()

Como podemos observar el método recupera todos los productos que tenemos en el sistema, los codifica en json y los envia al controlador get_products.

El siguiente paso seria definir este controlador en nuestro sistema Symfony:

public function get_productsAction()
{
    $em = $this->getDoctrine()->getManager(); 
    $products = json_decode($this->get('request')->getContent(), true);
        foreach ($products as $p)
       {
        $product = new Product();
                $product->setName($p['name']);
                $product->setListPrice($p['list_price']);
                $product->setStandardPrice($p['standard_price']);
                $product->setDescription($p['description']);
                $em->persist($product);
   }
   $em->flush();
      return new Response("ok");
}

Y añadirlo a nuestro routing.yml:

getProducts:
    path: /get_products
    defaults: { _controller: ConnectBundle:Default:get_products}

Como podemos observar en el código de nuestro controlador, existe una nueva entidad llamada Product que es la que se encarga de almacenar los productos. Para generarla utilizaremos la consola de Symfony:

$ php app/console doctrine:generate:entity

The Entity shortcut name: ConnectBundle:Product
Configuration format (yml, xml, php, or annotation) [annotation]: 
pulsamos enter

New field name (press  to stop adding fields): name
Field type [string]: 
pulsamos enter

Field length [255]: 
pulsamos enter

New field name (press  to stop adding fields): list_price
Field type [string]: decimal

New field name (press  to stop adding fields): standard_price
Field type [string]: decimal

New field name (press  to stop adding fields): description
Field type [string]: text

New field name (press  to stop adding fields): 
pulsamos enter

Do you want to generate an empty repository class [no]? 
pulsamos enter

Do you confirm generation [yes]? 
pulsamos enter

Por último, actualizamos el esquema de nuestra base de datos.

$ php app/console doctrine:schema:update --force

Con esto ya podemos ejecutar nuestro módulo de OpenERP y realizar la conexión que nos importara todos los productos.

productos

4. Conclusiones

Como hemos podido observar en este artículo, la conexión a OpenERP con Symfony es muy sencilla. Debemos incluir la librería de conexión de php a OpenERP en un nuevo bundle de conexión. Este nuevo bundle podra ser incluido en otros bundles facilitando con esto el acceso de Symfony a OpenErp.

En cuanto a la conexión de OpenErp con Symfony, también hemos podido comprobar que es bastante sencilla ya que Symfony actua como un servicio rest muy facil de acceder. Simplemente debemos llamar desde OpenErp al método de Symfony que queramos acceder.

En resumen, generar un nuevo proyecto web con Symfony que acceda a OpenERP es muy sencillo, lo cual nos permite generar proyectos como tiendas online mediante el respaldo de OpenERP.

5. Bibliografia

Symfony 2.3, el libro oficial.

http://librosweb.es/symfony_2_3/

Desarrollo web ágil con Symfony2
http://symfony.es/noticias/2013/08/27/desarrollo-web-agil-con-symfony-2-3/