Skip to content
intermediate Phase 35 · Models

Resource Models

AbstractDb, table definition, CRUD operations, afterSave/afterLoad, and resource model architecture.

45m
0 problems
Topic Progress 0%

Resource Model Structure

Resource models handle all database operations for models.

Basic resource model:

<?php
namespace Vendor\Blog\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Post extends AbstractDb
{
    protected function _construct()
    {
        $this->_init('vendor_blog_post', 'entity_id');
    }
}

_init() parameters:

  • First: table name (vendor_blog_post)
  • Second: primary key column (entity_id)

Custom table name:

protected function _construct()
{
    $this->_init(
        'vendor_blog_post', // Table name
        'entity_id'         // Primary key
    );
}

Table with prefix:

// Table name automatically gets store prefix
$this->_init('vendor_blog_post', 'entity_id');
// Becomes: {prefix}_vendor_blog_post

CRUD Operations

Resource models provide methods for database CRUD.

Insert (Create):

$resource = $this->postFactory->create()->getResource();

$post = $this->postFactory->create();
$post->setTitle('My Post');
$post->setContent('Content');

$resource->save($post);
// INSERT INTO vendor_blog_post (title, content) VALUES ('My Post', 'Content')

Update:

$post = $this->postFactory->create()->load(1);
$post->setTitle('Updated Title');

$resource->save($post);
// UPDATE vendor_blog_post SET title = 'Updated Title' WHERE entity_id = 1

Delete:

$post = $this->postFactory->create()->load(1);
$resource->delete($post);
// DELETE FROM vendor_blog_post WHERE entity_id = 1

Load:

$resource = $this->postFactory->create()->getResource();
$post = $this->postFactory->create();

$resource->load($post, 1);
// SELECT * FROM vendor_blog_post WHERE entity_id = 1

// Load by attribute
$resource->load($post, 'my-url-key', 'url_key');
// SELECT * FROM vendor_blog_post WHERE url_key = 'my-url-key'

Check existence:

$exists = $resource->checkExist($post, 'my-url-key', 'url_key');

Lifecycle Hooks

Resource models provide hooks for save/load/delete operations.

Available hooks:

_beforeSave() — Before inserting/updating
_afterSave() — After inserting/updating
_beforeLoad() — Before loading
_afterLoad() — After loading
_beforeDelete() — Before deleting
_afterDelete() — After deleting

_afterSave example:

protected function _afterSave(\Magento\Framework\Model\AbstractModel $object)
{
    // Process after save
    $this->processTags($object);
    $this->updateSearchIndex($object);
    
    return parent::_afterSave($object);
}

private function processTags(\Magento\Framework\Model\AbstractModel $object): void
{
    $tags = explode(',', $object->getTags());
    
    foreach ($tags as $tag) {
        $this->tagResource->addTagToPost($object->getId(), trim($tag));
    }
}

_afterLoad example:

protected function _afterLoad(\Magento\Framework\Model\AbstractModel $object)
{
    // Load related data
    $tags = $this->tagResource->getTagsByPost($object->getId());
    $object->setData('tags', $tags);
    
    // Format dates
    if ($object->getCreatedAt()) {
        $object->setCreatedAtFormatted(
            $this->dateFormatter->format($object->getCreatedAt())
        );
    }
    
    return parent::_afterLoad($object);
}

_beforeSave example:

protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object)
{
    // Validate data
    if (empty($object->getTitle())) {
        throw new \Magento\Framework\Exception\LocalizedException(
            __('Title cannot be empty')
        );
    }
    
    // Set timestamps
    if ($object->isObjectNew()) {
        $object->setCreatedAt($this->dateFormatter->formatDate());
    }
    $object->setUpdatedAt($this->dateFormatter->formatDate());
    
    return parent::_beforeSave($object);
}

Resource Model Best Practices

Best practices for resource model implementation.

1. Keep resource models focused:

// BAD: Business logic in resource model
class Post extends AbstractDb
{
    public function processOrder() { /* ... */ }
}

// GOOD: Resource model only handles DB
class Post extends AbstractDb
{
    protected function _construct()
    {
        $this->_init('vendor_blog_post', 'entity_id');
    }
}

2. Use transactions for multi-table operations:

public function saveWithRelations(\Magento\Framework\Model\AbstractModel $object): void
{
    $connection = $this->getConnection();
    $connection->beginTransaction();
    
    try {
        $this->save($object);
        $this->saveRelations($object);
        $connection->commit();
    } catch (\Exception $e) {
        $connection->rollBack();
        throw $e;
    }
}

3. Use prepared statements:

// BAD: SQL injection risk
$connection->query("SELECT * FROM table WHERE id = $id");

// GOOD: Prepared statement
$connection->query(
    'SELECT * FROM table WHERE id = ?',
    [$id]
);

4. Handle NULL values:

protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object)
{
    // Convert empty strings to NULL
    foreach ($object->getData() as $key => $value) {
        if ($value === '') {
            $object->setData($key, null);
        }
    }
    
    return parent::_beforeSave($object);
}

Quiz

1. What does _init() do in a resource model?

Question 1 options

2. What hook fires after a model is saved?

Question 2 options

3. How do you load a model via resource model?

Question 3 options

4. What should resource models NOT contain?

Question 4 options

Flashcards

Question

What does _init() set?

Answer

Table name and primary key column

Question

What hooks are available?

Answer

_beforeSave, _afterSave, _beforeLoad, _afterLoad, _beforeDelete, _afterDelete

Question

How do you save via resource model?

Answer

$resource->save($model)

Question

How do you delete via resource model?

Answer

$resource->delete($model)

Question

What is the parent class for resource models?

Answer

Magento\Framework\Model\ResourceModel\Db\AbstractDb

Revision Notes

Key Takeaways

  • 1. Resource models extend AbstractDb and handle database operations
  • 2. _init() sets table name and primary key
  • 3. Lifecycle hooks: _beforeSave, _afterSave, _beforeLoad, _afterLoad, _beforeDelete, _afterDelete
  • 4. Use prepared statements to prevent SQL injection
  • 5. Use transactions for multi-table operations
  • 6. Keep resource models focused on DB operations only

Interview Tips

  • Explain resource model lifecycle hooks
  • Describe how to implement _afterSave for related data
  • Discuss transaction usage in resource models
  • Know the difference between Model and Resource Model

Cheat Sheet

Resource Models Cheat Sheet

Structure:

class Post extends AbstractDb
{
    protected function _construct()
    {
        $this->_init('table_name', 'entity_id');
    }
}

CRUD:

  • $resource->save($model)
  • $resource->load($model, $id)
  • $resource->delete($model)

Hooks:

  • _beforeSave() / _afterSave()
  • _beforeLoad() / _afterLoad()
  • _beforeDelete() / _afterDelete()

Best practices:

  • Prepared statements
  • Transactions
  • No business logic