如何在 Moose 强制转换中访问对象的属性?

发布于 2024-10-19 14:35:23 字数 297 浏览 6 评论 0 原文

我想将我的 Moose 类中的属性的 Str 强制转换为 DBIx::Class::Row 对象。为此,我需要对 DBIC 架构执行查找以查找该行。如果查找失败,我想将错误推送到 ArrayRef 属性上。

我目前将架构作为属性传递给我的类。

通过强制,我似乎无法访问该对象,因此无法推送错误 arrayref 属性或使用架构对象来执行查找。

我尝试的另一种方法是在设置时使用“around”来查找和设置属性,但是当属性值通过构造函数传递时,这当然不会被调用。

这可能吗,或者有人有替代实现来实现我想要实现的目标吗?

I want to coerce a Str into a DBIx::Class::Row object for an attribute in my Moose class. To do this I need to perform a lookup on the DBIC schema to find the row. I want to push an error onto an ArrayRef attribute if the lookup failed.

I currently pass the schema in as an attribute to my class.

With coercion it appears I cannot access the object so I cannot push onto the error arrayref attribute or use the schema object to perform my lookup.

An alternative I tried was to use 'around' to lookup and set the attribute when set, but this of course does not get called when the attribute value is passed via the constructor.

Is this possible, or does someone have an alternative implementation to do what I want to achieve?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

零崎曲识 2024-10-26 14:35:23

您可以捕获并改变使用属性初始值设定项传递到构造函数时存储的值。 (但是,它仅在构造函数中设置属性时运行,而不是在任何其他时间运行。)可以在 类::MOP::属性

由于这仅捕获通过构造函数设置属性的情况,因此您仍然需要捕获设置属性的其他情况。正如您所说,这可以使用方法修饰符来完成,但是您可以将两者合并为一个方法,包裹在自动生成的访问器周围:

has my_attr => (
    is => 'rw',
    isa => 'DBIx::Class::Row',
    initializer => 'my_attr',
);

# my_attr is the autogenerated accessor - we method-modify it to mutate the
# value being set, and catch cases where it is called as an initializer.

# called for reads, writes, and on initialization at construction time
around 'my_attr' => sub {
    my $orig = shift;
    my $self = shift;
    # value is not defined if being called as a reader
    # setter and attr are only defined if being called as an initializer
    my ($value, $setter, $attr) = @_;

    # the reader behaves normally
    return $self->$orig if not @_;

    # convert the string to the row object
    my $row = $self->convert_str_to_row_obj($value);

    # if called as an initializer, set the value and we're done
    return $setter->($row) if $setter;

    # otherwise, call the real writer with the new value
    $self->$orig($row);
};

You can catch and mutate a value being stored when passed into a constructor with an attribute initializer. (However, it is only run when the attribute is set in the constructor, not at any other time.) Documentation for initializers can be found in Class::MOP::Attribute.

Since this only catches cases where the attribute is set via the constructor, you still need to catch the other cases where the attribute is set. This can be done with a method modifier as you said, but you can combine the two into one method, wrapped around the autogenerated accessor:

has my_attr => (
    is => 'rw',
    isa => 'DBIx::Class::Row',
    initializer => 'my_attr',
);

# my_attr is the autogenerated accessor - we method-modify it to mutate the
# value being set, and catch cases where it is called as an initializer.

# called for reads, writes, and on initialization at construction time
around 'my_attr' => sub {
    my $orig = shift;
    my $self = shift;
    # value is not defined if being called as a reader
    # setter and attr are only defined if being called as an initializer
    my ($value, $setter, $attr) = @_;

    # the reader behaves normally
    return $self->$orig if not @_;

    # convert the string to the row object
    my $row = $self->convert_str_to_row_obj($value);

    # if called as an initializer, set the value and we're done
    return $setter->($row) if $setter;

    # otherwise, call the real writer with the new value
    $self->$orig($row);
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文