窗口小部件应设计为独立的,并且不应直接访问数据库。但是最近,我遇到了使用直接访问数据库的代码来检索窗口小部件设置,并且还缓存检索到的值。 这是小部件的一部分:
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();
}
// ...
}
问题是:小部件在任何情况下都可以访问数据库吗?或者这表明需要重构?
答案 0 :(得分:1)
技术上查询数据并表示数据是两个不同的任务,因此此类小部件违反了单一职责原则。但是Yii已经有了从数据库(ActiveRecord
和/或ActiveQuery
)检索数据的抽象,因此并不是那么简单。您无需创建用于调用News::find()->newestFirst()->limit(5)->all()
的单独的数据提供程序类-通常,直接在LatestNewsWidget
中调用此查询更容易,更实用。
通常情况下,您会使用三种小部件:
GridView
)。至于前两种情况清楚表明应该将数据源和窗口小部件分开,在第三种情况下并不清楚。就我个人而言,我经常使用负责检索所有必要数据和依赖项的小部件,因此我可以通过MyWidget::widget()
来简单地使用它们。我从来没有遇到任何问题,但是我试图避免过于复杂的数据库查询-通常应该将隐藏隐藏在ActiveQuery
抽象后面。同样,您始终需要为将查询数据重构和提取到单独的组件做好准备-在某些时候,具有唯一数据集的唯一小部件可能变得不唯一,并且分开小部件和数据提供程序可能是保持代码DRY的唯一明智的方法。