Yii2:从小部件访问数据库

时间:2018-07-21 16:39:01

标签: yii2

窗口小部件应设计为独立的,并且不应直接访问数据库。但是最近,我遇到了使用直接访问数据库的代码来检索窗口小部件设置,并且还缓存检索到的值。 这是小部件的一部分:

class DbCarousel extends Carousel
{
    // ...
    public function init()
    {
        $cacheKey = [
            WidgetCarousel::className(),
            $this->key
        ];
        $items = Yii::$app->cache->get($cacheKey);
        if ($items === false) {
            $items = [];
            $query = WidgetCarouselItem::find()
                ->joinWith('carousel')
                ->where([
                    '{{%widget_carousel_item}}.status' => 1,
                    '{{%widget_carousel}}.status' => WidgetCarousel::STATUS_ACTIVE,
                    '{{%widget_carousel}}.key' => $this->key,
                ])
                ->orderBy(['order' => SORT_ASC]);
            foreach ($query->all() as $k => $item) {
                /** @var $item \common\models\WidgetCarouselItem */
                if ($item->path) {
                    $items[$k]['content'] = Html::img($item->getImageUrl());
                }
                if ($item->caption) {
                    $items[$k]['caption'] = $item->caption;
                }
            }
            Yii::$app->cache->set($cacheKey, $items, 60*60*24*365);
        }
        $this->items = $items;
        parent::init();
    }
    // ...
}

问题是:小部件在任何情况下都可以访问数据库吗?或者这表明需要重构?

1 个答案:

答案 0 :(得分:1)

技术上查询数据并表示数据是两个不同的任务,因此此类小部件违反了单一职责原则。但是Yii已经有了从数据库(ActiveRecord和/或ActiveQuery)检索数据的抽象,因此并不是那么简单。您无需创建用于调用News::find()->newestFirst()->limit(5)->all()的单独的数据提供程序类-通常,直接在LatestNewsWidget中调用此查询更容易,更实用。

通常情况下,您会使用三种小部件:

  1. 窗口小部件可以以相同的方式显示不同的数据集(例如GridView)。
  2. 相同的数据可能由不同的小部件以不同的方式显示,例如用于显示菜单的小部件-数据库中存储了一个菜单,但根据布局,应使用不同的小部件。
  3. 显示和数据的方式都是唯一的-例如,您只有一个菜单和一个布局(因此,只有一个用于显示菜单的小部件)。

至于前两种情况清楚表明应该将数据源和窗口小部件分开,在第三种情况下并不清楚。就我个人而言,我经常使用负责检索所有必要数据和依赖项的小部件,因此我可以通过MyWidget::widget()来简单地使用它们。我从来没有遇到任何问题,但是我试图避免过于复杂的数据库查询-通常应该将隐藏隐藏在ActiveQuery抽象后面。同样,您始终需要为将查询数据重构和提取到单独的组件做好准备-在某些时候,具有唯一数据集的唯一小部件可能变得不唯一,并且分开小部件和数据提供程序可能是保持代码DRY的唯一明智的方法。