15
Feb
Curso de Magento 2 – Modelos (Models)
Magento 2 es una plataforma de comercio electrónico potente y altamente personalizable que ofrece a los desarrolladores la capacidad de crear extensiones y funcionalidades personalizadas para satisfacer las necesidades específicas de sus proyectos. Uno de los componentes fundamentales en el desarrollo de extensiones para Magento 2 es la creación de modelos. Los modelos en Magento 2 son clases PHP que interactúan con la base de datos y se utilizan para gestionar los datos de la aplicación.
Creando un módulo
Lo primero que debemos tener es la estructura de un módulo en Magento 2. Te dejo el siguiente enlace para que puedas crear uno. Creación de un módulo en Magento 2.
Introducción a las interfaces
En Magento 2, las API Interfaces (Application Programming Interface) son una parte fundamental de la arquitectura del sistema que permiten la comunicación entre diferentes componentes del sistema, ya sea entre módulos internos de Magento o entre Magento y sistemas externos.
Las API Interfaces en Magento 2 proporcionan un conjunto de puntos de entrada estandarizados a través de los cuales los desarrolladores pueden interactuar con los datos y las funcionalidades de Magento.
Definiendo la interface para un modelo
Definimos una interface que nos servirá para crear la estructura de un modelo que se llamará Blog. Y definiremos los getters y setters para los atributos de nuestro modelo. Serán id del blog, titulo y descripción. Crearemos el siguiente archivo:
mkdir -p app/code/MyCompany/MyModule/Api/Data
touch app/code/MyCompany/MyModule/Api/Data/BlogInterface.php
<?php /** * Copyright © Gerson Hernández All rights reserved. */ declare(strict_types=1); namespace MyCompany\MyModule\Api\Data; interface BlogInterface { const DESCRIPTION = 'description'; const BLOG_ID = 'blog_id'; const TITLE = 'title'; /** * Get blog_id * @return string|null */ public function getBlogId(); /** * Set blog_id * @param string $blogId * @return \MyCompany\MyModule\Blog\Api\Data\BlogInterface */ public function setBlogId($blogId); /** * Get title * @return string|null */ public function getTitle(); /** * Set title * @param string $title * @return \MyCompany\MyModule\Blog\Api\Data\BlogInterface */ public function setTitle($title); /** * Get description * @return string|null */ public function getDescription(); /** * Set description * @param string $description * @return \MyCompany\MyModule\Blog\Api\Data\BlogInterface */ public function setDescription($description); }
Definiendo la interface para resultados
Esta interface nos servira para definir la estructura de nuestros metodos para obtener los resultados de nuestro modelo.
touch app/code/MyCompany/MyModule/Api/Data/BlogSearchResultsInterface.php
<?php /** * Copyright © Gerson Hernández All rights reserved. */ declare(strict_types=1); namespace MyCompany\MyModule\Api\Data; interface BlogSearchResultsInterface extends \Magento\Framework\Api\SearchResultsInterface { /** * Get Blog list. * @return \MyCompany\MyModule\Api\Data\BlogInterface[] */ public function getItems(); /** * Set title list. * @param \MyCompany\MyModule\Api\Data\BlogInterface[] $items * @return $this */ public function setItems(array $items); }
Definiendo la interface para nuestras acciones
Esta interface nos servirá para crear la estructura de un repositorio que contenga las operaciones básicas de nuestro modelo, como crear, leer, actualizar y eliminar los datos. Crearemos el siguiente archivo:
touch app/code/MyCompany/MyModule/Api/BlogRepositoryInterface.php
<?php /** * Copyright © Gerson Hernández All rights reserved. */ declare(strict_types=1); namespace MyCompany\MyModule\Api; use Magento\Framework\Api\SearchCriteriaInterface; interface BlogRepositoryInterface { /** * Save Blog * @param \MyCompany\MyModule\Api\Data\BlogInterface $blog * @return \MyCompany\MyModule\Api\Data\BlogInterface * @throws \Magento\Framework\Exception\LocalizedException */ public function save( \MyCompany\MyModule\Api\Data\BlogInterface $blog ); /** * Retrieve Blog * @param string $blogId * @return \MyCompany\MyModule\Api\Data\BlogInterface * @throws \Magento\Framework\Exception\LocalizedException */ public function get($blogId); /** * Retrieve Blog matching the specified criteria. * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria * @return \MyCompany\MyModule\Api\Data\BlogSearchResultsInterface * @throws \Magento\Framework\Exception\LocalizedException */ public function getList( \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria ); /** * Delete Blog * @param \MyCompany\MyModule\Api\Data\BlogInterface $blog * @return bool true on success * @throws \Magento\Framework\Exception\LocalizedException */ public function delete( \MyCompany\MyModule\Api\Data\BlogInterface $blog ); /** * Delete Blog by ID * @param string $blogId * @return bool true on success * @throws \Magento\Framework\Exception\NoSuchEntityException * @throws \Magento\Framework\Exception\LocalizedException */ public function deleteById($blogId); }
Creando nuestro modelo
Crearemos nuestro modelo basadonos en la interface que hemos creado anteriormente. Este modelo contendra los getters y setters de la siguiente manera:
mkdir -p app/code/MyCompany/MyModule/Model
touch app/code/MyCompany/MyModule/Model/Blog.php
<?php /** * Copyright © Gerson Hernández All rights reserved. */ declare(strict_types=1); namespace MyCompany\MyModule\Model; use Magento\Framework\Model\AbstractModel; use MyCompany\MyModule\Api\Data\BlogInterface; class Blog extends AbstractModel implements BlogInterface { /** * @inheritDoc */ public function _construct() { $this->_init(\MyCompany\MyModule\Model\ResourceModel\Blog::class); } /** * @inheritDoc */ public function getBlogId() { return $this->getData(self::BLOG_ID); } /** * @inheritDoc */ public function setBlogId($blogId) { return $this->setData(self::BLOG_ID, $blogId); } /** * @inheritDoc */ public function getTitle() { return $this->getData(self::TITLE); } /** * @inheritDoc */ public function setTitle($title) { return $this->setData(self::TITLE, $title); } /** * @inheritDoc */ public function getDescription() { return $this->getData(self::DESCRIPTION); } /** * @inheritDoc */ public function setDescription($description) { return $this->setData(self::DESCRIPTION, $description); } }
Creando nuestro modelo repositorio
Este contendrá las acciones CRUD, es decir, crear, leer, actualizar y eliminar de nuestro modelo. Deben basarse según la estructura de nuestra interface de la siguiente manera:
touch app/code/MyCompany/MyModule/Model/BlogRepository.php
<?php /** * Copyright © Gerson Hernández All rights reserved. */ declare(strict_types=1); namespace MyCompany\MyModule\Model; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; use Magento\Framework\Exception\CouldNotDeleteException; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\NoSuchEntityException; use MyCompany\MyModule\Api\BlogRepositoryInterface; use MyCompany\MyModule\Api\Data\BlogInterface; use MyCompany\MyModule\Api\Data\BlogInterfaceFactory; use MyCompany\MyModule\Api\Data\BlogSearchResultsInterfaceFactory; use MyCompany\MyModule\Model\ResourceModel\Blog as ResourceBlog; use MyCompany\MyModule\Model\ResourceModel\Blog\CollectionFactory as BlogCollectionFactory; class BlogRepository implements BlogRepositoryInterface { /** * @var CollectionProcessorInterface */ protected $collectionProcessor; /** * @var BlogInterfaceFactory */ protected $blogFactory; /** * @var BlogCollectionFactory */ protected $blogCollectionFactory; /** * @var ResourceBlog */ protected $resource; /** * @var Blog */ protected $searchResultsFactory; /** * @param ResourceBlog $resource * @param BlogInterfaceFactory $blogFactory * @param BlogCollectionFactory $blogCollectionFactory * @param BlogSearchResultsInterfaceFactory $searchResultsFactory * @param CollectionProcessorInterface $collectionProcessor */ public function __construct( ResourceBlog $resource, BlogInterfaceFactory $blogFactory, BlogCollectionFactory $blogCollectionFactory, BlogSearchResultsInterfaceFactory $searchResultsFactory, CollectionProcessorInterface $collectionProcessor ) { $this->resource = $resource; $this->blogFactory = $blogFactory; $this->blogCollectionFactory = $blogCollectionFactory; $this->searchResultsFactory = $searchResultsFactory; $this->collectionProcessor = $collectionProcessor; } /** * @inheritDoc */ public function save(BlogInterface $blog) { try { $this->resource->save($blog); } catch (\Exception $exception) { throw new CouldNotSaveException(__( 'Could not save the blog: %1', $exception->getMessage() )); } return $blog; } /** * @inheritDoc */ public function get($blogId) { $blog = $this->blogFactory->create(); $this->resource->load($blog, $blogId); if (!$blog->getId()) { throw new NoSuchEntityException(__('Blog with id "%1" does not exist.', $blogId)); } return $blog; } /** * @inheritDoc */ public function getList( \Magento\Framework\Api\SearchCriteriaInterface $criteria ) { $collection = $this->blogCollectionFactory->create(); $this->collectionProcessor->process($criteria, $collection); $searchResults = $this->searchResultsFactory->create(); $searchResults->setSearchCriteria($criteria); $items = []; foreach ($collection as $model) { $items[] = $model; } $searchResults->setItems($items); $searchResults->setTotalCount($collection->getSize()); return $searchResults; } /** * @inheritDoc */ public function delete(BlogInterface $blog) { try { $blogModel = $this->blogFactory->create(); $this->resource->load($blogModel, $blog->getBlogId()); $this->resource->delete($blogModel); } catch (\Exception $exception) { throw new CouldNotDeleteException(__( 'Could not delete the Blog: %1', $exception->getMessage() )); } return true; } /** * @inheritDoc */ public function deleteById($blogId) { return $this->delete($this->get($blogId)); } }
Relacionando la base de datos y nuestro modelo
mkdir -p app/code/MyCompany/MyModule/Model/ResourceModel
touch app/code/MyCompany/MyModule/Model/ResourceModel/Blog.php
<?php /** * Copyright © Gerson Hernández All rights reserved. */ declare(strict_types=1); namespace MyCompany\MyModule\Model\ResourceModel; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; class Blog extends AbstractDb { /** * @inheritDoc */ protected function _construct() { $this->_init('mycompany_mymodule_blog', 'blog_id'); } }
Relacionando nuestro modelo con los resultados
mkdir -p app/code/MyCompany/MyModule/Model/ResourceModel/Blog
touch app/code/MyCompany/MyModule/Model/ResourceModel/Blog/Collection.php
<?php /** * Copyright © Gerson Hernández All rights reserved. */ declare(strict_types=1); namespace MyCompany\MyModule\Model\ResourceModel\Blog; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; class Collection extends AbstractCollection { /** * @inheritDoc */ protected $_idFieldName = 'blog_id'; /** * @inheritDoc */ protected function _construct() { $this->_init( \MyCompany\MyModule\Model\Blog::class, \MyCompany\MyModule\Model\ResourceModel\Blog::class ); } }
Asignando nuestras interfaces a nuestros modelos
touch app/code/MyCompany/MyModule/etc/di.xml
<?xml version="1.0" ?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="MyCompany\MyModule\Api\BlogRepositoryInterface" type="MyCompany\MyModule\Model\BlogRepository"/> <preference for="MyCompany\MyModule\Api\Data\BlogInterface" type="MyCompany\MyModule\Model\Blog"/> <preference for="MyCompany\MyModule\Api\Data\BlogSearchResultsInterface" type="Magento\Framework\Api\SearchResults"/> </config>
Creando la estructura de nuestra tabla
touch app/code/MyCompany/MyModule/etc/db_schema.xml
<?xml version="1.0" ?> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="mycompany_mymodule_blog" resource="default" engine="innodb" comment="mycompany_mymodule_blog Table"> <column xsi:type="int" name="blog_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Entity Id"/> <constraint xsi:type="primary" referenceId="PRIMARY"> <column name="blog_id"/> </constraint> <column name="title" nullable="false" xsi:type="varchar" comment="title" length="255"/> <column name="description" nullable="false" xsi:type="text" comment="description"/> </table> </schema>
Registramos nuestro módulo
Para registrar nuestro módulo y crear la tabla de nuestra base de datos lo haremos ejecutando los siguientes dos comandos:
php bin/magento setup:upgrade php bin/magento cache:clean
Ejemplos de uso
<?php ... use MyCompany\MyModule\Model\BlogRepository; use MyCompany\MyModule\Model\BlogFactory; ... protected $blogRepository; protected $blogFactory; public function __construct( BlogRepository $blogRepository, BlogFactory $blogFactory) { $this->blogRepository = $blogRepository; $this->blogFactory = $blogFactory; } ... // Crear un nuevo registro con nuestro modelo personalizado $blogFactory = $this->blogFactory->create(); $blogFactory->setTitle('Mi primer blog'); $blogFactory->setDescription('Descripcion de mi primer blog'); $blogFactory->save(); ... // Obtener registro de nuestro modelo personalizado mediante su ID $blog = $this->blogRepository->get($blogId);
Conclusión
Con estos pasos, hemos creado con éxito un modelo en Magento 2 y estamos listos para utilizarlo en nuestra extensión personalizada. La creación de modelos es una parte fundamental del desarrollo en Magento 2 y nos permite gestionar y manipular los datos de nuestra aplicación de manera eficiente. Nos vemos en el próximo tutorial sobre como utilizar un CRUD con nuestro modelo personalizado.
¡Eso es todo!
Author
Licenciado en Informatica graduado de la Universidad Tecnológica de El Salvador. PHP Developer con más de 8 años de experiencia trabajando con HTML, CSS, Bootstrap, Tailwind, JavaScript, jQuery, Knockout JS, React JS, Node JS, MySQL, PHP, Laravel, Codeigniter, Wordpress, Woocommerce y Magento.