_themeFactory = $themeFactory;
$this->_domainFactory = $domainFactory;
$this->_imageFactory = $imageFactory;
$this->_validator = $validator;
$this->_customFactory = $customizationFactory;
$this->themeModelFactory = $themeModelFactory ?: ObjectManager::getInstance()->get(ThemeFactory::class);
$this->addData(['type' => self::TYPE_VIRTUAL]);
}
/**
* Init resource model
*
* @return void
*/
protected function _construct()
{
$this->_init(\Magento\Theme\Model\ResourceModel\Theme::class);
}
/**
* Get theme image model
*
* @return \Magento\Framework\View\Design\Theme\Image
*/
public function getThemeImage()
{
return $this->_imageFactory->create(['theme' => $this]);
}
/**
* @return \Magento\Framework\View\Design\Theme\Customization
*/
public function getCustomization()
{
if ($this->_customization === null) {
$this->_customization = $this->_customFactory->create(['theme' => $this]);
}
return $this->_customization;
}
/**
* Check if theme is deletable
*
* @return bool
*/
public function isDeletable()
{
return $this->isEditable();
}
/**
* Check if theme is editable
*
* @return bool
*/
public function isEditable()
{
return self::TYPE_PHYSICAL != $this->getType();
}
/**
* Check if theme is virtual
*
* @return bool
*/
public function isVirtual()
{
return $this->getType() == self::TYPE_VIRTUAL;
}
/**
* Check if theme is physical
*
* @return bool
*/
public function isPhysical()
{
return $this->getType() == self::TYPE_PHYSICAL;
}
/**
* Check theme is visible in backend
*
* @return bool
*/
public function isVisible()
{
return in_array($this->getType(), [self::TYPE_PHYSICAL, self::TYPE_VIRTUAL]);
}
/**
* Check is theme has child virtual themes
*
* @return bool
*/
public function hasChildThemes()
{
return (bool)$this->getCollection()->addTypeFilter(
self::TYPE_VIRTUAL
)->addFieldToFilter(
'parent_id',
['eq' => $this->getId()]
)->getSize();
}
/**
* Retrieve theme instance representing the latest changes to a theme
*
* @return Theme|null
*/
public function getStagingVersion()
{
if ($this->getId()) {
$collection = $this->getCollection();
$collection->addFieldToFilter('parent_id', $this->getId());
$collection->addFieldToFilter('type', self::TYPE_STAGING);
$stagingTheme = $collection->getFirstItem();
if ($stagingTheme->getId()) {
return $stagingTheme;
}
}
return null;
}
/**
* {@inheritdoc}
*/
public function getParentTheme()
{
if ($this->hasData('parent_theme')) {
return $this->getData('parent_theme');
}
$theme = null;
if ($this->getParentId()) {
$theme = $this->_themeFactory->create($this->getParentId());
}
$this->setParentTheme($theme);
return $theme;
}
/**
* {@inheritdoc}
*/
public function getArea()
{
// In order to support environment emulation of area, if area is set, return it
if ($this->getData('area') && !$this->_appState->isAreaCodeEmulated()) {
return $this->getData('area');
}
return $this->_appState->getAreaCode();
}
/**
* {@inheritdoc}
*/
public function getThemePath()
{
return $this->getData('theme_path');
}
/**
* Retrieve theme full path which is used to distinguish themes if they are not in DB yet
*
* Alternative id looks like "/".
* Used as id in file-system theme collection
*
* @return string|null
*/
public function getFullPath()
{
return $this->getThemePath() ? $this->getArea() . self::PATH_SEPARATOR . $this->getThemePath() : null;
}
/**
* {@inheritdoc}
*/
public function getCode()
{
return (string)$this->getData('code');
}
/**
* Get one of theme domain models
*
* @param int|null $type
* @return \Magento\Theme\Model\Theme\Domain\Virtual|\Magento\Theme\Model\Theme\Domain\Staging
* @throws \InvalidArgumentException
*/
public function getDomainModel($type = null)
{
if ($type !== null && $type != $this->getType()) {
throw new \InvalidArgumentException(
sprintf(
'Invalid domain model "%s" requested for theme "%s" of type "%s"',
$type,
$this->getId(),
$this->getType()
)
);
}
return $this->_domainFactory->create($this);
}
/**
* Validate theme data
*
* @return $this
* @throws \Magento\Framework\Exception\LocalizedException
*/
protected function _validate()
{
if (!$this->_validator->validate($this)) {
$messages = $this->_validator->getErrorMessages();
throw new \Magento\Framework\Exception\LocalizedException(__(implode(PHP_EOL, reset($messages))));
}
return $this;
}
/**
* Before theme save
*
* @return $this
*/
public function beforeSave()
{
$this->_validate();
return parent::beforeSave();
}
/**
* Update all relations after deleting theme
*
* @return $this
*/
public function afterDelete()
{
$stagingVersion = $this->getStagingVersion();
if ($stagingVersion) {
$stagingVersion->delete();
}
$this->getCollection()->updateChildRelations($this);
return parent::afterDelete();
}
/**
* Return the full theme inheritance sequence, from the root theme till a specified one
*
* @return ThemeInterface[]
*/
public function getInheritedThemes()
{
if (null === $this->inheritanceSequence) {
$theme = $this;
$result = [];
while ($theme) {
$result[] = $theme;
$theme = $theme->getParentTheme();
}
$this->inheritanceSequence = array_reverse($result);
}
return $this->inheritanceSequence;
}
/**
* @inheritdoc
*/
public function toArray(array $keys = [])
{
$data = parent::toArray($keys);
if (isset($data['parent_theme'])) {
$data['parent_theme'] = $this->getParentTheme()->toArray();
}
if (isset($data['inherited_themes'])) {
foreach ($data['inherited_themes'] as $key => $inheritedTheme) {
$data['inherited_themes'][$key] = $inheritedTheme->toArray();
}
}
return $data;
}
/**
* Populate Theme object from an array
*
* @param array $data
* @return Theme
*/
public function populateFromArray(array $data)
{
$this->_data = $data;
if (isset($data['parent_theme'])) {
$this->_data['parent_theme'] = $this->createThemeInstance()->populateFromArray($data['parent_theme']);
}
if (isset($data['inherited_themes'])) {
foreach ($data['inherited_themes'] as $key => $inheritedTheme) {
$themeInstance = $this->createThemeInstance()->populateFromArray($inheritedTheme);
$this->_data['inherited_themes'][$key] = $themeInstance;
}
}
return $this;
}
/**
* Create Theme instance
*
* @return \Magento\Theme\Model\Theme
*/
private function createThemeInstance()
{
return $this->themeModelFactory->create();
}
}