Skip to content

Instantly share code, notes, and snippets.

@schmengler
Last active April 17, 2019 08:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schmengler/018c5e19a207276579a5ffef364c8858 to your computer and use it in GitHub Desktop.
Save schmengler/018c5e19a207276579a5ffef364c8858 to your computer and use it in GitHub Desktop.
Domain Objects from Magento Configuration

Domain Objects from Magento Configuration

A pattern suggestion to integrate framework independent domain models into Magento.

Problem:

We want to instantiate a domain model based on Magento configuration.

Implementation:

We create a new Magento specific implementation of the domain model's interface, which acts like a decorator around the original model, passing through all method calls. It comes with its own private factory method to instantiate the original domain model once, with arguments taken from the Magento configuration (ScopeConfigInterface).

This implementation is then configured as preference for the interface, so that any client code that needs this configured object, can request it via constructor injection.

Example:

See attached code. A TvSpotSchedule model, that needs to be constructed from configuration in Magento.

Now any class that needs access to the schedule can use it like this:

public function __construct(TvSpotScheduleInterface $tvSpotSchedule)

Considerations

  • Extensibility: Pure Domain models should not need the full extensibility with plugins. The Magento implementation could still be replaced via preference to use a different factory method. However, in the scope of public extensions or core code, where maximum flexibility is a priority, the object manager could be used instead of new or static constructor methods.

Alternatives:

A typical implementation would be a factory class with createFromConfig() method (or just create(), taking default argument values from configuration).

Drawback: Everywhere we want to use the model, we need to inject the factory and create a new instance from it. This adds another layer of indirection in client code, and also using a shared instance is not possible.

<?php
/**
* Default, Magento independent implementation of the domain interface
*/
class TvSpotSchedule implements TvSpotScheduleInterface
{
// ...
}
<?php
/**
* Magento specific, acts as wrapper around the independent implementation, with internal factory method.
*
* This class is configured as preference for TvSpotScheduleInterface
*/
class TvSpotScheduleFromConfig implements TvSpotScheduleInterface
{
/**
* @var TvSpotScheduleInterface
*/
private $instance;
/**
* @var ScopeConfigInterface
*/
private $scopeConfig;
public function __construct(ScopeConfigInterface $scopeConfig)
{
$this->scopeConfig = $scopeConfig;
}
private function getInstance(): TvSpotScheduleInterface
{
if ($this->instance === null) {
$this->instance = TvSpotSchedule::fromCsvString(
$this->scopeConfig->getValue('tv_campaigns/schedule/csv')
);
}
return $this->instance;
}
public function nextSpot(): TvSpotInterface
{
return $this->getInstance()->nextSpot();
}
}
<?php
interface TvSpotScheduleInterface
{
public function nextSpot(): TvSpotInterface;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment