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.