我知道我可以在我的课程中延伸\DB\SQL\Mapper
:
public function getAll()
{
$this->upperBody = 'upper(body)';
$all = $this->find();
return $all;
}
然后,在调用时,此模型将具有虚拟(计算)属性upperBody
,该属性将保存数据库中body
字段的大写值。
但是,我仅限于底层数据库引擎在功能方面提供的功能。
是否有可能以这种方式使用这些动态字段:
$this->stripped_tags = strip_tags($this->body);
当然假设我们在数据库中有一个现有的body
字段?
如果没有,那么我将如何编写自己的过滤器以在模板中使用,从而改为{{@post.body|strip_tags}}
...或者例如{{@post.body|excerpt 30}}
。
我使用cast()
:
foreach ($this->model->getAll() as $p) {
$c = $p->cast();
$c[ 'excerpt' ] = chop_string( strip_tags($c[ 'body' ], '<p>'), $this->excerpt_limit);
$all_posts[] = $c;
}
$f3->set('posts', $all_posts);
但似乎必须有更优雅的方法来实现这一点,因为在这里我将数组处理加倍,只是为了分配一个新的计算属性。
那么有没有办法一次完成这一切?
AMEND 1:正如@ikkez建议我尝试这样做:
在我的模型类中,我添加了一个名为upperTitle
的属性,如下所示:
public $upperTitle;
然后在控制器中我有这样的代码:
$this->mdlPost->upperTitle = strtoupper($this->mdlPost->title);
使用$this->mdlPost->paginate(...,...,...)
查询数据库后
和var_dumping,upperTitle
是一个空字符串。
AMEND 2:(@ikkez评论中提出)
public function __construct(\DB\SQL $db)
{
$this->db = $db;
parent::__construct($db, 'posts');
$this->onload(function($self){
$self->set('upper_title', strtoupper($self->get('title')));
});
}
再次,没有成功。
转储映射器对象后,这可能会有所帮助吗?
因此它可以作为adhoc显示,但是作为mapper对象本身的属性为null。
我可以看到该值为NULL
,表达式应该是值。这就是为什么在模板中执行@post.upper_title
时获取空输出的原因,那么您将如何解决此问题。通常情况下,表达式会获取查询字符串,而值是执行该查询的结果,但显然情况并非如此。
答案 0 :(得分:2)
只需添加要在映射器中动态使用的字段作为类的属性,您应该能够即时使用它:
...
.state('myapp.child', {
url: '/child',
controller: function ($state, foo, bar) {
function someEvent() {
// Provision $stateParams to prevent fetching
$state.go($state.current, {foo: foo, bar:bar});
}
},
params: {
foo: null,
bar: null
},
resolve: {
/**
* @ngInject
*/
foo: function(fooService, $stateParams) {
if ($stateParams.foo !== null) { // <= Duplication
return foo;
} else {
return fooService.get();
}
},
/**
* @ngInject
*/
bar: function(barService, $stateParams) {
if ($stateParams.bar !== null) { // <= Duplication
return bar;
} else {
return barService.get();
}
}
}
});
答案 1 :(得分:2)
Mapper
实现稍微复杂一点,人们不希望看到源代码。首先,您不应该尝试设置不存在的映射器字段,因为Mapper
实现将它们解释为需要由数据库引擎派生的虚拟字段。这也是值为NULL
的原因。相反,你应该使用真实的类属性(如ikkez所说)。
提示
Mapper->cast()
方法忽略了类属性,因此如果想要使用它,则应该调整cast()
方法。
定义虚拟字段仅在查询数据库之前有效。
<强>解决方案强>
不要通过致电Mapper->set()
或设置Mapper->field = …
(内部调用Mapper->set()
)来创建(或更新)虚拟字段
改为创建类属性
使用ONLOAD
事件填充属性
<强>段强>
以下代码段显示了如何使用ONLOAD
触发器定义用于存储以编程方式派生的值的自定义类属性。可执行示例位于:https://gist.github.com/Rayne/fd24f5b664788cdf35956222ce790c02
/**
* @property string title
* @see https://gist.github.com/Rayne/fd24f5b664788cdf35956222ce790c02
*/
class TestMapper extends \DB\SQL\Mapper {
/**
* Custom mapper field which isn't backed and persisted by the database.
*
* @var null|string
*/
public $upper_title;
/**
* @param \DB\SQL $sql
*/
public function __construct(\DB\SQL $sql) {
parent::__construct($sql, 'test');
$this->onload(function (TestMapper $mapper) {
$mapper->upper_title = strtoupper($mapper->title);
});
}
}
从数据库中读取:
$mapper = new TestMapper($sql);
for ($mapper->load(); !$mapper->dry(); $mapper->next()) {
printf("title: %s\n", $mapper->title);
printf("upper_title: %s\n", $mapper->upper_title);
}
结果:
title: Hello World
upper_title: HELLO WORLD
答案 2 :(得分:1)
似乎最好的方法是在模板中定义自己的过滤器。它被描述为in the user guide。如果您需要的代码多于给定的代码,请随时告诉我。