适用于任意树结构的 Catalyst 调度程序

发布于 2024-10-18 03:46:35 字数 841 浏览 3 评论 0原文

您好,

我是 Catalyst 的新手,我正在尝试实现一些调度逻辑。

我的数据库有一个项目表,每个项目都有一个唯一的 url_part 字段,并且每个项目在同一个表中都有一个父项,形成树结构。如果 bazbar 的子级,而 barfoo 的子级,而 foo 是根的子级,我想要 URL / foo/bar/baz 映射到该对象。树可以是任意深度,用户需要能够访问任何节点,无论是分支还是叶子。

我一直在查看链式调度程序的文档,但我不确定这是否可以达到我想要的效果。似乎链式调度程序中的每个步骤都必须为 PathPart 属性定义一个名称,但我希望我的 URL 仅由数据库结构确定。

使用现有的 Catalyst 调度程序很容易实现这一点,还是我需要编写自己的调度类?

谢谢! :)

ETA:

我发现我可以使用空的 Args 属性来捕获任意数量的参数。以下似乎成功捕获了根下的每个请求:

sub default :Path :Args() {
    my ( $self, $c ) = @_;

    my $path = $c->request->path;

    $c->response->status( 200 );
    $c->response->body( "Your path is $path" );
}

从那里我可以手动解析路径并获取我需要的内容,但是,我不知道这是否是完成我所追求的内容的最佳方式。

Greetings,

I'm new to Catalyst and I am attempting to implement some dispatch logic.

My database has a table of items, each with a unique url_part field, and every item has a parent in the same table, making a tree structure. If baz is a child of bar which is a child of foo which is a child of the root, I want the URL /foo/bar/baz to map to this object. The tree can be any depth, and users will need to be able to access any node whether branch or leaf.

I have been looking through the documentation for Chained dispatchers, but I'm not sure if this can do what I want. It seems like each step in a chained dispatcher must have a defined name for the PathPart attribute, but I want my URLs to be determined solely by the database structure.

Is this easy to implement with the existing Catalyst dispatcher, or will I need to write my own dispatch class?

Thanks! :)

ETA:

I figured out that I can use an empty Args attribute to catch an arbitrary number of arguments. The following seems to successfully catch every request under the root:

sub default :Path :Args() {
    my ( $self, $c ) = @_;

    my $path = $c->request->path;

    $c->response->status( 200 );
    $c->response->body( "Your path is $path" );
}

From there I can manually parse the path and get what I need, however, I don't know if this is the best way to accomplish what I'm after.

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

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

发布评论

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

评论(2

阳光下慵懒的猫 2024-10-25 03:46:35

这取决于您的数据结构,从您的问题中我并不完全清楚这一点。

如果有固定数量的级别(或者至少是有限范围的级别数量),每个级别对应于一种特定类型的事物,那么 Chained 可以做你想做的事——拥有一个与 :CaptureArgs(1) PathPart('') 的链式操作将在路径中创建一个 /*/ 段 - 也就是说,它会吞噬路径的一个段路径,不需要显示任何特定的固定字符串。

如果没有这样的事情——例如,您正在任意树上追逐无限数量的级别,那么可变参数 :Args 操作可能正是您想要的,并且使用它没有什么肮脏的地方。但您不需要自己解码 $c->req->path ——您可以从 $c->req-> 获取剩余的路径段;args,或者简单地在您的操作中执行 my ($self, $c, @args) = @_;
可以编写一个新的DispatchType,但它不太可能值得回报。

It depends on the structure of your data, which I'm not completely clear on from your question.

If there is a fixed number of levels (or at least a limited range of numbers of levels) with each level corresponding to a specific sort of thing, then Chained can do what you want -- it's valid (and downright common) to have a chained action with :CaptureArgs(1) PathPart('') which will create a /*/ segment in the path -- that is, it gobbles up one segment of the path without requiring any particular fixed string to show up.

If there's not any such thing -- e.g. you're chasing an unlimited number of levels down an arbitrary tree, then a variadic :Args action is probably exactly what you want, and there's nothing dirty in using it. But you don't need to be decoding $c->req->path yourself -- you can get the left-over path segments from $c->req->args, or simply do my ($self, $c, @args) = @_; in your action.
You can write a new DispatchType, but it's just not likely to be worth the payoff.

笑,眼淚并存 2024-10-25 03:46:35

在尝试了各种选择之后,我相信我已经找到了一个可以接受的解决方案。不幸的是,我无法使用 :Chained 进行递归调度(如果您尝试将处理程序链接到自身,Catalyst 会抱怨。这没什么好玩的。)

所以我最终使用了一个带有大容量的处理程序 。 CaptureArgs,如下所示:

sub default : CaptureArgs(10) PathInfo('') { 
    my ( $self, $c, @args ) = @_;

    foreach my $i( 0 .. $#args ) { 
        my $sub_path = join '/', @args[ 0 .. $i ];

        if ( my $ent = $self->_lookup_entity( $c, $sub_path ) ) { 
            push @{ $c->stash->{ent_chain} }, $ent;
            next;
        }

        $c->detach( 'error_not_found' );
    }

    my $chain = join "\n", map { $_->entity_id } @{ $c->stash->{ent_chain} };
    $c->response->content_type( 'text/plain' );
    $c->response->body( $chain );
}

如果我在 /foo/bar/baz 上执行 GET,我就会得到

foo
foo/bar
foo/bar/baz

我想要的。如果 URL 的任何部分与数据库中的对象不对应,我会得到 404。

这对于我的应用程序来说效果很好,它永远不会有十级深的东西,但我希望我能找到一个更通用的解决方案可以支持任意深度的树。

After playing around with various options, I believe I've arrived at an acceptable solution. Unfortunately, I couldn't get a recursive dispatch going with :Chained (Catalyst complains if you try to chain a handler to itself. That's no fun.)

So I ended up using a single handler with a large CaptureArgs, like this:

sub default : CaptureArgs(10) PathInfo('') { 
    my ( $self, $c, @args ) = @_;

    foreach my $i( 0 .. $#args ) { 
        my $sub_path = join '/', @args[ 0 .. $i ];

        if ( my $ent = $self->_lookup_entity( $c, $sub_path ) ) { 
            push @{ $c->stash->{ent_chain} }, $ent;
            next;
        }

        $c->detach( 'error_not_found' );
    }

    my $chain = join "\n", map { $_->entity_id } @{ $c->stash->{ent_chain} };
    $c->response->content_type( 'text/plain' );
    $c->response->body( $chain );
}

If I do a GET on /foo/bar/baz I get

foo
foo/bar
foo/bar/baz

which is what I want. If any part of the URL doesn't correspond to an object in the DB, I get a 404.

This works fine for my application, which will never have things ten-levels deep, but I wish I could find a more general solution that could support an arbitrary-depth tree.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文