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

CatalystX::Controller::Sugar - Sugar for Catalyst controller

VERSION

0.0702

DESCRIPTION

This module is written to simplify the way controllers are written. I personally think that shifting off $c and $self in every action is tidious. I also wanted a simpler API to created chained actions, since I rarely use any other actions - except of "private".

SYNOPSIS

  package MyApp::Controller::Root;
  use CatalystX::Controller::Sugar;
 
  __PACKAGE__->config->{'namespace'} = q();
 
  # Private action
  private authenticate => sub {
    c->user_exists and return 1;
  };
 
  # Chain /
  chain sub {
    report debug => 'Someone tries to access %s', c->action;
  };

  # Endpioint /*
  chain '' => sub {
    res->body('not found');
  };

  # Endpoint /login
  chain login => {
    get => sub {}, # show template
    post => sub {
      forward 'authenticate' and go '';
    },
  };
 
  # Chain /user/[id]/*
  chain user => ['id'], sub {
    stash user => c->model('DB::User')->find($_[0]);
  };
 
  # Endpoint /user/[id]/view/*
  chain 'user:1' => view => sub {
    res->body(
      sprintf 'Person is called: %s', stash->{'user'}->name
    );
  };
 

Same with standard Catalyst syntax

  package MyApp::Controller::Root;
  use Moose;
  BEGIN { extends 'Catalyst::Controller' }
 
  __PACKAGE__->config->{'namespace'} = q();
 
  # Private action
  sub authenticate :Private {
    my($self, $c) = @_;
    $c->user_exists and return 1;
  }
 
  # Chain /
  sub root :Chained("/") PathPart("") CaptureArgs(0) {
    my($self, $c) = @_;
    $c->log->debug(sprintf 'Someone tries to access %s', $c->action);
  }

  # Endpioint /*
  sub default :Chained("/root") PathPart("") Args {
    my($self, $c) = @_;
    $c->res->body('not found');
  }

  # Endpoint /login
  sub login :Chained("/root") PathPart Args {
    my($self, $c) = @_;

    if(lc $c->req->method eq 'get') {
      return; # show template
    }
    elsif(lc $c->req->method eq 'post') {
      $c->forward('authenticate') and go('');
    }
  }
 
  # Chain /user/[id]/*
  sub user :Chained("/root") PathPart CaptureArgs(1) {
    my($self, $c, $id) = @_;

    $c->stash->{'id'} = $id; # alternative to captured('id');
    $c->stash->{'user'} = $c->model('DB::User')->find($id);
  }
 
  # Endpoint /user/[id]/view/*
  sub user_view :Chained("/user") PathPart('view') Args {
    my($self, $c) = @_;
    $c->res->body(sprintf 'Person is called: %s', $c->stash->{'user'}->name);
  }
 

NOTE

$self and $c is not part of the argument list inside a chain() or private() action. $c is acquired by calling c(), and $self is available by calling controller().

EXPORTED FUNCTIONS

chain

 1. chain sub { };

 2. chain $PathPart => sub { };
 3. chain $PathPart => $Int, sub { };
 4. chain $PathPart => \@CaptureArgs, sub { };

 5. chain $Chained => $PathPart => sub { };
 6. chain $Chained => $PathPart => $Int, sub { };
 7. chain $Chained => $PathPart => \@CaptureArgs, sub { };

 8. chain ..., \%method_map;

Same as:

 1. sub root : Chained('/') PathPart('') CaptureArgs(0) { }

 2. sub $PathPart : Chained('/root') Args { }
 3. sub $PathPart : Chained('/root') Args($Int) { }
 4. sub $PathPart : Chained('/root') CaptureArgs($Int) { }

 5. sub $PathPart : Chained($Chained) Args { }
 6. sub $PathPart : Chained($Chained) Args($Int) { }
 7. sub $PathPart : Chained($Chained) CaptureArgs($Int) { }

 8. Special case: See below

@CaptureArgs is a list of names of the captured arguments, which can be retrieved using captured().

$Int is a number of Args to capture at the endpoint of a chain. These cannot be aquired using captured(), but is instead available in @_.

%method_map can be used if you want to dispatch to a specific method, for a certain HTTP method: (The HTTP method is in lowercase)

 %method_map = (
    post => sub { ... },
    get => sub { ... },
    delete => sub { ... },
    default => sub { ... },
    #...
 );

private

 private $name => sub {};

Same as:

 sub $name :Private {}

forward

 @Any = forward $action;
 @Any = forward $action, \@arguments;

See Catalyst::forward().

go

 go $action;
 go $action, \@arguments;

See Catalyst::go().

c

 $context_obj = c;

Returns the context object for this request, an instance of Catalyst.

controller

 $controller_obj = controller;

Returns the current controller object.

req

 $request_obj = req;

Returns the request object for this request, an instance of Catalyst::Request.

res

 $response_obj = res;

Returns the response object for this request, an instance of Catalyst::Response.

captured

 $value = captured($name);

Retrieve data captured in a chain, using the names set with chain().

 chain '/' => 'user' => ['id'], sub {
   res->body( captured('id') );
 };

stash

 $value = stash $key;
 $hash_ref = stash $key => $value, ...;
 $hash_ref = stash;

Set/get data from the stash. The $hash_ref is a reference to what the stash is holding.

This will be the same as:

 $c->stash->{$key} = $value;

session

 $value = session $key;
 $hash_ref == session $key => $value;
 $hash_ref == session;

Set/get data from the session. The $hash_ref is a reference to what the session is holding.

This function will only work if a session module/plugin is loaded into Catalyst.

report

 report $level, $format, @args;

Almost the same as:

 $c->log->$level(sprintf $format, @args);

But undef values from @args are turned into "__UNDEF__", and objects and/or datastructructures are flatten, using Data::Dumper.

METHODS

init_meta

See Moose::Exporter.

BUGS

Please report any bugs or feature requests to bug-catalystx-controller-sugar at rt.cpan.org. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

COPYRIGHT & LICENSE

Copyright 2007 Jan Henning Thorsen, all rights reserved.

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

AUTHOR

Jan Henning Thorsen, <jhthorsen at cpan.org>