¡HOLA! SOY DANIEL RUIZ

Soy desarrollador, maquetador, programador y technology learner en HTML, Javascript, PHP, Java y .NET.

30 agosto, 2017

Prestashop: Web service: aprende a crear una nueva función 3

Hola!

Sois varios los que me habéis preguntado sobre mis antiguos artículos (el primero y el segundo).

Vamos sobre el tema de los servicios web de Prestashop.

Recordemos que la estructura de ficheros que tenemos después de los otros artículos es esta:

 

 

Antes de empezar

Una aclaración: la api de Prestashop ya nos devuelve el objeto producto con las combinaciones pero con el identificador de la combinación:

http://url_tienda/api/products/1

            <combinations nodeType="combination" api="combinations">
                <combination xlink:href="http://localhost/PS16/api/combinations/1">
                    <id>
                        <![CDATA[1]]>
                    </id>
                </combination>
                <combination xlink:href="http://localhost/PS16/api/combinations/2">
                    <id>
                        <![CDATA[2]]>
                    </id>
                </combination>
                <combination xlink:href="http://localhost/PS16/api/combinations/3">
                    <id>
                        <![CDATA[3]]>
                    </id>
                </combination>
                <combination xlink:href="http://localhost/PS16/api/combinations/4">
                    <id>
                        <![CDATA[4]]>
                    </id>
                </combination>
                <combination xlink:href="http://localhost/PS16/api/combinations/5">
                    <id>
                        <![CDATA[5]]>
                    </id>
                </combination>
                <combination xlink:href="http://localhost/PS16/api/combinations/6">
                    <id>
                        <![CDATA[6]]>
                    </id>
                </combination>
            </combinations>

Esta vez crearemos una función para que nos devuelva datos de los productos de nuestra tienda: devolveremos todos los productos de nuestra tienda con sus combinaciones completas.

Manos a la obra

Parar este artículo vamos a crear clases nuevas que nos ayuden a conseguir el objetivo y, además, ayudarnos a entender los servicios web de Prestashop.

Llamaremos a esta funcionalidad extensión de la funcionalidad de un producto: ProductExtension (¿original no? :))

Queremos que nuestra URL sea así: http://url_tienda/api/productextension/funcion1 y nos devuelva un xml (formato por defecto ya que podemos hacer que nos devuelva los datos en JSON) con todos los productos de nuestra tienda con las combinaciones completas.

Queremos que nuestra clase solamente esté disponible para los servicios web y no haya ningún problema con ningún módulo ni con el sitio en general. Esto significa que no sobreescribimos la clase original Product sino que creamos otra clase totalmente distinta. Es decir no creamos la clase con el fichero /overrides/classes/Product.php.

class Product extends ProductCore
{

Si tenéis alguna duda de lo que estoy hablando leeros mis antiguos posts donde hablo sobre los overrides en Prestashop.

Creando nuestra clase ProductExtension

Ahí va todo el código de la clase. La explicaré a continuación.

class ProductExtension extends ProductCore
{
	public function __construct(
		$id_product = null,
		$full = false,
		$id_lang = null,
		$id_shop = null,
		Context $context = null
	) {

		$this->webserviceParameters['associations']['combinations']['fields'] = array_merge(
			$this->webserviceParameters['associations']['combinations']['fields'],
			array(
				'id_product' =>        array('required' => true),
				'location' =>            array('required' => true),
				'ean13' =>                array('required' => true),
				'upc' =>                array('required' => true),
				'quantity' =>            array('required' => true),
				'reference' =>            array('required' => true),
				'supplier_reference' => array('required' => true),
				'wholesale_price' =>    array('required' => true),
				'price' =>                array('required' => true),
				'ecotax' =>            array('required' => true),
				'weight' =>            array('required' => true),
				'unit_price_impact' =>    array('required' => true),
				'minimal_quantity' =>    array('required' => true),
				'default_on' =>        array('required' => true),
				'available_date' =>    array('required' => true)
			)
		);

		parent::__construct( $id_product, $full, $id_lang, $id_shop, $context );
	}

	public function getWsCombinations()
	{
		$result = Db::getInstance()->executeS(
			'SELECT pa.`id_product_attribute` as id, pa.*
			FROM `'._DB_PREFIX_.'product_attribute` pa
			'.Shop::addSqlAssociation('product_attribute', 'pa').'
			WHERE pa.`id_product` = '.(int)$this->id
		);

		return $result;
	}
}

 

Lo primero que sorprende es que extendemos esta clase de ProductCore y esto es porque queremos todo lo que ya tiene la clase producto con nuestras modificaciones:

  • El constructor: modificamos los parámetros del servicio web que Producto tiene declarados. Concretamente, la asociación (relaciones externas con otras entidades) combinaciones. Incluyendo los campos que queremos añadir en la respuesta a nuestra llamada. En el ejemplo pongo todos de los que dispone combinaciones.
  • getWsCombinations: esta función es usada en Producto para devolver todas las combinaciones que tiene un solo producto. Es usada por el servicio web para poder devolver la salida de un producto. El cambio que le hacemos a esta función (ya que la copiamos del fichero original y la trajimos a esta clase) es ponerle en el sql que seleccione todos los campos de la tabla product_attribute. Estos coincidirán con los que hemos indicado en el constructor.

Declarar nuestra clase de servicio web manejada

Acordaos que hay que añadir la declaración de este objeto en los servicios web de Prestashop. Esto se hace a través de la clase WebServiceRequest. La deberemos sobrecargar (como ya aprendimos)  y modificar la función getResources():

$resources['productextension'] = array('description' => 'Mis funciones de producto', 'specific_management' => true);

Creando nuestra clase WebserviceSpecificManagementProductextension

Esta clase es necesaria para poder manejar toda nuestra llamada, entrada y salida, comprobación de parámetros, errores, etc. Aquí la tenemos (si tenéis dudas de esto revisar el anterior artículo):

<?php

class WebserviceSpecificManagementProductextensionCore implements WebserviceSpecificManagementInterface
{

	/** @var WebserviceOutputBuilder */
	protected $objOutput;
	protected $output;

	/** @var WebserviceRequest */
	protected $wsObject;

	protected $validateFunctions = array( 'funcion1' );

	public function setObjectOutput(WebserviceOutputBuilderCore $obj)
	{
		$this->objOutput = $obj;
		return $this;
	}

	public function setWsObject(WebserviceRequestCore $obj)
	{
		$this->wsObject = $obj;
		return $this;
	}

	public function getWsObject()
	{
		return $this->wsObject;
	}
	public function getObjectOutput()
	{
		return $this->objOutput;
	}

	public function manage()
	{

		if (count($this->wsObject->urlSegment) < 2)
			throw new WebserviceException('Error', array(100, 400));

		if ( ! in_array( $this->wsObject->urlSegment[1], $this->validateFunctions ) )
			throw new WebserviceException('Error', array(100, 400));


		$funcion = $this->wsObject->urlSegment[1];
		$params = array_slice( $this->wsObject->urlSegment, 2);

		$this->objects = $this->{$funcion} ( $params );
	}

	public function getContent()
	{
		$type_of_view = WebserviceOutputBuilder::VIEW_DETAILS;
		$this->fieldsToDisplay = 'full';
		$this->schemaToDisplay = null;
		$this->depth = 0;
		$this->objects['empty'] = new ProductExtension();
		return $this->objOutput->getContent($this->objects, $this->schemaToDisplay, $this->fieldsToDisplay, $this->depth, $type_of_view);
	}

	private function funcion1 ( $params ) {
		/** @var ProductExtension $tmp */
		$tmp = new ProductExtension();

		$sqlObjects = $tmp->getWebserviceObjectList();
		$objects = array();

		if ($sqlObjects) {
			foreach ($sqlObjects as $sqlObject) {
				$objects[] = new ProductExtension((int)$sqlObject['id_product']);
			}

			return $objects;
		}
	}
}

Lo primero el nombre de esta clase: WebserviceSpecificManagementProductextensionCore debe llamarse con la siguiente estructura: WebserviceSpecificManagementKKKKKCore (donde KKKKK = nombre de nuestro servicio web con la primera letra en mayúscula). El nombre de nuestro servicio web es el que hemos usado para declararlo en getResources(), concretamente, 'productextension'

Las funciones interesantes aquí son la getContent() y la funcion1.

  • getContent(): Simplifico mucho la función, pero lo que hacemos con esta función es invocar al escritor de XML para que nos devuelva la respuesta. Las variables que indico antes del return son necesarias para el correcto funcionamiento de la llamada… esto está extraído de la propia funcionalidad de Prestashop y adaptado a nuestra necesidad.
  • funcion1(): obtenemos todos los ProductExtension (recordad que extiende de productos, así que es como decir que los obtenemos todos). La función getWebserviceObjectList proviene de ObjectModel que es la clase primaria que representa un objeto en base de datos (una entidad) y que puede ser parametrizada para contener filtros y restricciones para conseguir un subconjunto de entidades producto. A continuación repasamos todos los objetos y creamos un array de ellos.

 

Resumen

Y eso es todo. Al llamar a la api (recordad activarla desde el backend de prestashop) nos devolverá todos los productos pero la parte de combinaciones en vez de darnos solamente los identificadores de estos, tendremos todos los campos de las combinaciones.

¿Qué os parece?

Si tenéis alguna duda no olvidéis que tenéis una caja de comentarios para ello xD

Un saludo!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *