Magento 2 is a powerful and highly customizable eCommerce platform that lets developers build custom extensions and features tailored to specific project needs. A key part of Magento 2 extension development is creating models—PHP classes that handle database interactions and manage application data.
Creating a Module
Start by setting up the basic structure of a Magento 2 module. Follow this guide to get started: [Creating a Module in Magento 2].
Introduction to Interfaces
In Magento 2, API Interfaces are a core part of the system architecture. They enable communication between different components, whether internal Magento modules or external systems.
These interfaces provide standardized entry points to interact with Magento’s data and features.
Defining the Model Interface
Define an interface to serve as a blueprint for a Blog model. It includes getters and setters for properties like blog ID, title, and description. Create the following file:
app/code/Magencode/MyModule/Api/Data/BlogInterface.php
<?php /** * Copyright © Magencode 2025 All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magencode\MyModule\Api\Data; interface BlogInterface { const TITLE = 'title'; const BLOG_ID = 'blog_id'; const DESCRIPTION = 'description'; /** * Get blog_id * @return string|null */ public function getBlogId(); /** * Set blog_id * @param string $blogId * @return \Magencode\MyModule\Blog\Api\Data\BlogInterface */ public function setBlogId($blogId); /** * Get title * @return string|null */ public function getTitle(); /** * Set title * @param string $title * @return \Magencode\MyModule\Blog\Api\Data\BlogInterface */ public function setTitle($title); /** * Get description * @return string|null */ public function getDescription(); /** * Set description * @param string $description * @return \Magencode\MyModule\Blog\Api\Data\BlogInterface */ public function setDescription($description); }
Defining the Search Results Interface
This interface sets the structure for methods that retrieve model results.
app/code/Magencode/MyModule/Api/Data/BlogSearchResultsInterface.php
<?php /** * Copyright © Magencode 2025 All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magencode\MyModule\Api\Data; interface BlogSearchResultsInterface extends \Magento\Framework\Api\SearchResultsInterface { /** * Get Blog list. * @return \Magencode\MyModule\Api\Data\BlogInterface[] */ public function getItems(); /** * Set title list. * @param \Magencode\MyModule\Api\Data\BlogInterface[] $items * @return $this */ public function setItems(array $items); }
Defining the Actions Interface
This interface outlines a repository structure supporting basic CRUD operations—create, read, update, delete—for the model. Create the following file:
app/code/Magencode/MyModule/Api/BlogRepositoryInterface.php
<?php /** * Copyright © Magencode 2025 All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magencode\MyModule\Api; use Magento\Framework\Api\SearchCriteriaInterface; interface BlogRepositoryInterface { /** * Save Blog * @param \Magencode\MyModule\Api\Data\BlogInterface $blog * @return \Magencode\MyModule\Api\Data\BlogInterface * @throws \Magento\Framework\Exception\LocalizedException */ public function save( \Magencode\MyModule\Api\Data\BlogInterface $blog ); /** * Retrieve Blog * @param string $blogId * @return \Magencode\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 \Magencode\MyModule\Api\Data\BlogSearchResultsInterface * @throws \Magento\Framework\Exception\LocalizedException */ public function getList( \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria ); /** * Delete Blog * @param \Magencode\MyModule\Api\Data\BlogInterface $blog * @return bool true on success * @throws \Magento\Framework\Exception\LocalizedException */ public function delete( \Magencode\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); }
Create a Model in Magento 2
Build the model based on the interface defined earlier. Include the necessary getters and setters as specified:
app/code/Magencode/MyModule/Model/Blog.php
<?php /** * Copyright © Magencode 2025 All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magencode\MyModule\Model; use Magencode\MyModule\Api\Data\BlogInterface; use Magento\Framework\Model\AbstractModel; class Blog extends AbstractModel implements BlogInterface { /** * @inheritDoc */ public function _construct() { $this->_init(\Magencode\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); } }
Creating the Repository Model
Implement the CRUD operations for the model according to the interface structure.
app/code/Magencode/MyModule/Model/BlogRepository.php
<?php /** * Copyright © Magencode 2025 All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magencode\MyModule\Model; use Magencode\MyModule\Api\BlogRepositoryInterface; use Magencode\MyModule\Api\Data\BlogInterface; use Magencode\MyModule\Api\Data\BlogInterfaceFactory; use Magencode\MyModule\Api\Data\BlogSearchResultsInterfaceFactory; use Magencode\MyModule\Model\ResourceModel\Blog as ResourceBlog; use Magencode\MyModule\Model\ResourceModel\Blog\CollectionFactory as BlogCollectionFactory; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; use Magento\Framework\Exception\CouldNotDeleteException; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\NoSuchEntityException; class BlogRepository implements BlogRepositoryInterface { /** * @var Blog */ protected $searchResultsFactory; /** * @var ResourceBlog */ protected $resource; /** * @var CollectionProcessorInterface */ protected $collectionProcessor; /** * @var BlogInterfaceFactory */ protected $blogFactory; /** * @var BlogCollectionFactory */ protected $blogCollectionFactory; /** * @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)); } }
Linking the Database to the Model
app/code/Magencode/MyModule/Model/ResourceModel/Blog.php
<?php /** * Copyright © Magencode 2025 All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magencode\MyModule\Model\ResourceModel; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; class Blog extends AbstractDb { /** * @inheritDoc */ protected function _construct() { $this->_init('magencode_mymodule_blog', 'blog_id'); } }
Linking the Model with the Results
app/code/Magencode/MyModule/Model/ResourceModel/Blog/Collection.php
<?php /** * Copyright © Magencode 2025 All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magencode\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( \Magencode\MyModule\Model\Blog::class, \Magencode\MyModule\Model\ResourceModel\Blog::class ); } }
Assigning Interfaces to Models
app/code/Magencode/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="Magencode\MyModule\Api\BlogRepositoryInterface" type="Magencode\MyModule\Model\BlogRepository"/> <preference for="Magencode\MyModule\Api\Data\BlogInterface" type="Magencode\MyModule\Model\Blog"/> <preference for="Magencode\MyModule\Api\Data\BlogSearchResultsInterface" type="Magento\Framework\Api\SearchResults"/> </config>
Creating the Table Structure
app/code/Magencode/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="magencode_mymodule_blog" resource="default" engine="innodb" comment="magencode_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="true" xsi:type="varchar" comment="title" length="255"/> <column name="description" nullable="true" xsi:type="text" comment="description"/> </table> </schema>
Registering the Module
To register the module and create the database table, run these two commands:
php bin/magento setup:upgrade php bin/magento cache:clean
Usage Examples
<?php ... use Magencode\MyModule\Model\BlogRepository; use Magencode\MyModule\Model\BlogFactory; ... protected $blogRepository; protected $blogFactory; public function __construct( BlogRepository $blogRepository, BlogFactory $blogFactory) { $this->blogRepository = $blogRepository; $this->blogFactory = $blogFactory; } ... // Create $blogFactory = $this->blogFactory->create(); $blogFactory->setTitle('My Blog Title'); $blogFactory->setDescription('My Blog Description'); $blogFactory->save(); ... // Find $blog = $this->blogRepository->get($blogId);
Conclusion
Following these steps, a model is successfully created in Magento 2 and ready for integration in a custom extension. Model creation is a fundamental part of Magento 2 development, enabling efficient data management and manipulation. Stay tuned for the next tutorial on implementing CRUD operations with the custom model.
Leave a Reply