luyadev/luya-module-cms

View on GitHub
src/models/Block.php

Summary

Maintainability
A
2 hrs
Test Coverage
C
78%
<?php

namespace luya\cms\models;

use luya\admin\aws\DetailViewActiveWindow;
use luya\admin\ngrest\base\NgRestModel;
use luya\admin\ngrest\plugins\SelectModel;
use luya\admin\ngrest\plugins\ToggleStatus;
use luya\cms\admin\aws\BlockPagesActiveWindow;
use luya\cms\admin\Module;
use luya\cms\base\BlockInterface;
use Yii;

/**
 * Block ActiveRecord contains the Block<->Group relation.
 *
 * @property integer $id
 * @property integer $group_id
 * @property string $class
 * @property integer $usageCount returns the amount of how much this block is used inside a page.
 * @property integer $is_disabled
 *
 * @author Basil Suter <basil@nadar.io>
 * @since 1.0.0
 */
class Block extends NgRestModel
{
    private int $cachedDeletedId = 0;

    /**
     * @inheritdoc
     */
    public static function ngRestApiEndpoint()
    {
        return 'api-cms-block';
    }

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'cms_block';
    }

    /**
     * @inheritdoc
     */
    public function ngRestAttributeTypes()
    {
        return [
            'group_id' => [
                'class' => SelectModel::class,
                'modelClass' => BlockGroup::class,
                'labelField' => fn ($model) => $model->getGroupLabel()
            ],
            'class' => 'text',
            'is_disabled' => 'toggleStatus',
        ];
    }

    /**
     * @inheritdoc
     */
    public function ngRestExtraAttributeTypes()
    {
        return [
            'usageCount' => ['number', 'sortField' => false],
            'translationName' => ['text', 'sortField' => false],
            'fileExists' => ['class' => ToggleStatus::class, 'interactive' => false, 'sortField' => false],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'translationName' => Module::t('model_block_translation_name_label'),
            'class' => Module::t('model_block_class_label'),
            'group_id' => Module::t('model_block_group_id_label'),
            'usageCount' => Module::t('model_block_usage_count_label'),
            'fileExists' => Module::t('model_block_file_exists_label'),
            'is_disabled' => Module::t('model_block_is_disable_label'),
        ];
    }

    /**
     * @inheritdoc
     */
    public function ngRestActiveWindows()
    {
        return [
            [
                'class' => DetailViewActiveWindow::class,
                'attributes' => [
                    'id:integer:ID',
                    'translationName',
                    'class',
                    'blockGroup.groupLabel:text:' . Module::t('model_block_group_id_label'),
                    'usageCount',
                    'is_disabled:boolean',
                    'fileExists:boolean',
                ],
            ],
            [
                'class' => BlockPagesActiveWindow::class,
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public function ngRestScopes()
    {
        return [
            ['list', ['translationName', 'class', 'group_id', 'usageCount', 'fileExists', 'is_disabled']],
        ];
    }

    /**
     * Wehther the class file exists or not.
     *
     * @return number
     * @since 1.0.4
     */
    public function getFileExists()
    {
        return class_exists($this->class) ? 1 : 0;
    }

    /**
     * Returns the amount where the block is used inside the content.
     *
     * @return integer
     */
    public function getUsageCount()
    {
        return $this->getNavItemPageBlockItems()->count();
    }

    /**
     *
     * @return \yii\db\ActiveQuery
     * @since 1.0.4
     */
    public function getNavItemPageBlockItems()
    {
        return $this->hasMany(NavItemPageBlockItem::class, ['block_id' => 'id']);
    }

    /**
     * Returns the name from the block label.
     *
     * @return string
     */
    public function getTranslationName()
    {
        return $this->getClassObject() ? $this->getClassObject()->name() : $this->class;
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['group_id', 'class'], 'required'],
            [['group_id', 'is_disabled'], 'integer'],
            [['class'], 'string', 'max' => 255],
        ];
    }

    /**
     * @inheritdoc
     */
    public function ngRestGroupByField()
    {
        return 'group_id';
    }

    /**
     * Save id before deleting for clean up in afterDelete()
     *
     * @return bool
     */
    public function beforeDelete()
    {
        $this->cachedDeletedId = $this->id;
        return parent::beforeDelete();
    }

    /**
     * Search for entries with cached block id in cms_nav_item_page_block_item and delete them
     */
    public function afterDelete()
    {
        if ($this->cachedDeletedId) {
            foreach (NavItemPageBlockItem::find()->where(['block_id' => $this->cachedDeletedId])->all() as $item) {
                $item->delete();
            }
        }
        parent::afterDelete();
    }

    /**
     * BlockGroup ActiveQuery.
     *
     * @return \yii\db\ActiveQuery
     * @since 1.0.4
     */
    public function getBlockGroup()
    {
        return $this->hasOne(BlockGroup::class, ['id' => 'group_id']);
    }

    /**
     * Returns the origin block object based on the current active record entry.
     *
     * @return \luya\cms\base\BlockInterface
     */
    public function getClassObject()
    {
        return $this->getFileExists() ? Yii::createObject(['class' => $this->class]) : false;
    }

    /**
     * Try to get the name of the log.
     */
    public function getNameForLog()
    {
        if ($this->getClassObject() && $this->getClassObject() instanceof BlockInterface) {
            return $this->getClassObject()->name();
        }

        return $this->class;
    }

    /**
     * Find the the class names for a certain amount of block ids.
     *
     * @return array
     */
    public static function findObjectClassesById(array $ids)
    {
        return self::find()->select('class')->indexBy('id')->where(['in', 'id', $ids])->column();
    }

    /**
     * @param int $id
     * @param string $context
     * @param NavItemPage|null $pageObject
     * @since 1.0.6
     */
    public function getObject($id, $context, NavItemPage $pageObject = null): false|\luya\cms\base\BlockInterface
    {
        return self::createObject($this->class, $this->id, $id, $context, $pageObject);
    }

    /**
     * Creates the block object and stores the object within a static block container.
     *
     * @param string $class The block object class name.
     * @param int $blockId The id of the cms_block table
     * @param int $id The context id, the cms_nav_item_page_block_item unique id
     * @param string $context admin or frontend
     * @param NavItemPage|null $pageObject
     */
    public static function createObject($class, $blockId, $id, $context, NavItemPage $pageObject = null): false|\luya\cms\base\BlockInterface
    {
        if (!class_exists($class)) {
            return false;
        }

        $object = Yii::createObject([
            'class' => $class,
        ]);

        $object->setEnvOption('id', $id);
        $object->setEnvOption('blockId', $blockId);
        $object->setEnvOption('context', $context);
        $object->setEnvOption('pageObject', $pageObject);

        $object->setup();

        return $object;
    }
}