NAME
Yancy::Controller::Yancy - Basic controller for displaying content
VERSION
version 1.088
SYNOPSIS
use Mojolicious::Lite;
plugin Yancy => {
schema => {
blog => {
properties => {
id => { type => 'integer' },
title => { type => 'string' },
html => { type => 'string' },
},
},
},
};
app->routes->get( '/' )->to(
'yancy#list',
schema => 'blog',
template => 'index',
);
__DATA__
@@ index.html.ep
% for my $item ( @{ stash 'items' } ) {
<h1><%= $item->{title} %></h1>
<%== $item->{html} %>
% }
DESCRIPTION
This controller contains basic route handlers for displaying content configured in Yancy schema. These route handlers reduce the amount of code you need to write to display or modify your content.
Route handlers use the Mojolicious stash
for configuration. These values can be set at route creation, or by an under
route handler.
Using these route handlers also gives you a built-in JSON API for your website. Any user agent that requests JSON will get JSON instead of HTML. For full details on how JSON clients are detected, see "Content negotiation" in Mojolicious::Guides::Rendering.
METHODS
schema
Get the Yancy::Model::Schema object to handle the current request. This uses the schema
stash value to look up the schema from the default model. Override the default model using the model
stash value.
item_id
Get the ID for the currently-requested item, if available, or undef
.
clean_item
Clean the given item by removing any sensitive fields (like passwords).
list
$routes->get( '/' )->to(
'yancy#list',
schema => $schema_name,
template => $template_name,
);
This method is used to list content.
Input Stash
This method uses the following stash values for configuration:
- schema
-
The schema to use. Required.
- template
-
The name of the template to use. See "Renderer" in Mojolicious::Guides::Rendering for how template names are resolved. Defaults to
yancy/table
. - limit
-
The number of items to show on the page. Defaults to
10
. - page
-
The page number to show. Defaults to
1
. The page number will be used to calculate theoffset
parameter to "list" in Yancy::Backend. - filter
-
A hash reference of field/value pairs to filter the contents of the list or a subref that generates this hash reference. The subref will be passed the current controller object (
$c
).This overrides any query filters and so can be used to enforce authorization / security.
- order_by
-
Set the default order for the items. Supports any "list" in Yancy::Backend
order_by
structure. - join
-
One or more schemas to join when returning results.
- before_render
-
An array reference of hooks to call once for each item in the
items
list. See "ACTION HOOKS" for usage.
Output Stash
The following stash values are set by this method:
- items
-
An array reference of items to display.
- total
-
The total number of items that match the given filters.
- total_pages
-
The number of pages of items. Can be used for pagination.
Query Params
The following URL query parameters are allowed for this method:
- $page
-
Instead of using the
page
stash value, you can use the$page
query paremeter to set the page. - $offset
-
Instead of using the
page
stash value, you can use the$offset
query parameter to set the page offset. This is overridden by the$page
query parameter. - $limit
-
Instead of using the
limit
stash value, you can use the$limit
query parameter to allow users to specify their own page size. - $order_by
-
One or more fields to order by. Can be specified as
<name>
orasc:<name>
to sort in ascending order ordesc:<field>
to sort in descending order. - $match
-
How to match multiple field filters. Can be
any
orall
(defaultall
).all
means all fields must match for a row to be returned.any
means at least one field must match for a row to be returned. - Additional Field Filters
-
Any named query parameter that matches a field in the schema will be used to further filter the results. The stash
filter
will override this filter, so that the stashfilter
can be used for security.
Content Negotiation
If the GET
request accepts content type is application/json
, or the URL ends in .json
, the results page will be returned as a JSON object with the following keys:
- items
-
The array of items for this page.
- total
-
The total number of results for the query.
- offset
-
The current offset. Get the next page of results by increasing this number and setting the
$offset
query parameter.
get
$routes->get( '/:id_field' )->to(
'yancy#get',
schema => $schema_name,
template => $template_name,
);
This method is used to show a single item.
Input Stash
This method uses the following stash values for configuration:
- schema
-
The schema to use. Required.
- "id_field"
-
The ID field(s) for the item should be defined as stash items, usually via route placeholders named after the field.
# Schema ID field is "page_id" $routes->get( '/pages/:page_id' )
- template
-
The name of the template to use. See "Renderer" in Mojolicious::Guides::Rendering for how template names are resolved.
- join
-
One or more schemas to join when returning results.
- before_render
-
An array reference of helpers to call before the item is displayed. See "ACTION HOOKS" for usage.
Output Stash
The following stash values are set by this method:
- item
-
The item that is being displayed.
Content Negotiation
If the GET
request accepts content type is application/json
, or the URL ends in .json
, the item will be returned as a JSON object.
set
# Update an existing item
$routes->any( [ 'GET', 'POST' ] => '/:id_field/edit' )->to(
'yancy#set',
schema => $schema_name,
template => $template_name,
);
# Create a new item
$routes->any( [ 'GET', 'POST' ] => '/create' )->to(
'yancy#set',
schema => $schema_name,
template => $template_name,
forward_to => $route_name,
);
This route creates a new item or updates an existing item in a schema. If the user is making a GET
request, they will simply be shown the template. If the user is making a POST
or PUT
request, the form parameters will be read, the data will be validated against the schema configuration, and the user will either be shown the form again with the result of the form submission (success or failure) or the user will be forwarded to another place.
Displaying a form could be done as a separate route using the yancy#get
method, but with more code:
$routes->get( '/:id_field/edit' )->to(
'yancy#get',
schema => $schema_name,
template => $template_name,
);
$routes->post( '/:id_field/edit' )->to(
'yancy#set',
schema => $schema_name,
template => $template_name,
);
Input Stash
This method uses the following stash values for configuration:
- schema
-
The schema to use. Required.
- "id_field"
-
The ID field(s) for the item should be defined as stash items, usually via route placeholders named after the field. Optional: If not specified, a new item will be created.
# Schema ID field is "page_id" $routes->post( '/pages/:page_id' )
- template
-
The name of the template to use. See "Renderer" in Mojolicious::Guides::Rendering for how template names are resolved.
- before_write
-
An array reference of helpers to call after the new values are applied to the item, but before the item is written to the database. See "ACTION HOOKS" for usage.
- forward_to
-
The name of a route to forward the user to on success. Optional. Any route placeholders that match item field names will be filled in.
$routes->get( '/:blog_id/:slug' )->name( 'blog.view' ); $routes->post( '/create' )->to( 'yancy#set', schema => 'blog', template => 'blog_edit.html.ep', forward_to => 'blog.view', ); # { id => 1, slug => 'first-post' } # forward_to => '/1/first-post'
Forwarding will not happen for JSON requests.
- properties
-
Restrict this route to only setting the given properties. An array reference of properties to allow. Trying to set additional properties will result in an error.
NOTE: Unless restricted to certain properties using this configuration, this method accepts all valid data configured for the schema. The data being submitted can be more than just the fields you make available in the form. If you do not want certain data to be written through this form, you can prevent it by using this.
Output Stash
The following stash values are set by this method:
- item
-
The item that is being edited, if the
id
is given. Otherwise, the item that was created. - errors
-
An array of hash references of errors that occurred during data validation. Each hash reference is either a JSON::Validator::Error object or a hash reference with a
message
field. See the yancy.validate helper docs and "validate" in JSON::Validator for more details.
Query Params
This method accepts query parameters named for the fields in the schema.
Each field in the item is also set as a param using "param" in Mojolicious::Controller so that tag helpers like text_field
will be pre-filled with the values. See Mojolicious::Plugin::TagHelpers for more information. This also means that fields can be pre-filled with initial data or new data by using GET query parameters.
CSRF Protection
This method is protected by Mojolicious's Cross-Site Request Forgery (CSRF) protection. CSRF protection prevents other sites from tricking your users into doing something on your site that they didn't intend, such as editing or deleting content. You must add a <%= csrf_field %>
to your form in order to delete an item successfully. See "Cross-site request forgery" in Mojolicious::Guides::Rendering.
Content Negotiation
If the POST
or PUT
request content type is application/json
, the request body will be treated as a JSON object to create/set. In this case, the form query parameters are not used.
delete
$routes->any( [ 'GET', 'POST' ], '/delete/:id_field' )->to(
'yancy#delete',
schema => $schema_name,
template => $template_name,
forward_to => $route_name,
);
This route deletes an item from a schema. If the user is making a GET
request, they will simply be shown the template (which can be used to confirm the delete). If the user is making a POST
or DELETE
request, the item will be deleted and the user will either be shown the form again with the result of the form submission (success or failure) or the user will be forwarded to another place.
Input Stash
This method uses the following stash values for configuration:
- schema
-
The schema to use. Required.
- "id_field"
-
The ID field(s) for the item should be defined as stash items, usually via route placeholders named after the field.
# Schema ID field is "page_id" $routes->get( '/pages/:page_id' )
- template
-
The name of the template to use. See "Renderer" in Mojolicious::Guides::Rendering for how template names are resolved.
- forward_to
-
The name of a route to forward the user to on success. Optional. Forwarding will not happen for JSON requests.
- before_delete
-
An array reference of helpers to call just before the item is deleted. See "ACTION HOOKS" for usage.
Output Stash
The following stash values are set by this method:
- item
-
The item that will be deleted. If displaying the form again after the item is deleted, this will be
undef
.
CSRF Protection
This method is protected by Mojolicious's Cross-Site Request Forgery (CSRF) protection. CSRF protection prevents other sites from tricking your users into doing something on your site that they didn't intend, such as editing or deleting content. You must add a <%= csrf_field %>
to your form in order to delete an item successfully. See "Cross-site request forgery" in Mojolicious::Guides::Rendering.
feed
$routes->websocket( '/' )->to(
'yancy#feed',
schema => $schema_name,
);
Subscribe to a feed of changes to the given schema. This first sends a list result (like "list" would). Then it sends change messages. Change messages are JSON objects with different fields based on the method of change:
# An item in the list was changed
{
method => "set",
# The position of the changed item in the list, 0-based
index => 2,
item => {
# These are the fields that changed
name => 'Lars Fillmore',
},
}
# An item was added to the list
{
method => "create",
# The position of the new item in the list, 0-based
index => 0,
item => {
# The entire, newly-created item
# ...
},
}
# An item was removed from the list. This does not necessarily mean
# the item was removed from the database.
{
method => "delete",
# The position of the item removed from the list, 0-based
index => 0,
}
TODO: Allow the client to send change messages to the server.
Input Stash
This method uses the following stash values for configuration:
- schema
-
The schema to use. Required.
- limit
-
The number of items to show on the page. Defaults to
10
. - page
-
The page number to show. Defaults to
1
. The page number will be used to calculate theoffset
parameter to "list" in Yancy::Backend. - filter
-
A hash reference of field/value pairs to filter the contents of the list or a subref that generates this hash reference. The subref will be passed the current controller object (
$c
).This overrides any query filters and so can be used to enforce authorization / security.
- order_by
-
Set the default order for the items. Supports any "list" in Yancy::Backend
order_by
structure. - before_render
-
An array reference of hooks to call once for each item in the
items
list before they are sent as messages. See "ACTION HOOKS" for usage.
Query Params
The following URL query parameters are allowed for this method:
- $page
-
Instead of using the
page
stash value, you can use the$page
query parameter to set the page. - $offset
-
Instead of using the
page
stash value, you can use the$offset
query parameter to set the page offset. This is overridden by the$page
query parameter. - $limit
-
Instead of using the
limit
stash value, you can use the$limit
query parameter to allow users to specify their own page size. - $order_by
-
One or more fields to order by. Can be specified as
<name>
orasc:<name>
to sort in ascending order ordesc:<field>
to sort in descending order. - $match
-
How to match multiple field filters. Can be
any
orall
(defaultall
).all
means all fields must match for a row to be returned.any
means at least one field must match for a row to be returned. - Additional Field Filters
-
Any named query parameter that matches a field in the schema will be used to further filter the results. The stash
filter
will override this filter, so that the stashfilter
can be used for security.
ACTION HOOKS
Every action can call one or more of your application's helpers. These helpers can change the item before it is displayed or before it is saved to the database.
These helpers get one argument: An item being displayed, created, saved, or deleted. The helper then returns the item to be displayed, created, or saved.
use Mojolicious::Lite -signatures;
plugin Yancy => { ... };
# Set a last_updated timestamp when creating or updating events
helper update_timestamp => sub( $c, $item ) {
$item->{last_updated} = time;
return $item;
};
post '/event/:event_id' => 'yancy#set',
{
event_id => undef,
schema => 'events',
helpers => [ 'update_timestamp' ],
forward_to => 'events.get',
},
'events.set';
Helpers can also be anonymous subrefs for those times when you want a unique behavior for a single route.
# Format the last_updated timestamp when showing event details
use Time::Piece;
get '/event/:event_id' => 'yancy#get',
{
schema => 'events',
helpers => [
sub( $c, $item ) {
$item->{last_updated} = Time::Piece->new( $item->{last_updated} );
return $item;
},
],
},
'events.get';
EXTENDING
Here are some tips for inheriting from this controller to add functionality.
- set
-
When setting field values to add to the updated/created item, use
$c->req->param
not$c->param
. The underlying code uses$c->req->param
to get all of the params, which will not be updated if you use$c->param
.
DIAGNOSTICS
- Page not found
-
If you get a
404 Not Found
response or Mojolicious's "Page not found... yet!" page, it could be from one of a few reasons:- No route with the given path was found
-
Check to make sure that your routes match the URL.
- Configured template not found
-
Make sure the template is configured and named correctly and the correct format and renderer are being used.
The Mojolicious debug log will have more information. Make sure you are logging at
debug
level by running indevelopment
mode (the default), or setting theMOJO_LOG_LEVEL
environment variable todebug
. See MODE in the Mojolicious tutorial for more information.
TEMPLATES
To override these templates, add your own at the designated path inside your app's templates/
directory.
yancy/table.html.ep
The default list
template. Uses the following additional stash values for configuration:
- properties
-
An array reference of columns to display in the table. The same as
x-list-columns
in the schema configuration. Defaults tox-list-columns
in the schema configuration or all of the schema's columns inx-order
order. See "Documenting Your Schema" in Yancy::Guides::Schema for more information. - table
-
get '/events' => ( controller => 'yancy', action => 'list', table => { thead => 0, # Disable column headers class => 'table table-responsive', # Add a class }, );
Attributes for the table tag. A hash reference of the following keys:
- thead
-
Whether or not to display the table head section, which contains the column headings. Defaults to true (
1
). Set to false (0
) to disable<thead>
. - show_filter
-
Show filter input boxes for each column in the header. Pressing
Enter
will filter the table. - id
-
The ID of the table element.
- class
-
The class(s) of the table element.
SEE ALSO
AUTHOR
Doug Bell <preaction@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2021 by Doug Bell.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.