NAME
Yancy::Guides::Model - Building modules for your application's business logic
VERSION
version 1.080
DESCRIPTION
This guide describes how to extend Yancy::Model to add custom business logic.
Model Classes
There are three types of classes in Yancy::Model
:
- Model
-
The model class represents the entire database and contains schemas.
- Schema
-
Schema classes represent individual tables, views, or collections and contain items.
- Item
-
Item classes represent individual records from the database.
Using the Default Model
The default Yancy::Model class contains basic CRUD (Create, Retrieve, Update, Delete) methods.
Setup
For now, you must set up the model manually by creating a Yancy::Model object, passing in a Yancy::Backend:
my $model = Yancy::Model->new( backend => $backend );
Schemas
Get a schema using the schema
method:
my $users = $model->schema( 'users' );
This returns a Yancy::Model::Schema object (or a custom schema class, see "Schema Classes").
Creating Items
To create an item, use the create
method on the schema:
my $user_id = $model->schema( 'users' )->create({
username => 'bender',
password => 'shiny',
});
Only the ID of the new item is returned.
Lookup by ID
To look up an item by its ID, use the get
method on the schema.
my $bender = $model->schema( 'users' )->get( $bender_id );
This method returns a Yancy::Model::Item object (or a custom item class, see "Item Classes").
Search
To search for items, use the list
method on the schema. The list
method returns a hash reference with items
and total
keys. items
is an array reference of Yancy::Model::Item objects. total
is the total number of items that match the query.
my $result = $model->schema( 'users' )->list({ active => 1 });
if ( $result->{total} > 0 ) {
my @users = $result->{items}->@*;
say "Found $result->{total} active users: ",
map { $_->{username} } @users;
}
Updating Items
To update an item, first get the item object and then call set
to update its data.
my $bender = $model->schema( 'users' )->get( $bender_id );
$bender->set({ password => 'daffodil' });
Bulk-updating items is not yet supported, but may be added in a later release (patches welcome!)
Deleting Items
If you already have an item, you can use its delete
method to delete it. Otherwise, you can delete an item by its ID.
$model->schema( 'users' )->get( $user_id )->delete;
$model->schema( 'users' )->delete( $user_id );
Bulk-deleting items is not yet supported, but may be added in a later release (patches welcome!)
Relationships
Related data can be prefetched and added to an item using the join
option to get
or list
.
my $user = $model->schema( 'users' )->get( $id, join => 'user_roles' );
my $result = $model->schema( 'users' )->list( {}, join => 'user_roles' );
The resulting data is added in a key named for the join:
my $roles = $user->{user_roles};
TODO: Items could have a related
method that gets related data after-the-fact.
Future Development: Queries
In the future, a query
method may be added that will return an object that can build up arguments for a call to the list
method, as well as act as a cursor for that call.
Starting a Custom Model
When building your own model layer, you only need to create classes when you want to add custom code. By default, the Yancy::Model class will load classes from all of its configured namespaces.
Make sure to add your namespace to the "namespaces" in Yancy::Model array:
unshift @{ $model->namespaces }, 'MyApp';
This adds MyApp::Schema
as a namespace for schema classes, and MyApp::Item
as a namespace for item classes.
Create a Model Class
If you need it, you can create a model class by extending Yancy::Model.
package MyApp::Model;
use Mojo::Base 'Yancy::Model', -signatures;
Your model class could include methods for the most common data lookups:
sub get_user( $self, $id ) {
return $self->schema( 'user' )->get( $id );
}
Your model class should also store configuration needed by the other classes:
# Invitation e-mails come from this address
has email_from => 'no-reply@example.com';
Schema Classes
Schema classes contain code for working with the entire schema or a subset of the schema. Any code that affects more than one item should live in the schema class.
To create a schema class, extend Yancy::Model::Schema. The name of the schema class should be the camel-cased version of the schema's name.
package MyApp::Schema::User; # schema: 'user'
use Mojo::Base 'Yancy::Model::Schema', -signatures;
The schema class should contain methods that work on the collection: Creating new items, searching for items.
# Invite a new user
sub invite( $self, $email ) {
my $id = $self->create({ email => $email });
$self->get( $id )->send_invite_mail;
return $id;
}
Item Classes
Item classes contain code for working on a single item.
To create an item class, extend Yancy::Model::Item. The name of the item class should be the camel-cased version of the schema's name.
package MyApp::Item::User;
use Mojo::Base 'Yancy::Model::Item', -signatures;
# Send the invite mail to this user
sub send_invite_mail( $self ) {
my $to = $self->data->{email};
my $from = $self->model->email_from;
# TODO: Send e-mail
}
SEE ALSO
Yancy::Model, Yancy::Guides::Schema, Yancy::Backend, Yancy::Guides
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.