Create a Magento 2 Model and Database Layer

In Magento 2, models, resource models, and collections work together to handle data storage and retrieval. Models encapsulate business logic, resource models contain database-specific logic, and collections help you work with multiple rows (entities) at once.

1. Create the Model Class

The model represents a single entity (row) from your custom table. It should not contain raw SQL. Instead, it delegates all database operations to the resource model.

File: app/code/Hikmadh/Mymodule/Model/Contact.php

<?php namespace Hikmadh\Mymodule\Model; use Magento\Framework\Model\AbstractModel; /** * Contact Model */ class Contact extends AbstractModel { /** * Initialize resource model */ protected function _construct() { $this->_init(\Hikmadh\Mymodule\Model\ResourceModel\Contact::class); } }

2. Create the ResourceModel Class

The resource model contains table and primary key information, and it’s responsible for all low-level DB operations. The model calls into this class when you use save(), load(), or collections.

File: app/code/Hikmadh/Mymodule/Model/ResourceModel/Contact.php

<?php namespace Hikmadh\Mymodule\Model\ResourceModel; use Magento\Framework\Model\ResourceModel\Db\AbstractDb; /** * Contact Resource Model */ class Contact extends AbstractDb { /** * Initialize resource */ protected function _construct() { // 'hikmadh_mymodule' = table name // 'hikmadh_mymodule_id' = primary key column $this->_init('hikmadh_mymodule', 'hikmadh_mymodule_id'); } }

3. Create the Collection Class

A collection is used to load multiple entities, apply filters, and iterate over the result set. It is tied to your model and resource model.

File: app/code/Hikmadh/Mymodule/Model/ResourceModel/Contact/Collection.php

<?php namespace Hikmadh\Mymodule\Model\ResourceModel\Contact; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; /** * Contact Resource Model Collection */ class Collection extends AbstractCollection { /** * Initialize resource collection */ protected function _construct() { $this->_init( \Hikmadh\Mymodule\Model\Contact::class, \Hikmadh\Mymodule\Model\ResourceModel\Contact::class ); } }

4. (Optional but Recommended) Define the Database Table (db_schema.xml)

In modern Magento 2 (declarative schema), you define your table in db_schema.xml. This file creates the hikmadh_mymodule table with an auto-increment primary key and a name column, which our model uses via the setName() method.

File: app/code/Hikmadh/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="hikmadh_mymodule" resource="default" engine="innodb" comment="Hikmadh Contacts"> <column xsi:type="int" name="hikmadh_mymodule_id" padding="10" unsigned="true" nullable="false" identity="true" comment="Entity ID" /> <column xsi:type="varchar" name="name" nullable="false" length="255" comment="Contact Name" /> <constraint xsi:type="primary" referenceId="PRIMARY"> <column name="hikmadh_mymodule_id" /> </constraint> </table> </schema>

Run the usual setup upgrade command after adding this file:

php bin/magento setup:upgrade

5. Create Contacts from the Controller (Using Dependency Injection)

To test the model and database integration, you can create a controller that instantiates the Contact model and saves records into the table. Here’s a best-practice example using a factory instead of the object manager.

File: app/code/Hikmadh/Mymodule/Controller/Test/Index.php

<?php namespace Hikmadh\Mymodule\Controller\Test; use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; use Hikmadh\Mymodule\Model\ContactFactory; class Index extends Action { /** * @var ContactFactory */ protected $contactFactory; public function __construct( Context $context, ContactFactory $contactFactory ) { $this->contactFactory = $contactFactory; parent::__construct($context); } public function execute() { $names = [ 'Hikmadh Noor', 'Hikmadh Harun', 'Hikmadh Mohamed' ]; foreach ($names as $name) { /** @var \Hikmadh\Mymodule\Model\Contact $contact */ $contact = $this->contactFactory->create(); $contact->setName($name); $contact->save(); } $this->getResponse()->setBody('test'); } }

After deploying and clearing caches, visit:

http://www.example.com/index.php/mymodule/test/index

You should see the response test, and all three contacts will be inserted into your hikmadh_mymodule table. Open your database (MySQL) and verify that the rows were created successfully.

6. Summary

  • Model – wraps business logic for a single entity.
  • ResourceModel – knows the table and primary key, handles DB I/O.
  • Collection – loads multiple entities with filters.
  • db_schema.xml – declarative schema to create/update DB tables.
  • Controller – uses the model (via factory) to create and save data.

Together, these pieces form the standard Magento 2 persistence layer for your custom module, giving you a clean and extensible way to work with your own database tables.