{"id":16307904,"url":"https://github.com/ap/catalyst-view-template","last_synced_at":"2025-08-21T06:43:22.333Z","repository":{"id":54462865,"uuid":"306946439","full_name":"ap/Catalyst-View-Template","owner":"ap","description":"Template Toolkit meets Catalyst","archived":false,"fork":false,"pushed_at":"2022-08-08T23:26:40.000Z","size":29,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-25T00:08:47.230Z","etag":null,"topics":["perl","perl-catalyst","template-toolkit","templatetoolkit"],"latest_commit_sha":null,"homepage":"https://metacpan.org/release/Catalyst-View-Template","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ap.png","metadata":{"files":{"readme":"README.pod","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-24T18:28:24.000Z","updated_at":"2024-03-14T16:16:20.000Z","dependencies_parsed_at":"2022-08-13T16:20:44.877Z","dependency_job_id":null,"html_url":"https://github.com/ap/Catalyst-View-Template","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/ap/Catalyst-View-Template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FCatalyst-View-Template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FCatalyst-View-Template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FCatalyst-View-Template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FCatalyst-View-Template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ap","download_url":"https://codeload.github.com/ap/Catalyst-View-Template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ap%2FCatalyst-View-Template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271436836,"owners_count":24759422,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["perl","perl-catalyst","template-toolkit","templatetoolkit"],"created_at":"2024-10-10T21:15:42.821Z","updated_at":"2025-08-21T06:43:22.302Z","avatar_url":"https://github.com/ap.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"=pod\n\n=encoding UTF-8\n\n=head1 NAME\n\nCatalyst::View::Template - Template Toolkit meets Catalyst\n\n=head1 SYNOPSIS\n\n package MyApp::View::Web;\n use parent 'Catalyst::View::Template';\n 1;\n \n package MyApp;\n __PACKAGE__-\u003econfig( default_view =\u003e 'Web' );\n 1;\n \n package MyApp::Controller::Root;\n __PACKAGE__-\u003econfig( namespace =\u003e '' );\n sub end : ActionClass('RenderView') {}\n 1;\n\n=head1 DESCRIPTION\n\nThis is a L\u003cCatalyst\u003e view class for the L\u003cTemplate Toolkit|Template\u003e\nwith the following design objectives:\n\n=over 2\n\n=item * To be as close as possible to direct use of L\u003cTemplate Toolkit|Template\u003e\n\n=item * To nevertheless integrate seamlessly with L\u003cCatalyst\u003e\n\n=item * To be easily augmented in behaviour by overriding or modifying methods\n\nTaken together with the other objectives, this should make it easy to repurpose\nfor any view class in which you might want to use Template Toolkit templates.\n\n=back\n\nThis is a rethink of L\u003cCatalyst::View::TT\u003e whose focus is on\nproviding lots of L\u003cCatalyst\u003e-specific features on top of Template Toolkit,\nbut which are hard to augment without copy-pasting code from it, and\nwhich ultimately only make templates harder to reuse or test in other contexts.\n\n=head1 DEFAULT OPERATION\n\nAs with any Catalyst view, you create a subclass of it for your application,\nsomething like C\u003cMyApp::View::Web\u003e. Generally you then forward to C\u003cView::Web\u003e\nfrom the C\u003cend\u003e action of your root controller, which indirectly invokes its\nL\u003c/process\u003e method:\n\n package MyApp::Controller::Root;\n \n __PACKAGE__-\u003econfig( namespace =\u003e '' );\n \n # ...\n \n sub end : Private {\n   my ( $self, $c ) = ( shift, @_ );\n   $c-\u003eforward( $c-\u003eview( 'Web' ) ) # just $c-\u003eview if set as default_view\n     if  $c-\u003ereq-\u003emethod ne 'HEAD'\n     and $c-\u003eresponse-\u003estatus !~ /^20[14]$|^3[0-9][0-9]$/\n     and ( not defined $c-\u003eresponse-\u003ebody )\n     and ( not @{ $c-\u003eerror } );\n }\n \n 1;\n\nThis picks an appropriate template to render for the request,\nusing the data you put into the C\u003c\u003c $c-\u003estash \u003e\u003e as template variables,\nthen sets C\u003c\u003c $c-\u003eresponse-\u003econtent_type \u003e\u003e and C\u003c\u003c $c-\u003eresponse-\u003ebody \u003e\u003e.\n\nThe name of the template processed\ncorresponds to the private path of the dispatched action,\nunless you specify a template explicitly using the C\u003ctemplate\u003e stash key.\nThe value of L\u003c/template_ext\u003e is appended to the template name\nbefore calling Template Toolkit to process it,\nwhich will look in C\u003cINCLUDE_PATH\u003e to find the corresponding file.\n\nSo if you consider the C\u003clobster\u003e action in a controller called C\u003cEssay\u003e:\n\n package MyApp::Controller::Essay;\n sub lobster : Local {\n   my ( $self, $c ) = ( shift, @_ );\n   # ...\n }\n\nThis will be invoked when you go to C\u003chttp://localhost:5000/essay/lobster\u003e.\nThe private path of this action is C\u003cessay/lobster\u003e.\nIf L\u003c/template_ext\u003e is set to C\u003c.tt2\u003e and C\u003cINCLUDE_PATH\u003e is left unchanged,\nthat means the template that will be rendered is C\u003cF\u003croot/essay/lobster.tt2\u003e\u003e.\n\nTo set L\u003c/template_ext\u003e or other configuratin options you can use\nthe usual mechanisms available in Catalyst:\n\n=over 3\n\n=item 1.\n\nCalling the C\u003cconfig\u003e class method in the view class:\n\n package MyApp::View::Web;\n use parent 'Catalyst::View::Template';\n \n __PACKAGE__-\u003econfig(\n   template_ext =\u003e '.tt',\n   PRE_PROCESS  =\u003e 'config/main',\n   WRAPPER      =\u003e 'site/wrapper',\n );\n \n 1;\n\n=item 2.\n\nCalling the C\u003cconfig\u003e class method in the application class\nand passing it a configuration section named after the view class:\n\n package MyApp;\n \n # ...\n \n __PACKAGE__-\u003econfig(\n   'View::Web' =\u003e {\n     INCLUDE_PATH =\u003e [\n       __PACKAGE__-\u003epath_to( 'root', 'src' ),\n       __PACKAGE__-\u003epath_to( 'root', 'lib' ),\n     ],\n   },\n );\n \n 1;\n\n=item 3.\n\nCalling the C\u003cconfig\u003e class method in the application class indirectly,\nthrough a plugin such as L\u003cCatalyst::Plugin::ConfigLoader\u003e,\nand putting the configuration section into a configuration file.\n\n=back\n\n=head1 CONFIGURATION\n\nBy default, L\u003cCatalyst::View::Template\u003e instantiates Template Toolkit as\nfollows:\n\n Template-\u003enew( {\n   EVAL_PERL    =\u003e 0,\n   ENCODING     =\u003e 'UTF-8',\n   INCLUDE_PATH =\u003e [ $c-\u003epath_to( 'root' ) ],\n } )\n\nYou can override any or all of these settings or add others by passing any of\nL\u003cthe Template Toolkit configuration options|Template::Manual::Config\u003e\nthrough the configuration of your view class.\nYou can also override L\u003c/new_template\u003e\nfor control over the final set of configuration values.\n\nThe following non-L\u003cTemplate\u003e configuration options are also available:\n\n=head2 C\u003ccontent_type\u003e\n\nThe content type which will be set on the response,\nunless one has been set already.\n\nDefaults to C\u003ctext/html; charset=utf-8\u003e\n\n=head2 C\u003ctemplate_ext\u003e\n\nA suffix to add to the template name\njust before passing it to L\u003cTemplate/process\u003e.\n\nDefaults to the empty string.\n\n=head2 C\u003cclass_name\u003e\n\nThe template class to instantiate. E.g. for easier XSS protection:\n\n package MyApp::View::Web;\n use parent 'Catalyst::View::Template';\n __PACKAGE__-\u003econfig(\n   class_name  =\u003e 'Template::AutoFilter',\n   AUTO_FILTER =\u003e 'html',\n );\n\nDefaults to L\u003cTemplate\u003e.\n\n=head1 METHODS\n\nThis class inherits everything in L\u003cCatalyst::Component\u003e.\n\nAdditionally it implements the following methods:\n\n=head2 C\u003cnew_template\u003e\n\n $view-\u003enew_template( $c, \\%config )\n\nThis is called by the constructor to construct the L\u003cTemplate\u003e instance.\nIt gets passed the configuration hash to pass to L\u003cTemplate/new\u003e\nand is expected to return an instance of L\u003cTemplate\u003e or something like it.\nIt throws an exception on failure.\n\nB\u003cYou might want to override this method in your view class\u003e\nto modify the result of merging all static class configuration.\n\nMost likely you might use this to inject values into the C\u003cINCLUDE_PATH\u003e\nin C\u003c\\%config\u003e and then pass through to the super method.\nBut you could also construct an instance yourself,\neither to completely bypass all defaults (including L\u003c/class_name\u003e),\nor maybe to not throw an exception on error.\n\n=head2 C\u003cprocess\u003e\n\n $view-\u003eprocess( $c )\n\nThis decides which template to call L\u003c/render\u003e on,\nthen calls it with a copy of the C\u003c\u003c $c-\u003estash \u003e\u003e.\nThe template name is taken from C\u003c\u003c $c-\u003eaction-\u003ereverse \u003e\u003e by default,\nor from C\u003c\u003c $c-\u003estash-\u003e{'template'} \u003e\u003e if that has been set.\n\nOn success it then calls L\u003c/process_output\u003e on the output.\nIf template execution fails it calls L\u003c/process_error\u003e.\nIt returns whatever the called method returns.\n\nB\u003cYou might want to override this method in your view class\u003e\nif you want additional steps taken when the view is forwarded to,\nbut which should not be taken when L\u003c/render\u003e is called directly.\n\n=head2 C\u003crender\u003e\n\n $view-\u003erender( $c, $template, \\%vars, \\$output )\n $view-\u003erender( $c, $template, \\%vars, \\$output, ... )\n\nThis renders the template named by C\u003c$template\u003e and the L\u003c/template_ext\u003e\nconfiguration option into C\u003c$output\u003e, passing it the values from C\u003c\\%vars\u003e,\nand returns true on success.\nIn other words, the default implementation means it is a shorthand for this:\n\n $view-\u003etemplate-\u003eprocess( $template . $view-\u003etemplate_ext, \\%vars, \\$output )\n\nAs usual, you can also forward to this method:\n\n $c-\u003eforward( 'View::Web', 'render', $template, \\%vars, \\$output )\n\nB\u003cYou might want to override this method in your view class\u003e\nif you always want certain additional steps taken before rendering a template.\nE.g. you would use this to add a standard set of variables to the variables\npassed to any template, in which case you will want to modify C\u003c\\%vars\u003e and\nthen pass through to the super method.\n\nE.g. to mimic the standard L\u003cCatalyst::View::TT\u003e behaviour:\n\n sub render {\n   my ( $self, $c, $vars ) = ( shift, @_ );\n   my %extra_vars = (\n     c    =\u003e $c,\n     base =\u003e $c-\u003ereq-\u003ebase,\n     name =\u003e $c-\u003econfig-\u003e{'name'},\n   );\n   @$vars{ keys %extra_vars } = values %extra_vars;\n   $self-\u003enext::method( @_ );\n }\n\nIn other words, overriding this method has much the same uses as overriding\nL\u003cCatalyst::View::TT/template_vars\u003e.\nHowever, your method remains in the call stack during template execution,\nso you can do things like this:\n\n sub render {\n   my ( $self, $c, $vars ) = ( shift, @_ );\n   $vars{'helper_might_croak'} = sub { $c-\u003eapp_method_that_might_croak( @_ ) };\n   local $Carp::Internal{(__PACKAGE__)} = 1;\n   $self-\u003enext::method( @_ );\n }\n\nYou could do this more conveniently with L\u003cCatalyst::View::TT/expose_methods\u003e,\nbut the L\u003cC\u003c%Carp::Internal\u003e|Carp/%Carp::Internal\u003e line means exceptions caused\nby code in a template will be reported from the call site in the template,\nrather than from where the helper closure was defined in the view class.\nL\u003cCatalyst::View::TT\u003e could be modified to offer this for helpers added\nthrough C\u003cexpose_methods\u003e,\nbut your view class will not be able to do this for helpers\nadded through an overridden C\u003ctemplate_vars\u003e method.\n\n=head2 C\u003cprocess_output\u003e\n\n $view-\u003eprocess_output( $c, $template_name, \\%vars, \\$output )\n $view-\u003eprocess_output( $c, $template_name, \\%vars, \\$output, ... )\n\nThis sets C\u003c\u003c $c-\u003eresponse-\u003ebody \u003e\u003e to C\u003c$output\u003e\nand C\u003c\u003c $c-\u003eresponse-\u003econtent_type \u003e\u003e to C\u003c\u003c $view-\u003econtent_type \u003e\u003e\n(unless a content type has already been set),\nthen it returns true.\n\nB\u003cYou might want to override this method in your view class\u003e\nto use the output somewhere other than the HTTP response, e.g. for e-mail.\n\n=head2 C\u003cprocess_error\u003e\n\n $view-\u003eprocess_error( $c, $template_name, \\%vars )\n $view-\u003eprocess_error( $c, $template_name, \\%vars, ... )\n\nThis logs C\u003c\u003c $view-\u003etemplate-\u003eerror \u003e\u003e at the C\u003cerror\u003e level\nand sets it as a C\u003c\u003c $c-\u003eerror \u003e\u003e,\nthen it returns false.\n\nB\u003cYou might want to override this method in your view class\u003e\nin rare cases only, like in an ancillary view (or some such)\nwhere setting C\u003c\u003c $c-\u003eerror \u003e\u003e might be too drastic.\n\n=head1 DIFFERENCES FROM L\u003cCatalyst::View::TT\u003e\n\n=over 2\n\n=item *\n\nThe biggest difference is probably\nthat C\u003ctemplate_ext\u003e is appended to the template name in the L\u003c/render\u003e method\nrather than just one branch in L\u003c/process\u003e, which means it is not only appended\nto the default template name derived from C\u003c\u003c $c-\u003eaction-\u003ereverse \u003e\u003e,\nbut also to C\u003c\u003c $c-\u003estash-\u003e{'template'} \u003e\u003e and even to template names passed\nto L\u003c/render\u003e directly. Effectively you always use action paths to refer to\ntemplates rather than hardcoding your preferred extension for templates all\nover the code.\n\n=item *\n\nThe L\u003c/render\u003e method works exactly like L\u003cTemplate/process\u003e: it takes\na scalar reference for storing the output and returns a boolean success value.\n\nThis is very much unlike the original design of L\u003cCatalyst::View::TT/render\u003e,\nwhich returns either the output or a Template Toolkit error object and leaves\nyou to examine the value to figure out which case you are dealing with.\nThis mistake was fixed by L\u003cCatalyst::View::TT/render_die\u003e,\nat the the cost of guarding every C\u003crender\u003e call with an C\u003ceval\u003e.\n\n=item *\n\nThere are no standard variables passed to templates by default.\nMost particularly there is no automatically passed C\u003cc\u003e variable\n(nor any other name for the C\u003c$c\u003e context object)\nbecause it only encourages unhealthy chumminess of the templates\nwith the request object and especially the model.\nCatalyst is certainly not suited for the kind of quick and dirty small project\nwhere one might even conceivably get away with that sort of misbehaviour.\n\n=item *\n\nThere is no equivalent to L\u003cCatalyst::View::TT/expose_methods\u003e.\nThis feature offers syntactic sugar for something already trivially simple\nbut which should nevertheless not be done lightly.\n\n=item *\n\nThere is no equivalent to L\u003cCatalyst::View::TT/additional_template_paths\u003e.\nThis seems too specialised a feature to support by default.\nIf you need it you can implement it in your view class without too much code:\n\n use Template::Provider ();\n \n {\n   my $dynamic_path = bless {}, do {\n     package MyApp::Template::DynamicPath;\n     sub paths { $_[0]{'paths'} || [] }\n     __PACKAGE__\n   };\n \n   sub dynamic_path { $dynamic_path }\n }\n \n sub new_template {\n   my ( $self, $c, $config ) = ( shift, @_ );\n   $config-\u003e{'INCLUDE_PATH'} = Template::Provider-\u003enew( $config )-\u003einclude_path;\n   unshift @{ $config-\u003e{'INCLUDE_PATH'} }, $self-\u003edynamic_path;\n   $self-\u003enext::method( @_ );\n }\n \n sub render {\n   my ( $self, $c ) = ( shift, @_ );\n   local $self-\u003edynamic_path-\u003e{'paths'} = $c-\u003estash-\u003e{'additional_template_paths'};\n   $self-\u003enext::method( @_ );\n }\n\nSee L\u003cTemplate::Manual::Config/INCLUDE_PATH\u003e for details.\n\n=back\n\n=head1 SEE ALSO\n\nL\u003cCatalyst::Manual\u003e, L\u003cTemplate::Manual\u003e\n\n=cut\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fap%2Fcatalyst-view-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fap%2Fcatalyst-view-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fap%2Fcatalyst-view-template/lists"}