我正在努力完成以下作業。
- 我有一個 Moose 風格的模塊 A 和 B
- 需要元資料作為強制引數
- B想多次創建A的物件
- 因此想設定為屬性
有沒有更好的方法來做到這一點(這樣我可以將元資料傳遞給包 A 并在包 B 中避免多次呼叫 new ),如果可能的話,也嘗試完成 1 班輪。
package A {
use Moose;
has 'metadata' => (
is => 'rw',
isa => 'HashRef',
default => sub {{}},
required => 1
);
sub process {
die unless keys %{shift->metadata};
# ... process
print "Success!\n";
}
__PACKAGE__->meta->make_immutable;
}
#######B#########
package B {
use Moose;
use A;
has 'obj_a' => (
is => 'rw',
isa => 'A',
writer => 'set_meta',
);
sub _set_meta {
my ( $self, $metadata) = @_;
return $self->set_meta(A->new(metadata => $metadata));
}
sub obj_with_meta {
my ( $self, $metadata) = @_;
return A->new(metadata => $metadata);
}
__PACKAGE__->meta->make_immutable;
1;
}
############
use B;
my $b = B->new();
# want to call like this but I am sure I am missing something which moose is providing
# here I am supposed to call obj_a instead of _set_meta I believe
#calling _set_meta I am bypassing the Moose attribute I guess
$b->_set_meta({id=>'id for metadata'})->process;
#works
$b->obj_with_meta({id=>'id for metadata'})->process;
注意上面的代碼是作業輸出是成功!成功!
我想知道駝鹿身上是否有什么我可以利用的東西。這樣我就可以通過寫入元資料或使用某些特征來與下一個班級共享資料。
包 A 是催化劑控制器 包 B 是一個獨立的模塊,沒有與催化劑緊密耦合。
uj5u.com熱心網友回復:
在 Catalyst 應用程式中將業務邏輯與控制器分離是一個好主意。您可以將其封裝到自己的模塊中,并通過一個薄的 Catalyst::Model 層使用它們。
您實際上不需要擔心從控制器傳入會話,因為所有 Catalyst::Components 都為您提供了執行此操作的方法,稱為ACCEPT_CONTEXT. 這是一種可以在任何組件中實作的方法,但通常在模型中使用。每當$c->model(...)呼叫完成時都會呼叫它,它會傳遞背景關系物件$c,并且應該回傳一個可以像模型一樣使用的物件。這可能是也可能不是 Catalyst::Component 物件。
我已經構建了一個示例應用程式,我將使用它來回答這個問題。您可以在這個 github 存盤庫中找到完整的源代碼。
假設有一個名為 MyApp::Model::API::User 的 Catalyst::Model 類,代碼如下。它繼承自Catalyst::Model::DBI,以便通過 Catalyst 來利用資料庫句柄快取。
package MyApp::Model::API::User;
use strict;
use warnings;
use API::User;
use parent 'Catalyst::Model::DBI';
sub ACCEPT_CONTEXT {
my ( $self, $c, @args ) = @_;
$c->log->debug( sprintf 'Creating a new API::User object for %s line %d',
( caller(2) )[ 0, 2 ] );
return API::User->new(
dbh => $self->dbh,
metadata => $c->session->{data},
);
}
1;
每次控制器呼叫$c->model('API::User')該ACCEPT_CONTEXT方法時,它都會實體化一個名為 API::User 的類,這是我對與 Catalyst 無關的業務邏輯的實作。它接受 DBI 模型為我們提供的資料庫句柄物件,以及我們從用戶會話中獲取的元資料。
在我的示例中,我將用戶 ID 作為會話的一部分,以便可以使用實際的元資料(如果沒有,我們創建一個,但這在這里并不重要)。
package API::User;
use Moose;
use DBI;
has metadata => (
isa => 'HashRef',
is => 'ro',
required => 1, # either it's required or it has a default
);
has dbh => (
isa => 'DBI::db',
is => 'ro',
required => 1,
);
sub create { ... }
sub read {
my ($self) = @_;
my $sql = 'SELECT id, number_of_writes FROM user WHERE id=?';
my $sth = $self->dbh->prepare($sql);
$sth->execute( $self->metadata->{id} );
return $sth->fetchrow_hashref;
}
sub write { ... }
__PACKAGE__->meta->make_immutable;
API::User 有三個方法。它可以創建、讀取和寫入。作為一個例子,這一切都非常簡化。我們將重點閱讀這個答案。注意metadata屬性如何required,但沒有default。你不能同時擁有兩者,因為它們相互矛盾。您希望將其傳入,因此您希望它在丟失時爆炸,而不是設定空哈希參考的默認值。
最后,在 Controller 中使用如下。
package MyApp::Controller::User;
use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller' }
__PACKAGE__->config( namespace => 'user' );
sub auto : Private {
my ( $self, $c ) = @_;
unless ( $c->session->{data}->{id} ) {
# we have to initialise data first because the model depends on it
$c->session->{data} = {};
$c->session->{data}->{id} = $c->model('API::User')->create;
}
return 1;
}
sub index_get : Path('') Args(0) GET {
my ( $self, $c ) = @_;
$c->stash->{json_data} = $c->model('API::User')->read;
return;
}
sub index_post : Path('') Args(0) POST {
my ( $self, $c ) = @_;
$c->stash->{json_data} = $c->model('API::User')->write;
return;
}
__PACKAGE__->meta->make_immutable;
我在操作中設定了一些會話資料,這些資料在auto任何其他操作之前被呼叫。對于特定會話,這將完成一次,然后將該用戶的 ID 存盤在會話中以供后續請求使用。
在index_get我通過$c->model('API::User) 訪問我們的類的操作中,它將呼叫ACCEPT_CONTEXT我們的 Model 類,實體化一個新的 API::User 物件,該物件填充了現有的資料庫句柄以及包含我們用戶 ID 的會話元資料。
為了這個例子,我使用了一個 JSON 視圖,這樣我們就可以看到資料庫中發生了什么。
當我們 curl 應用程式以獲取我們的用戶時,日志如下所示。
[info] *** Request 2 (0.044/s) [31642] [Fri May 6 19:01:25 2022] ***
[debug] Path is "user"
[debug] "GET" request for "user" from "127.0.0.1"
[debug] Created session "36d509c55d60c02a7a0a9cbddfae9e50b092865a"
[debug] Creating a new API::User object for MyApp::Controller::User line 15
[debug] Creating a new API::User object for MyApp::Controller::User line 23
[debug] Response Code: 200; Content-Type: application/json; charset=utf-8; Content-Length: unknown
[info] Request took 0.018616s (53.717/s)
.------------------------------------------------------------ -----------.
| Action | Time |
------------------------------------------------------------ -----------
| /user/auto | 0.013309s |
| /user/index_get | 0.000640s |
| /end | 0.000994s |
| -> MyApp::View::JSON->process | 0.000411s |
'------------------------------------------------------------ -----------'
正如你所看到的,我們先去auto,然后去index_get。在上面的除錯陳述句中,它創建了兩個 API::User 實體。一個是auto創建一個新用戶,因為我沒有提供會話 cookie,第二個是來自index_get.
如果我們通過提供會話 cookie 與現有用戶一起呼叫它(請參閱存盤庫中的測驗腳本),它只會呼叫一次。
[info] *** Request 8 (0.037/s) [31642] [Fri May 6 19:04:16 2022] ***
[debug] Path is "user"
[debug] "GET" request for "user" from "127.0.0.1"
[debug] Found sessionid "710cb37124a7042b89f1ffa650985956949df7d0" in cookie
[debug] Restored session "710cb37124a7042b89f1ffa650985956949df7d0"
[debug] Creating a new API::User object for MyApp::Controller::User line 23
[debug] Response Code: 200; Content-Type: application/json; charset=utf-8; Content-Length: unknown
[info] Request took 0.017655s (56.641/s)
.------------------------------------------------------------ -----------.
| Action | Time |
------------------------------------------------------------ -----------
| /user/auto | 0.001887s |
| /user/index_get | 0.001238s |
| /end | 0.003510s |
| -> MyApp::View::JSON->process | 0.001463s |
'------------------------------------------------------------ -----------'
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/475698.html
