MageWork

Back to home

Objects and class fallback

Custom classes

You can use a custom class for any types, by specifying the wanted class name.

<?php
// packages/Acme/etc/config.php

$config = [
    Core_Page::TYPE => [ // Type
        '/contact.html' => [ // Identifier (a page identifier is its route)
            'class' => Acme_Page_Contact::class,
        ],
    ],
    Core_Block::TYPE => [ // Type
        'banner' => [ // Identifier
            'class' => Acme_Block_Banner::class,
        ],
    ],
    Core_Model::TYPE => [ // Type
        'customer' => [ // Identifier
            'class' => Acme_Model_Customer::class,
        ],
    ],
];

To create an instance of an object, you need to use the App::getSingleton or App::getObject methods:

App::getSingleton({identifier}, {type}, {package}) (Create a single instance)

App::getObject({identifier}, {type}, {package}) (Create a new instance)

<?php

/** @var Acme_Model_Customer $model */
$model = App::getSingleton('customer', Core_Model::TYPE);
// packages/Acme/Model/Customer.php

/** @var Admin_Model_Customer $model */
$model = App::getSingleton('customer', Core_Model::TYPE, 'admin');
// packages/Admin/Model/Customer.php

Class fallback priorities

If the class is missing, the system will automatically attempt to load a class based on the following priorities:

  1. {package}_{type}_{identifier}
  2. Core_{type}_{identifier}
  3. {package}_{type}
  4. Core_{type}
  5. DataObject

The execute() method

When the factory builds an object (page, block, model, mail, console command, rewrite), it calls its execute() method — if defined — immediately after instantiation and after the configuration data has been injected, but before the template is rendered.

It is the single entry point for your logic: read the request, call a model, inject data into the template.

<?php

declare(strict_types=1);

class Acme_Page_Contact extends Core_Page
{
    public function execute(): void
    {
        $this->setData('countries', App::getSingleton('country', Core_Model::TYPE)->getAll());
    }
}

DataObject

Every object extends DataObject, a simple typed container:

<?php

$this->setData('title', 'Hello');        // set one key
$this->addData(['a' => 1, 'b' => 2]);    // set several keys
$this->getData('title');                 // read one key
$this->getData();                        // read every key (array)
$this->getTitle();                       // magic getter  -> getData('title')
$this->setTitle('Hi');                   // magic setter  -> setData('title', 'Hi')
$this->hasData('title');                 // key exists?
$this->unsetData('title');               // remove one key
$this->keep(['a', 'b']);                 // new array with only the given existing keys
$this->toArray();                        // every key as an array

keep() is handy to forward only part of a page's data to a block:

<?= $this->getBlock('block/head', $this->keep(['meta_title', 'meta_description']), 'head') ?>

Overrides

To override default core objects like Core_Block or Core_Page, add the class to the root of your package:

packages > Acme > Page.php

<?php

declare(strict_types=1);

class Acme_Page extends Core_Page
{
    public function myCustomMethod(): string
    {
        return 'Hello World!';
    }
}

Your class methods will now be available for all pages.

Don't forget to inherit your own classes from Acme_Page instead of Core_Page.

In the same way for the blocks:

packages > Acme > Block.php

<?php

declare(strict_types=1);

class Acme_Block extends Core_Block
{
    public function myCustomMethod(): string
    {
        return 'Hello World!';
    }
}

Your class methods will now be available for all blocks.

Fallback examples

For a block type, with banner identifier, in the Acme package.

App::getSingleton('banner', Core_Block::TYPE)

The system will try to load classes in this order until it is found:

  1. Acme_Block_Banner
  2. Core_Block_Banner
  3. Acme_Block
  4. Core_Block
  5. DataObject

For a model type, with customer identifier, in the Acme package.

App::getSingleton('customer', Core_Model::TYPE)

The system will try to load classes in this order until it is found:

  1. Acme_Model_Customer
  2. Core_Model_Customer
  3. Acme_Model
  4. Core_Model
  5. DataObject