Stefan Hornburg (Racke)
No Act on ACT
PerlDancer for Perlers (FOSDEM 2011)
Modern Perl for web applications
More Reasons for "No act on ACT"
Perl Dancer Conference Website
Conferences
YAPC::EU 2008 in Copenhagen

PerlDancer for Perlers (FOSDEM 2011)

Perl Dancer Conference 2014

http://act.perl.dance/eic2014/
Using ACT in 2013/2014
-
Managed software
-
Listed in other conferences (Marketing)
-
User database
Modern Perl for web applications
-
PSGI / Plack
-
Web application framework (Dancer2)
-
Web framework (Bootstrap, Jquery)
-
DBIx::Class
-
Moo and friends
-
Testing
mod_perl vs PSGI
-
Apache / mod_perl
-
slow
-
memory footprint
-
deployment related code
-
-
PSGI
-
runs on any webserver supporting PSGI
-
fast (Nginx)
-
simple configuration (Nginx)
-
no deployment related code
-
Apache version
Apache/1.3.42 (Unix) mod_perl/1.31
more than 6 years old
Dancer2 Advantages
-
Clean OO interface
-
Routes
-
Hooks
-
Engines
-
Multiple Applications
-
Web application
-
REST API
-
Admin interface
-
Manual SQL vs DBIx::Class
-
Manual SQL
-
error prone
-
compatibility problems
-
less secure
-
-
DBIx::Class
-
Business logic
-
works on dozens of RDBMS
-
usually faster
-
more secure
-
More Reasons for "No act on ACT"
-
Single Point of Failure
-
Development
-
Responsiveness
-
No https://
Single Point of Failure
-
Baltimore Perl Workshop
-
Eventbrite
Development
-
Last commit on ACT: July 2015 https://github.com/book/Act
-
Last commit on ACT in the box: September 2015
Hackathon in Lyon

Responsiveness
Picture by Guillaume Brocker, CC BY-SA 3.0
Perl Dancer Conference Website

https://github.com/interchange/Perl-Dancer-Conference
Web Application Features
-
Maps with Leaflet
-
Cropping Photos
-
Administration
-
SEO / Modern Design
-
Dancer2::Debugger
Maps with Leaflet
-
Venue on Frontpage
-
Leaflet library
-
Leaflet code
-
User map
Venue on Frontpage

Leaflet Library
Leaflet Code
var map = L.map('map').setView([48.20078,16.36826], 13); L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', { attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>', maxZoom: 18, id: 'petermottram.mp1dpak2', accessToken: 'pk.eyJ1IjoicGV0ZXJtb3R0cmFtIiwiYSI6IjE1NWI5NjRjN2IxNjNkYTM1MzI3YzY5M2E0YjZjMDc0In0.T0bpnZGXCQBSW_SOv_nWHA' }).addTo(map); var marker2 = L.marker([48.18246, 16.38075]).addTo(map); marker2.bindPopup("<b>Hotel Schani Wien</b><br>Karl-Popper-Straße 22<br>Conference Venue<br>21/22 Oct"); $("#marker2").click(function(){ marker2.openPopup(); return false; });
User Map

Cropping photos
You can drag and drop or uplad your photo and crop it in our website.
Current photo

Ballerina

Cropping I

Cropping II

Final Result

Jcrop Library
Jcrop - jQuery Image Cropping Plugin
SEO / Modern Web Design
-
Secure site with HTTPS
-
Speaking links
Secure site with HTTPS
-
More secure and gives users more confidence
-
Small ranking boost with Google
-
Free certificates with Let's Encrypt
Speaking Links I

Speaking Links II
Administration
-
Users
-
Talks
-
Tickets
-
Events
-
News
Navigation

Development
Dancer2::Debugger
Dancer2::Debugger Presentation

DBIx::Class Techniques
-
Set Based DBIx::Class http://www.perladvent.org/2012/2012-12-21.html
-
Truth of ResultSet
-
Chaining
-
Relationship traversal
-
Predefined searches
-
-
Hashref Inflation
Truth of ResultSet
This doesn't execute SQL:
my $talks = $schema->resultset('Talk')->search(...);
This does:
my $first_talk = $schema->resultset('Talk') ->search(...)->first;
Chaining
my $talks = $schema->resultset('Talk') ->search({-bool => 'accepted'}) ->search({conferences_id => 1}) ->search({room => { '!=' => '' }), ->search({start_time => { '>=' => '2015-10-22 00:00:00' '<=' => '2015-10-23 00:00:00' }}), );
Relationship Traversal
# countries dropdown $tokens->{countries} = [ $users->search_related( 'addresses', { type => 'primary', }, )->search_related( 'country', undef, { columns => [ 'country_iso_code', 'name' ], distinct => 1, order_by => 'country.name', } )->hri->all ];
Hashref Inflator
# countries dropdown $tokens->{countries} = [ rset('Country')->search( undef, { columns => [ 'country_iso_code', 'name' ], order_by => 'name' } ) ->hri->all ]; unshift @{ $tokens->{countries} }, { country_iso_code => undef, name => "Select Country" };
Predefined Searches
User class:
sub last_conference_attended { my $self = shift; my $conference = $self->conferences->search({}, { order_by => { -desc => 'start_date' }, })->first; }
Web application:
my $conference = $user->last_conference_attended;
Dancer2
-
Code structure
-
Hooks
-
Plugins
-
Plack::Middleware
Code Structure
-
Main module
-
Multiple modules for routes
Main Module
use Dancer2; use PerlDance::Routes::Account; use PerlDance::Routes::Admin; use PerlDance::Routes::Data; use PerlDance::Routes::PayPal; use PerlDance::Routes::Profile; use PerlDance::Routes::Survey; use PerlDance::Routes::Talk; use PerlDance::Routes::User; use PerlDance::Routes::Wiki;
Route module I
use Dancer2 appname => 'PerlDance'; use Dancer2::Plugin::Auth::Extensible; use Dancer2::Plugin::DataTransposeValidator; use Dancer2::Plugin::DBIC; use Dancer2::Plugin::Email; use Dancer2::Plugin::Deferred; use Dancer2::Plugin::Interchange6; use Dancer2::Plugin::TemplateFlute; prefix '/profile';
Route module II
get '/talk/create' => sub { my $tokens = { title => "New Talk", }; $tokens->{form} = form('create-update-talk'); $tokens->{form}->reset; $tokens->{form}->fill( duration => 40 ); add_durations_token($tokens); template 'profile/create_update_talk', $tokens; };
Hooks used
hook 'before_template_render' => sub { my $tokens = shift; if ( my $user = logged_in_user ) { $tokens->{logged_in_user} = schema->current_user; } $tokens->{conference_name} = setting('conference_name'); };
Plugins used
- Dancer2::Plugin::Auth::Extensible
-
User Authentication
- Dancer2::Plugin::DataTransposeValidator
-
Form validation
- Dancer2::Plugin::DBIC
-
DBIx::Class Wrapper
- Dancer2::Plugin::Deferred
-
Flash messages after redirect
- Dancer2::Plugin::Email
-
Sending emails
- Dancer2::Plugin::Interchange6
-
Cart and other business functions
- Dancer2::Plugin::TemplateFlute
-
Form handling
Plack Middleware

Cross-site request forgery (CSRF/XSRF)
# bin/app.psgi use Plack::Builder; use PerlDance; my $app = PerlDance->to_app; builder { enable 'Session'; enable 'XSRFBlock', cookie_name => 'PerlDance-XSRF-Token', meta_tag => 'xsrf-meta', cookie_options => { httponly => 1, }; enable 'XForwardedFor', trust => [qw( 127.0.0.1 10.0.0.0/8 172.16.0.0/20 192.168.0.0/16 )]; $app; }
Summary
-
Modern Perl
-
Missing features
-
Perl Dancer Conference 2016
-
Call for developers
-
Ask questions
Modern Perl
Missing features
Perl Dancer Conference 2016

Call for developers
https://github.com/interchange/Perl-Dancer-Conference
Questions
Questions?