Yii2:从小部件访问数据库

Yii2:从小部件访问数据库,yii2,Yii2,小部件应设计为自包含的,并且不应直接访问数据库。但最近我遇到了一段代码,它使用对数据库的直接访问来检索小部件设置,并缓存检索到的值。 以下是小部件的一部分: class DbCarousel extends Carousel { // ... public function init() { $cacheKey = [ WidgetCarousel::className(), $this->key

小部件应设计为自包含的,并且不应直接访问数据库。但最近我遇到了一段代码,它使用对数据库的直接访问来检索小部件设置,并缓存检索到的值。 以下是小部件的一部分:

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();
    }
    // ...
}

问题是:widget在任何情况下都能访问数据库吗,或者这是需要重构的标志?

从技术上来说,查询数据和表示数据是两个不同的任务,所以这种widget打破了单一责任原则。然而,Yii已经有了一个从数据库检索数据的抽象(
ActiveRecord
和/或
ActiveQuery
),所以它并没有那么简单。您不需要创建单独的数据提供程序类来调用
News::find()->newestFirst()->limit(5)->all()
——通常直接在
LatestNewsWidget
中调用此查询更简单、更实用

通常,小部件有三种情况:

  • 小部件可能以相同的方式显示不同的数据集(如
    GridView
  • 相同的数据可能通过不同的小部件以不同的方式显示,比如用于显示菜单的小部件-数据库中存储有一个菜单,但根据布局,应该使用不同的小部件
  • 显示方式和数据都是独一无二的——例如,您只有一个菜单和一个布局(所以只有一个用于显示菜单的小部件)

  • 由于前两种情况清楚地表明数据源和小部件应该分开,第三种情况就不那么清楚了。就我个人而言,我经常使用小部件,它们负责检索所有必要的数据和依赖项,因此我可以通过
    MyWidget::widget()
    简单地使用它们。我在这方面从来没有遇到过任何问题,但我正在努力避免过于复杂的DB查询-共谋通常应该隐藏在
    ActiveQuery
    抽象之后。此外,您还需要随时准备重构和提取查询数据以分离组件-在某些情况下,具有唯一数据集的唯一小部件可能会变得不唯一,而分离小部件和数据提供程序可能是保持代码干燥的唯一明智方法。

    小部件是自包含的,但您可能应该改变使用的方法如果需要旋转木马处理的项目来自数据库,而不是在旋转木马小部件中添加查询,则应在初始化时向小部件提供数据,就像下拉小部件一样,它可以通过以
    name=>value
    对的形式传递选项集来显示任何静态或动态项目,声明一个公共属性
    $data
    ,并通过类似
    DbCarousel::widget('data'=>$yourDataSet)
    的选项初始化它,但在正式的文档中,并没有任何内容是这样写的:它不应该访问数据库,至少我可以找到它。尽管它确实有意义。我也这么认为。我读过一些文章,其中建议不要从窗口小部件访问数据库,这是有道理的,因为允许这样做会使数据库请求遍布整个应用程序。但是我经常会发现一些带有db访问代码的小部件的例子,所以我想知道是否有任何例子。谢谢你详尽的回答,你已经澄清了我的疑问!