[Moscow.pm] Mouse хочу странного
Ilya Chesnokov
chesnokov.ilya на gmail.com
Чт Окт 17 03:35:48 PDT 2013
17 октября 2013 г., 2:25 пользователь Ivan Petrov
<i.petro.77.00 на gmail.com>написал:
> есть допустим объект
>
>
> package User;
> use Mouse;
> has name => is => 'ro', isa => 'Str';
>
> далее роль у него составляющая некие списки юзеров
>
> with 'User::List';
>
> ...
>
> package User::List;
> use Mouse::Role;
>
> sub list {
> ... возвратит список пользователей
> }
>
> sub list_by_some {
> ... возвратит еще какой-то список
> }
>
> ну понятно
>
> далее у юзеров могут быть допустим заказы. всю работу с заказами
> выносим в отдельную роль (тут в примере работа со списками заказов)
>
>
> package User::Order::List;
> use Mouse::Role;
>
> sub list_orders {
> ... возвратит список заказов пользователя
> }
>
> или игрушки
>
> package User::Toy::List;
> use Mouse::Role;
>
> sub list_toys {
> ... возвратит игрушки пользователя
> }
>
> Ну вот, в большом проекте накапливается у некоторых сущностей много
> разных ролей (или иерархия наследования, тут по разному можно
> смотреть, это непринципиально).
>
> и хочется писать далее не
>
> $user->list_orders;
> $user->list_toys;
>
> а организовать нечто вроде неймспейсов ролевых.
>
> то есть я хочу чтобы можно было написать
>
> ns 'User::Order::List' => as => 'orders';
> ns 'User::Toy::List' => as => 'toys';
>
> в основном классе и далее чтобы можно было обращаться к его методам
> так:
>
> $user->orders->list;
> $user->toys->list;
>
> то есть очень похоже на контейнер, но это не контейнер.
> это неймспейс.
> функция $user->orders->list в качестве self должна получать объект $user.
>
> то есть
>
> has things => is => 'ro', isa => 'User::Thing::List';
>
> тут не подходит. можно прослойку сделать на базе has конечно, но я
> боюсь сильно просесть на бенчмарках.
>
> что еще хочется:
> - has внутри namespace
> - в идеале наследования какого-то всей этой "хрени с которой
> взлетать", но в целом наследование мы почти не применяем в Mouse,
> поэтому не сильно актуально
>
>
> я примерно представляю как такое написать, но
>
> 1. может быть кто-то писал уже подобное? дайте ссылку
> 2. сейчас сильно занят другими проектами, но если бы кто взялся мог бы
> профинансировать появление подобного модуля на cpan :) с
> документацией, тестами и сравнительными бенчмарками
> (сравниваем с Mouse::Role). Пусть бенчмаркает вдвое хуже метода
> Mouse::Role, но не хуже чем вдвое. Я думаю можно сделать чтобы
> бенчмаркало соизмеримо.
>
> кто что думает?
>
>
Действительно странного хотите.
По-моему более очевидно для каждой сущности (игрушка, заказ, пользователь)
сделать отдельный класс (не роль), в котором прописать, в какой таблице
хранятся записи для этого класса, а в роль вынести как раз работу с БД.
Примерно так мы делаем в нашем проекте на работе. При этом никто не мешает
добавить в класс User метод orders(), который будет возвращать список
заказов данного пользователя. И, что важно, сможет сделать обратное -
например, добавить в класс Toy метод users(), который выдаст юзеров,
пользующихся данной игрушкой (а как вы это будете делать с неймспейсами -
непонятно).
Из $self, который вы хотите получать в качестве параметра, вам нужно только
значение первичного ключа, который вы добавите в поисковый запрос.
Кусок кода, который иллюстрирует вышесказанное, приведен ниже (я в нём
использую более привычный мне Moose, но код на Mouse должен выглядеть
похоже, если не идентично).
package Role::DatabaseObject;
use Moose::Role;
requires 'table';
sub list {
my $self = shift;
return $self->_list_table($self->table, @_);
}
sub _list_table {
my ($self, $table, @args) = @_;
# свой код для выборки из $table с поиском по параметрам @args
}
sub list_related {
my ($self, $related_table, @args) = @_;
# Это если внешний ключ связанной таблицы имеет вид $foreign_table .
'_id',
# иначе делайте свой маппинг.
my $key_name = $self->table . '_id';
my $key_value = $self->get_column_value($foreign_key_name);
return $self->_list_table(
$related_table,
@args,
$foreign_key_name => $foreign_key_value
);
}
# Это можно добавить в BUILD, а можно добавлять в каждый класс вручную - в
зависимости
# от того, как будет удобнее и что фантазия позволит
sub add_relations {
my ($class, %class_mapping) = @_;
while (my ($relation, $related_class) = each %class_mapping) {
$class->meta->add_method(
$relation => sub {
my ($self) = @_;
require $related_class;
return $self->list_related($related_class->table),;
}
);
}
}
package User;
use Moose;
with 'Role::DatabaseObject';
sub table { 'user' }
__PACKAGE__->add_relations(
orders => 'Order',
toys => 'Toy',
);
package Order;
use Moose;
with 'Role::DatabaseObject';
sub table { 'order' }
# здесь логика работы с заказами
1;
package Toy;
use Moose;
with 'Role::DatabaseObject';
sub table { 'toy' }
__PACKAGE__->add_relations(users => 'User');
# здесь логика работы с игрушками
1;
--
Best regards,
Ilya Chesnokov
----------- следущая часть -----------
Вложение в формате HTML было извлечено…
URL: <http://mail.pm.org/pipermail/moscow-pm/attachments/20131017/634c53d4/attachment-0001.html>
Подробная информация о списке рассылки Moscow-pm