How to call a Mojolicious controller method after failing on template - perl

I have a Mojolicious problem that I suspect has an easy solution, but I can't swim through all of its code.
$r->get(
'/:controller/:action',
sub {
my $c = shift;
$c->render_maybe && return;
# No template. Either call controller->action() or dispatch as POST
}
);
$r->post('/:controller/:action');
As you can see, I have two routes that use the same URL, one for GET and one for POST. The POST is straightforward. It renders after finding the controller and action method and isn't concerned with a template. I have the GET method working where a template exists, ignoring the controller, by using a callback with render_maybe(). My issue is, if there isn't a template, I want to go ahead and run the controller's method.
One solution would be to simply identify my controller and call the action. Since I'm using placeholders in my route, I can't simply hard code this. So, is there a Mojolicious way of getting my controller class, or actual code that will get the class and call the method? I have both controller and action defined in stash, so this really shouldn't be a big deal. Mojo knows how to do this internally.
Another option would be to convert this to a POST method and run it as normal. I don't know if it's best to either come up with the URL, or find the defined POST route, or just convert my GET to a POST. I'm not sure how to accomplish any of these.
Thanks.

I'm not sure if this is the intended use case for under(), but it seems to be a decent solution to my problem.
$r->under( '/:controller/:action', sub { !shift->render_maybe } )->get('/');
$r->post('/:controller/:action');
Chaining under()->get() will create a nested route. The first in the stack will render a template, if it exists, from the render_maybe, stopping there. If the template doesn't exist, it will go to the standard get(), which will first check for a controller action. This is exactly what I was wanting.

Related

backpack for laravel: how to customize routes?

We need to change every <anything>/show routes to something localized.
How can we customize the show string in something like dettagli ?
You can do in two way:
By creating a custom operation, starting from the default Show operation. Copy-paste the code of the ShowOperation.php in your project, and change the route. Then throughout your project use your ShowOperation, instead of the one provided by Backpack.
By overriding the protected function setupShowRoutes($segment, $routeName, $controller) in your CrudController. If you have that method in your ProductCrudController for example, your method will be run instead of the one in the ShowOperation trait. However, this needs to be done in all CrudControllers individually, so it's less DRY.

Magento: Accessing models/blocks from a phtml

Hi I have a situation where I need to look up the number of recently viewed products on catalog/product/view.phtml. In the recently viewed 'product_viewed.phtml' file it calls
$_products = $this->getRecentlyViewedProducts()
to get the recently viewed. How would I access this method from within the catalog/product/view.phtml file?
I don't know where this method is. I've tried searching for it but it doesn't seem to exist. When I write click it in Netbeans and click go to declaration it takes me to
class Mage_Reports_Block_Product_Viewed extends Mage_Reports_Block_Product_Abstract
Actually on the class itself. This class only has _toHtml(), getCount(), and getPageSize() methods.
I just need to know whether there are any recently viewed products.
Any help most appreciated!
Billy
If you look into 'Mage_Reports_Block_Product_Viewed', you will notice:
$this->setRecentlyViewedProducts($this->getItemsCollection());
That 'getItemsCollection' method is defined in the abstract class... And you will notice this abstract class will create a model based on $_indexName defined in the (subclassed) block.
If you just want the collection, you can probably get away with:
$_products = Mage::getModel('reports/product_index_viewed')->getCollection();
And then adding whatever you want to the collection:
$_products
->addAttributeToSelect('*')
->setAddedAtOrder();
// optionally add other methods similar to Mage_Reports_Block_Product_Abstract::getItemsCollection
Another approach that might be more suited would be to create the original block:
$productViewedBlock = $this->getLayout()->createBlock('reports/product_viewed');
On which you can simply call whatever you want:
$_collection = $productViewedBlock->getItemsCollection();
$_count = $productViewedBlock->getCount();
The getRecentlyViewedProducts function is a magical getter that gets the data that was set with setRecentlyViewedProducts in app/code/core/Mage/Reports/Block/Product/Viewed.php (which builds it using app/code/core/Mage/Reports/Block/Product/Abstract.php's function _getRecentProductsCollection).
This is complicated stuff that you don't want to reproduce; its better, IMO to make your own Block that extends Mage_Catalog_Block_Product_Abstract that will give you access to the same functionality, and drop your new block into the page you're working on.

Is it possible to route my simple URL (without specifing the module, controller and action) in Zend framework?

I am using zend framework for my project and I have a requirement to route the path where I want it. For example:
I have a path www.example.com/module/controller/action1 and I want to internally route in to www.example.com/module/controller/action2.
But the main problem is I do not want to use the function in which I have to specify the module, controller and action [$this->_forward('action2', 'controller', 'module');], simply I something like this: $this->_forward('module/controller/action2');.
Please suggest me if anybody has its solution. its urgent need of my project.
Thanks,
Jitu
The controller method _forward() can accept only the action if it is in the same controller and module as the first action you are forwarding from.
So in your action1Action() method, you can simply call:
$this->_forward('action2');
If your second action is not in the same module/controller, you could subclass Zend_Controller_Action into your own "base" application controller that all your other action controllers inherit from (a good practice on ZF projects I find) and then create another one called _forwardFromUrl() or something like that, which breaks your URL apart and passes it to _forward() (or create an action controller helper if you just need this one extra thing).
This example is simplified and assumes your $url will always be in the format module/controller/action:
protected function _forwardFromUrl($url)
{
$parts = array_reverse(explode("/",$url));
$this->_forward($parts[0],$parts[1],$parts[2]);
}
Hope that helps!

ASP.NET MVC 2 - Set ViewData on every request in specific area (without inheritance)

In the "Admin" area of my application, an object must be available in ViewData on every page (for display in the Master template). I have already inherited from Controller, so I cannot make a simple base class that handles it. What is a good solution of doing this when not using inheritance? An ActionFilter seems interesting but I don't want to put it on every controller in the Admin area. I'm considering the following:
Custom ControllerFactory that detects Area as well
Application_BeginRequest(), though I have no knowledge on executing controller then.
Maybe you have a better solution?
In this case I would create a separate action that executes a partial view that shows the data you need. In my opinion this is the most clean solution for this kind of problem and it's easily testable and reusable.
i have a dropdown on my masterpage. you dont need viewdata for it. i did it like this
code on masterpage:
<%= Html.DropDownList("schselectr", MVC2_NASTEST.MvcApplication.masterSchooljaarList())%>
in Global.asax.cs
public static SelectList masterSchooljaarList() {
NASDataContext _db = new NASDataContext();
List<Schooljaar> newlist = _db.Schooljaars.ToList();
return new SelectList(_db.Schooljaars.ToList(), "Sch_Schooljaar", "Sch_Schooljaar");
}
so simply, it calls the method, which returns the data i need, every time you load the page. easy, clean, effective.

zend_form access parent form element

I couldn't find any reference on how to use a parent form element in a subclassed form. May be because it's obvious to everyone but me. It's got me stumped. This is what I tried.
At first, within my form constructor I called
parent::__construct($options = null);
then accessed the parent elements like this
$type = parent::setName($this->type);
The problem was that ALL the parent form elements would display whether explicitly called or not. Someone said, "don't use __construct(), use the init() function instead. So I changed the constructor to init(), commented out the parent constructor, then ran the form. It bombed saying it couldn't pass an empty value for setName(). I commented out all the seName() calls and the form ran, but only displayed the elements instantiated in the subclassed form.
My question is this: If I don't use the parent constructor, how do i get and use the parent's form elements?
Solved: Since the constructor was switched to init, the call to the parent also needed to be switched. Easy for someone with php background. Not so much for one who doesn't.
Use
parent::init();
Solved: Since the constructor was switched to init, the call to the parent also needed to be switched. Easy for someone with php background. Not so much for one who doesn't.
Use
parent::init();
You should learn OOP principles first. Obviously you have no understanding of it whatsoever. You need to call parent::init() in you Form_Class::init() method as you wrote, but why? Because otherwise the parent method is not called and is overriden by the From_Class method.
Other thing is that when you have a parent class "SuperForm" with input and submit, then your "SuperForm_Subclass" would have the same elements assigned. There is no need to use "parent::*" to access element (only exception would be if you used static SuperForm variable to store them - which makes no sense).
You can easily use $this->inputElement and $this->submitElement inside your SuperForm_Subclass like you would in the SuperForm class.
In your example you could used the __contruct() as good, but with the same condition of calling the parent constructor. You would be able to access elements generated there too...