I would like to be able to move Controllers, Models etc from their default Mojolicious paths:
- App
- Controller
- Namespace1
- ...
- Namespace2
- ...
- Model
- Namespace1
- ...
- Namespace2
- ...
into something a little more manageable, such as:
- App
- Namespace1
- Controller
- ...
- Model
- ...
- Namespace2
- Controller
- ...
- Model
- ...
So instead of
$r->any('/api/test')->to('Namespace1::Controller1#test');
I could call something like
$r->any('/api/test')->to('App::Namespace1::Controller1#test');
How does one accomplish this in Mojolicious?
CodePudding user response:
It turns out that you can specify the namespace like this:
$r->any('/api/test')->to(
namespace => 'App::Namespace1',
controller => 'Controller::Controller1',
action => 'test'
);
Which would call the test
method from the controller App::Namespace1::Controller::Controller1
See Mojolicious Routing for details
CodePudding user response:
I have no idea what you are doing, but it looks like you might have too mode code in your Mojo app. Maybe not, but I've seen this pattern a few times. If this doesn't apply to you, just ignore it. It certainly applies to other people who may read answers to your question.
First, I've done as you've done: specify the prefix namespace in to()
. I prefer that because it helps me (and others) find the class in projects where there are lots of controller namespaces (as well as de-conflict namespace collisions).
You can also push namespace prefixes:
push @{$app->routes->namespaces}, 'MyApp::MyController';
People tend to shove what could be several different services into a monolithic Mojo app, and eventually that leads to some sort of conflict. Consider, for instance, two completely different sets of routes that both want to start with /api
but have nothing to do with each other.
The controllers are there to receive and control the transaction, and it's much nicer if they only concern themselves with that. Nicer often means "I have to type less to get to the file I want". But, it also means that the Models should not be tied to any particular Controller. The a good Model should be independent and reusable. That's the point of their separation of concerns.
- App
- Controller
- MajorPartOfApp
- ...
- UnrelatedPartOfApp
- ...
- Model
- NotTiedToAnyController
- StillNotTiedToAnyController
When the Model is not independent, and it's specifically made to serve a particular Controller (or set of them), reuse gets messy. I'd much rather have general Models. Suppose that you add another major section for the application, but a Model from an existing Controller could handle it. Now the naming convention breaks down because you are reaching across namespaces unrelated to your task. Alternately, I've seen people create additional Models that use the same source but have a different interface. That duplicates code.
as an aside: forget about syntax and statements when you talk about code readability. I'd trade some hard-to-grok code for better project structure so I don't have to look in weird places for code I should use. For instance, why would I look in CatStuff.pm when I need to do things with dogs? Poor architecture and organization is more painful to me.
I tend to like command line programs, so I like to do the same tasks that the web app enables but from the terminal. And, here's the real test of code separation. Can I use the same components to make terminal tools? If the Controllers and Models are lightweight wrappers, that means I can easily use the stuff they wrap for a completely different non-Mojo project. If I can't easily do that, I've probably made the Controllers or Models too complicated.
It should be easier to make new tools, not harder. That's the "options triangle". If my range of options narrow (so, approaching the pointy part of the triangle) the further I get into the project, I've probably done things incorrectly. If my options widen, I'm probably doing it better.
The usual objection is that these things will never interact with each other. Well, then, that's a question of code management and deployment. If they really are two separate things, I'd prefer them to be actually separate. I don't always get my way though (maybe not even usually ;) Maybe you don't get your way either.