我有一个名为Area
的模型,其中包含我需要填充下拉列表的区域名称列表。该列表使用Rainlab Translate插件进行翻译。
如果我只做一个简单的Area::lists()
,那么列表就不会被翻译。但是,如果我执行Area::get()->lists()
,则会对其进行翻译,但会在rainlab_translate_attributes
表中为下拉列表中的每个项目运行一个查询,从而导致运行约100个查询和1.5秒请求持续时间。
模型
<?php namespace Namespace\PluginName\Models;
use Model;
class Area extends Model
{
public $implement = ['RainLab.Translate.Behaviors.TranslatableModel'];
public $translatable = ['name'];
// ....
}
查看
<div class="form-group {{ errors.first('location_id') ? 'has-error' }}">
{{ form_label('area_id','Area') }}
{{ form_select('area_id', {'': 'Select...'} + area, null, {'class': 'form-control', 'placeholder': 'Select...'}) }}
<small class="text-danger" data-validate-for="area_id"></small>
</div>
组件选项#1 (快速查询但项目无法翻译)
public function areas() {
return Area::lists('name','id');
}
组件选项#2 (项目已翻译但约100次查询且非常慢)
public function areas() {
return Area::get()->lists('name','id');
}
在其他类似的情况下,我会添加public $with = ['relation']
,但rainlab_translate_attributes
表似乎没有可以将Area
模型与之关联的模型。
更新
我在Area.php
模型中创建了以下函数:
public static function listAreas()
{
$areas = Cache::rememberForever("all:" . App::getLocale() , function() {
return self::
whereNotNull('iso3166_2')
->get()
->toArray();
});
return self::makeCollection( $areas ) ;
}
public static function makeCollection ( array $models = [] )
{
return self::hydrate( $models );
}
...然后在我的组件中,我尝试过:
$areas = Area::listAreas();
&lt; - 这会立即读取缓存数据
$areas->lists('name','id');
&lt; - 这会导致为集合中的每个项目生成一个新查询,这是一个查询的示例:
select * from
{rainlab_translate_attributes {1}}的区域设置where
{MODEL_ID {1}} {model_type {1}}
我已确认= 'th' and
已正确设置为= '1275' and
答案 0 :(得分:1)
您需要手动触发JOIN
我想,似乎no functionality available for collection
。
$locale = 'de';
$query = \HardikSatasiya\DemoTest\Models\Relation::query();
$query->select($query->getModel()->getTable() .'.*');
$query->addSelect('rainlab_translate_attributes.attribute_data');
$query->leftJoin('rainlab_translate_attributes', function($join) use ($locale, $query) {
$join
->on(\Db::raw(\DbDongle::cast($query->getModel()->getQualifiedKeyName(), 'TEXT')), '=', 'rainlab_translate_attributes.model_id')
->where('rainlab_translate_attributes.model_type', '=', get_class($query->getModel()))
->where('rainlab_translate_attributes.locale', '=', $locale)
;
});
$data = $query->get();
$translatedArray = [];
foreach ($data as $value) {
if(is_null($value->attribute_data)) {
$translatedArray[$value->id] = $value->name;
}
else {
$translations = json_decode($value->attribute_data);
$translatedArray[$value->id] = $translations->name;
}
}
dd($translatedArray);
可能会对你有帮助。
答案 1 :(得分:1)
我有相同的要求,并使用缓存解决了这个问题。如果您不想缓存查询,请忽略此答案,但我认为您应该考虑它。
1)确保您的RainLab Translator
已配置,因此在使用App::getLocale()
时,会返回译员的活动区域设置而不是Laravel。
2)在模型中创建一个方法以用于前端使用。目的是缓存Model / Relations&amp; amp;翻译属性。
E.g AreaModel.php
public static function listAreas()
{
$areas = Cache::tags([ 'areas' ])
->rememberForever( "all:" . App::getLocale() , function() {
return self::
with(['relation_model_name']) // Fetch the Relation
->get()
->toArray();
});
return self::makeCollection( $areas ) ;
}
public static function makeCollection ( array $models = [] )
{
return self::hydrate( $models );
}
a)在这里,我们使用包含活动区域设置的密钥来查询查询
b)我们正在为相关模型添加with
c)我们只是缓存整个集合(No pluck
/ lists
)并转换回雄辩的模型实例。
优点是,现在在您的组件Area::listAreas();
中将返回缓存的集合,您可以像其他任何一样进行操作。
$areas = Area::listAreas(); // collection ( Area + Relation )
$dropdown = $areas->pluck('name', 'id'); // get Dropdown values for Areas...
一些考虑因素是每次记录更新,添加或删除(模型+关系)时清除缓存(删除缓存标记/密钥)。
Store Model
及其关系模型Business Type
的Redis缓存商店屏幕截图;
更新:
首先,我假设每个人都在我的例子中使用Redis道歉。原帖应该更侧重于实施。请不要像我一样复制/粘贴代码。
a)在我原来的回答中,我使用hydrate()
方法发布了代码,以便从缓存的记录中创建一个现有的模型实例。令人困惑的是不是必要的,但我怀疑它与rainlab翻译的相关查询有关。 (需要确认)
b)return self::whereNotNull('iso3166_2')->get()->lists('name','id')
足以缓存区域记录。
c)在我的评论中,我使用了pluck
因为lists
已被弃用。 pluck
会返回一个集合 - 请参阅here和here
$areas = self::whereNotNull('iso3166_2')->pluck('name', 'id') ; // collection
$areas->toArray();
我还没有在十月份尝试过基于文件的缓存,并且不确定它的行为是否与Redis一致。
再次,一些注意事项;
a)请在我的帖子中all + locale
与缓存标记areas
相关联,将缓存密钥命名为唯一且有意义的内容。例如areas.iso3166_2.locale
(避免覆盖)
b)添加Cache :: forget(&#39; key&#39;);在您的模型中afterSave
&amp; afterDelete
方法
c)如果您正在缓存相关模型,请在更改时清除缓存。
答案 2 :(得分:0)
另一个可能影响速度的想法(如果不是查询数量) - 索引模型的名称属性:
public $translatable = [
['name', 'index' => true]
];
参考:https://github.com/rainlab/translate-plugin#indexed-attributes