The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

PEF::Front::Guide::QuickStart - a quick-start guide to the PEF::Front web framework.

DESCRIPTION

A quick-start guide with examples to get you up and running with the PEF::Front web framework.

PREPARATION

There're many possible ways to start your PSGI application. You can choose any that you like. Here is one of the most effective possible way.

nginx -> uwsgi -> PEF::Front(application)

Nginx accepts incoming requests and serves static content. Some defined request it passes to uwsgi. Which works as a very effective PSGI-server and passes semi-prepared requests to PEF::Front framework. Which runs your application on.

Approximate Nginx configuration

This is usually in /etc/nginx/sites-enabled/ directory. Alternatively you can put this (say, app-nginx.conf) configuration file in any directory you like and add include /$FULL_PATH_TO/app-nginx.conf to your nginx.conf file in http section.

server {
  listen 80 default_server;

  root /$PROJECT_DIR/www-static;
  access_log /$PROJECT_DIR/log/nginx.access.log;
  error_log /$PROJECT_DIR/log/nginx.error.log;
  client_max_body_size 100m;
  server_name $PROJECT.DOMAIN;
  # Static content
  location =/favicon.ico {}
  location /jss/ {}
  location /fonts/ {}
  location /images/ {}
  location /styles/ {}
  location /captchas/ {}
  # Dynamic content
  location / {
    include uwsgi_params;
    uwsgi_pass unix:///run/uwsgi/app/$UWSGI_APP/socket;
    uwsgi_modifier1 5;
  }
  location ~ /\. {
    deny all;
  }
}

Approximate uwsgi configuration

/etc/uwsgi/apps-available/$UWSGI_APP.ini
/etc/uwsgi/apps-enabled/$UWSGI_APP.ini is symbolic link 
 to /etc/uwsgi/apps-available/$UWSGI_APP.ini
 
[uwsgi]
plugins = psgi,logfile
chdir = /$PROJECT_DIR
logger = file:log/application.log
psgi = bin/startup.pl
master = true
processes = 10
stats = 127.0.0.1:5000
perl-no-plack = true
#cheaper-algo = spare
#cheaper = 3
#cheaper-initial = 6
#cheaper-step = 1
harakiri = 0
uid = $PROJECT_USER
gid = www-data
chmod-socket = 664

Typical project structure

cd $PROJECT_DIR
mkdir  app bin log model templates var www-static
mkdir app/$MyAPP
cd app/$MyAPP
mkdir InFilter Local OutFilter
cd var
mkdir cache captcha-db tt_cache upload
cd ../ www-static
mkdir captchas images jss styles

Now you are ready to start coding your application.

CONFIGURING

AppFrontConfig

Edit /$PROJECT_DIR/app/$MyAPP/AppFrontConfig.pm. Usually you need only something like this:

package $MyAPP::AppFrontConfig;
sub cfg_db_user      { $DBUSER }
sub cfg_db_password  { $DBPASSWORD }
sub cfg_db_name      { $DBNAME }
1;

When you don't need multilanguage support, then add

sub cfg_no_nls { 1 }
sub cfg_no_multilang_support { 1 }

More info about configuration is here.

startup.pl

Typical startup file

#!/usr/bin/perl

use lib qw'/$PROJECT_DIR/app';

use $MyAPP::AppFrontConfig;
use PEF::Front::Preload;

use PEF::Front::Route (
  '/'               => ['/index' 'R'],
  qr'/index(.*)'    => '/appIndex$1',
);

PEF::Front::Route->to_app();

PEF::Front::Preload makes database connect and builds validation subroutines for model method descriptions. It's very often needed to make route for '/' path but after that it's up to whether to use default routing scheme or amend it. See PEF::Front::Route for more info about routing.

APPLICATION

"Local" model handlers are located in /$PROJECT_DIR/app/$MyAPP/Local. For example, /$PROJECT_DIR/app/$MyAPP/Local/Article.pm:

package MyApp::Local::Article;
use DBIx::Struct qw(connector hash_ref_slice);
use strict;
use warnings;

sub get_articles {
  my ($req, $context) = @_;
  my $articles = all_rows(
      [   "article a" => -join => "author w",
          -columns => ['a.*', 'w.name author']
      ],
      -order_by => {-desc => 'id_article'},
      -limit    => $req->{limit},
      -offset   => $req->{offset},
      sub { $_->filter_timestamp->data }
  );
  for my $article (@$articles) {
      $article->{comment_count} =
        one_row([comment => -columns => 'count(*)'], {hash_ref_slice $article, 'id_article'})->count;
  }
  return {
      result   => "OK",
      articles => $articles,
      count    => one_row([article => -columns => 'count(*)'])->count
  };
}

Model description for this handler /$PROJECT_DIR/model/GetArticles.yaml:

---
params:
  limit:
    regex: ^\d+$        
    max-size: 3
  offset:
    regex: ^\d+$
    max-size: 10
model: Article::get_articles

Then this handler can be called from AJAX with request like:

GET /ajaxGetArticles?limit=5&offset=0

or from template:

[% articles="get articles".model(limit => 5, offset => 0) %]

AUTHOR

This module was written and is maintained by Anton Petrusevich.

Copyright and License

Copyright (c) 2016 Anton Petrusevich. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.