Reading http://search.cpan.org/~ether/Catalyst-Manual-5.9009/lib/Catalyst/Manual/Tutorial/02_CatalystBasics.pod I see $c->stash(template => 'hello.tt');.
There is a template, but where is the view? Why is the view not specified explicitly?
Also: How to call a view explicitly (not by the template name)?
This can be a little tricky because it is a combination of extremely flexible and plain DWIW. The .tt in the template name indicates that Template::Toolkit is the presumptive default. It's not necessary to use this View at all but it is used in most of the documentation.
You can render whatever is in your stash/$ctx by forwarding to a view: $c->forward($c->view("JSON")); for example, or you can decide for the rest of the request cycle like this $c->stash( current_view => "CSV" ). You have to have the view(s) installed and configured in your application, of course. You can also use views directly-
my $body = $c->view("Xslate")->render($c, "folder/email_template.tx", $params);
A tricky part becomes what your end method(s) will do.
The generally recommended default is Catalyst::Action::RenderView. It is smart (and flexible if you want to change its behavior). If you have set a redirect, for example, it won't render a page, it will just do the redirect. If you have already generated $c->response->body content it will also "just stop" and trust that what you've already done is what you wanted.
There is enough complexity in the flexibility that I really recommend just putting together a toy app run in the restarting dev server and trying out all the things you want to understand better. None of it is that hard in itself but it all adds up to confusion unless you break it down into digestible chunks.
Related
Roald has written an excellent guide for the Twincat Eventlogger.
https://roald87.github.io/twincat/2020/11/03/twincat-eventlogger-plc-part.html
https://roald87.github.io/twincat/2021/01/20/twincat-eventlogger-hmi-part.html
For us this is exactly what we want, there is however 1 thing I haven't figured out. How to get the sourcename of the alarm in multiple languages in the HMI. params::sourceName gives the path in the software (example: MAIN.fbConveyor1.Cylinder1) This path can be customized when initializing the alarm (as Roald has shown). This doesn't work in my case, since I would like to define a generic alarm (example: "Cilinder not retracted within maximum time") that is instantiated multiple times.
I was thinking of using the source as a way to show the operator where the alarm occurs. We use this way (path) already for saving machine settings among other things. The machines we build are installed all over the world, so multilanguage is a must.
Beckhoff does support multilanguage alarm names (when defined), but the source is not defined, but dynamically generated.
Anyone have an idea how this problem can be solved?
If I understand your question correctly, then being able to parameterize the event text with information of the source of the problem should help you out.
If you define the event text as Cylinder {0} has not retracted in time. then you can add the arguments of that text during runtime.
IF bRaiseAlarm THEN
bRaiseAlarm := FALSE;
fbAlarm.ipArguments.Clear().AddString('Alice');
fbAlarm.Raise(0);
END_IF
However, since this also stated in the articles you mentioned, I am unsure if this would solve your problem.
'Alice' in this example, can be hard to localize. The following options come to my mind.
The string can be based on an ENUM. Enums can have textlist support, so if you add your translations there, that should allow multilingual output. However... this does require a lot of setup, placing translations inside your code, and making sure the PLC application is aware of the language that the parameter should use.
Use tags to mark the source device, as tags can be language invariant. It is not the most user-friendly method, but it could work for you. It would become something like: "Cylinder 'AA.1123' did not retract in time.". 'AA.1123' as a tag would have to be stored inside your PLC code as a string. You will have to trust that your operator can relate the tag back to the actual source.
Hopefully, this helped, or else please help me understand the problem better.
I have a large Catalyst app and want to get a list of all endpoints it supports (bonus points if it can tell me if the request method). Is there some easy way to ask Catalyst to list them?
Catalyst does not know the full set of paths. The true dispatch paths are resolved dynamically, iterating through DispatchType classes until one responds favourably to a call of match.
The debug option does a one-time enumeration of all possibilities that your controllers allow. If you want to interfere with this, you have to look at Catalyst::Dispatcher::_display_action_tables
It's a tree-walking algorithm that iterates through each route it finds at '/' and follows each subsequent route that $controller->actions returns. It's not easy to read, but you could conceivably implement a version of _display_action_tables that doesn't just print to a table, but does something else instead. Then call it in the live application with $c as argument and see what happens!
i've got a problem that i wasn't able to solve yet, and hope you can help :)
i have build a CataPLACK-Application with a web-interface. Now i am supposed to establish a JSON/REST/XML-Api, so i thought i could do something like this:
/ => root
/blog/ => ...
/news/ => ...
/api =>chainedTo(root) PathPart(api) Args(1) { set_view($arg) };
how do i loop back api to root (/), so i can redispatch the whole request with a different view without having to establish a lot of "fake routines" ?
i feel there must be a clean way ...
Have a look at the differences between $c->forward / $c->detach and $c->visit / $c->go in the manual. I think you'll find you can probably build a $c->go() construct from within your api method that achieves what you're after.
It's still a bit messy though, particularly if you have to de-reference the URI back to an action manually.
You can achieve the same effect with a lot less hassle by adding the 'api' path-part at the end rather than the beginning, so it just becomes an argument to the request that you can test for in your auto sub, and set whatever stash variables you need. Then you don't need to do any re-dispatching. Only you can decide whether such a URI scheme will be clean enough and appropriate for your application.
A week or two ago I just started using Zend Framework seriously and have had trouble escaping manually with Zend_View::escape().
Does anyone knows how to escape vars in templates (Zend_View templates) automatically without using $this->escape(), or any other tricky ways like output buffering and PREG replacing *.phtml files.
I'd like to know the best practice in this case.
You can extend Zend_View to create a custom view class which autoescapes things, or you can use a view helper to turn autoescaping on/off.
I have written a blogpost about it, with example code for both approaches:
How to automatically escape template variables in Zend_View
Over at the PiKe project we build a custom stream wrapper that automatically escapes all view variables, with a MINIMAL performance hit! You can still get the RAW value with:
<?=~ $variable ?>
Notice the "~" character. Checkout http://code.google.com/p/php-pike/wiki/Pike_View_Stream
I know you said that you want to avoid "tricky ways like output buffering and PREG replacing *.phtml files.", but I still think it's a very neat way to fix auto escaping in Zend Framework 1.
You said "automatically", so I believe that that means when you do echo $this->var; you want it escaped. Well, if that's the case, maybe you could do the escaping when the variable is set to the view. AFAIK it's done in the Zend_View_Abstract class' __set magic method* (around line 300). Changing the core ZF code is not recommended, so you could go by extending Z_V_A or Z_V and just override the __set method.
*I'm not 100% sure that Z_V_A::__set is the only place where the params are assigned to the view, but I think it should be. Can't think of any other place for that.
Edit: Personally, I'd avoid this and just stick with the good ol' $this->escape(). More typing but less magic going on in the background.
You have asked for best practice then what you are doing is already it.
Wait till when you want to display your data before modifying it only for output reasons.
I understand you find writting ->escape() everytime tedious but its still the way to go.
If you where to auto escape everything then you would run into problems one day when you want/need unescaped data.
ZendX_View_Autoescaping, this project provides you a ViewRenderer with autoescaping of all assigned view variables.
https://github.com/jensklose/ZendX_View_Autoescaping
Try it!
It supports:
escaping into deep data structures
escaping the array keys
possibility to switch the escaping context (html, json, nofilter)
I have seen the examples of Net::OpenID::Consumer::Lite on CPAN but I was hoping to get a single script that uses POST method. If nobody has this than I will post my solution back here once I get it working.
This seems to be the only applicable test in the manifest and it doesn't seem too useful
http://cpansearch.perl.org/src/TOKUHIROM/Net-OpenID-Consumer-Lite-0.02/xt/001_mixi.t Apache2::AuthMixi also uses it a bit
This module simply delegates to LWP::UserAgent. I don't like it, it should subclass LWP::UserAgent instead of delegating. You can find the docs for LWP::UserAgent on cpan, and access the base copy through the hidden method _ua (though, by convention, the preceding underscore tells you it isn't supported and it is supposed to be kept secret)
my $csr = Net::OpenID::Consumer::Lite->new();
$csr->_ua->post(); # same as LWP::UserAgent::post()
It seems as if you're supposed to use only handle_server_response() which calls _check_authentication() which calls _get() which delegates to ->_ua->get().
check_authentication() wants an HashRef jump-table with 5 events for not_openid, setup_required, cancelled, verified, and error. In addition I believe it wants a bunch of key (openid.) prefixed stuff, and values.
Per the code, for a request to be sent $request->{'openid.mode'} must exist in the $request and be set (preferably to) check_authentication, and not set to 'cancel'. The openid.user_setup_url key must logically not be set or it will just call the respective callback. It must also have an op_endpoint.endpoint key set, which is where the request is destined to go.
This code isn't hard to read, I'd suggesting taking a look The author also seems to have a bunch of modules which is a good sign. I don't like jump-tables with data like that, it seems kind of weird from a UI perspective.