nebiros / yasc
Yet Another Sinatra Clone
Requires
- php: >=5.2.4
This package is not auto-updated.
Last update: 2024-12-21 17:27:44 UTC
README
Yet Another Sinatra Clone
yasc
is a sinatra (kind of) clone written in php
and highly influenced by zend framework 1.x, the routing system is based on
limonade's code, is a tiny framework that uses user defined functions as actions
(like in the MVC pattern) and annotations to route the requested url to a function.
Features
- Functions based.
- RESTful.
- Tiny ^_^.
- Routing system based on regex patterns, named params, pairs param (like zend framework 1.x).
- View helpers.
- Function helpers.
- Layouts support.
- Class autoloading based on the Framework Interop Group.
- Models support.
Default project structure
yasc
uses this project structure:
app.php
views/
helpers/
models/
If you create these folders in your project they are auto-loaded in your application. Default namespaces:
helpers/Helper_*
models/Model_*
Accessors
I saw that invoking the requested function with a lot of arguments is too ugly and a little bit verbose (just a little?), so I add some accessors to be used in each function.
<?php Yasc_App::view() // Access the view object inside your function. Yasc_App::params() // Get all route params. Yasc_App::params("key") // Get param "key" value, also, you can specify a default value as the second argument of this static method. Yasc_App::config() // App config. Yasc_App::viewHelper("url") // Get a view helper, like Layout, Url, or some of your own. Yasc_App::functionHelper("flash") // Get a function helper, like Flash, this helper is a stack of messages, errors, notices, etc.
Prerequisites
yasc
requires PHP 5.2.4 or later.
Installation
Easiest way to install yasc
is through composer,
php composer.phar require nebiros/yasc "~0.1.18"
or add it as a git submodule
.
Create a index.php or a app.php file and include yasc
, like:
namespace My\App; // composer autoload. require_once "vendor/autoload.php"; // yasc runtime. require_once "vendor/nebiros/yasc/src/Yasc.php"; $yasc = new \Yasc(); $yasc->run(__NAMESPACE__); unset($yasc);
Add a function and a pattern using an annotation for your application index, your script will be something like this:
<?php namespace My\App; // composer autoload. require_once "vendor/autoload.php"; // yasc runtime. require_once "vendor/nebiros/yasc/src/Yasc.php"; $yasc = new \Yasc(); $yasc->run(__NAMESPACE__); unset($yasc); /** * @GET("/") */ function index() { echo "Hello world!"; }
Now, go to your favorite browser and run your script:
http://localhost/app.php
Follow the examples and you'r done :).
Setup
Maybe you want to hide your script file from the URL, http://app.com/app.php/some/thing (I know, pretty URLs, SEO shut, blah, blah) and get something fancier like: http://app.com/some/thing, ok, well, create a VirtualHost and add a .htaccess file to your application folder like this:
Virtual host configuration
<VirtualHost *:80>
DocumentRoot "/path/to/your/application/public"
ServerName app.com
<Directory "/path/to/your/application/public">
Options -Indexes MultiViews FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
.htaccess file
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
NOTE: Your app file must be named index.php in order to work with this .htaccess
file.
Simple Example
<?php namespace My\App; // composer autoload. require_once "vendor/autoload.php"; // yasc runtime. require_once "vendor/nebiros/yasc/src/Yasc.php"; $yasc = new \Yasc(); $yasc->run(__NAMESPACE__); unset($yasc); /** * @GET("/") */ function index() { echo "Hello world!"; } /** * @POST("/") */ function create() { // save something. } /** * @PUT("/") */ function update() { // update something. } /** * @DELETE("/") */ function destroy() { // delete something. }
Configuration
<?php /** * Function to configure some yasc options. This function is optional you don't * need to write it in your app script if you don't want. */ function configure() { // * You can add a layout, a layout is just a .phtml file that represents // the site template. Yasc_App::config()->setLayoutScript(dirname(__FILE__) . "/layouts/default.phtml"); // * If you want to use a stream wrapper to convert markup of mostly-PHP // templates into PHP prior to include(), seems like is a little bit slow, // so by default is off. // ->setViewStream(true); // // * You can add more than one folder to store views, each view script // is a .phtml file. // ->addViewsPath(dirname(__FILE__) . "/extra_views"); // // * You can add more than one path of view helpers and set a // class prefix for the path added. // ->addViewHelpersPath(dirname(__FILE__) . "/../library/My/View/Helper", "My_View_Helper"); // // or if you don't want a class prefix just leave it blank. // ->addViewHelpersPath(dirname(__FILE__) . "/extra_views/helpers"); // // * Function helpers, second argument is a prefix class. // ->addFunctionHelpersPath(dirname(__FILE__) . "/extra_function_helpers"); // // * Add models folder, second argument is a prefix class. // ->addModelsPath(dirname(__FILE__) . "/models"); // ->addModelsPath(dirname(__FILE__) . "/extra_models/My/Model", "My_Model"); // // * Add extra options to the configuration object, like some $mysql connection // resource or a global flag, etc. // ->addOption("db", $mysql); }
Pre- and Post-Dispatch Hooks
We provide two functions, pre_dispatch
and post_dispatch
, that may be called before and after an action is
invoked.
Advanced Examples
<?php /** * @GET("/") */ function index() { // Use layout view helper to disable the layout or use Yasc_Layout object // Yasc_Layout::getInstance()->disable(), Yasc_Layout uses singleton pattern. Yasc_App::view()->layout()->disable(); // Get the mysql resource from this app configuration option. // // $mysql = Yasc_App::config()->getOption("db"); // // ... do some sql operation. echo "Hello world!"; } /** * @POST("/") * * You can route the same url to another function using a different request * method. */ function save_index() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "post: "; var_dump($_POST); echo "</pre>"; } /** * @GET("/tales") */ function tales() { // You can add variables to the view object and get his value on // the view script using the variable $this, like: $this->tales. Yasc_App::view()->tales = "oh! I'm a view variable!"; // Render a view script, a view script is a .phtml file where you can mix // php and html, the V in the MVC model, in this example the view files // are stored in views/ folder. // // This view calls a view helper 'Tales', so check views/helpers/Tales.php // to see what it does. Yasc_App::view()->render("tales"); } /** * @GET("/tales/:lol") * @POST("/woot") // Ignored, yasc only uses the first annotation found. * * Named params, you can access those via Yasc_App::params() method. * * Matches: /tales/foo and /tales/bar */ function tales1() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "lol value: " . Yasc_App::params("lol"); echo "</pre>"; Yasc_App::view()->tales = "oh! I'm a view variable!"; // instance of a model. $foo = new Model_Foo(); Yasc_App::view()->helloModel = $foo->doSomething(); // Render a view without the layout. Yasc_App::view()->render("tales"); } /** * @GET("/tales/:lol/id/:id") */ function tales2() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "lol value: " . Yasc_App::params("lol"); echo "id value: " . Yasc_App::params("id"); echo "</pre>"; } /** * @POST("/tales3") */ function tales3() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "post: "; var_dump($_POST); echo "</pre>"; } /** * @GET("/foo") */ function foo() { // Render view script foo, this view script calls the view helper class 'Foo', // this view helper render a view helper script inside and return his content // to this view, a view helper script is just another .phtml file, if you don't // want to create a whole html string inside the helper ;). Yasc_App::view()->render("foo"); } /** * @GET("^/regex/id/(\d+)/name/([a-z]+)") * * You can create patterns using a regular expression, this kind of route must * begin with a '^'. Check limonade docs and code if you want more information, or * just use limonade framework :), it's a more robust framework. * * http://www.limonade-php.net/README.htm * https://github.com/sofadesign/limonade/blob/master/lib/limonade.php * * Matches: /regex/id/26/name/juan */ function regex() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "params: "; var_dump(Yasc_App::params()); echo "</pre>"; } /** * @GET("/say/*\/to\/*") * * Patterns may also include wildcard parameters. Each value is associted * through numeric indexes, in the same order as in the pattern. * * Matches: /say/hello/to/world */ function single_asterisk() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "params: "; var_dump(Yasc_App::params()); echo "hello: "; var_dump(Yasc_App::params(0)); // hello echo "world: "; var_dump(Yasc_App::params(1)); // world echo "</pre>"; } /** * @GET("/download/*.*") * * Matches: /download/file.xml */ function download() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "params: "; var_dump(Yasc_App::params()); echo "filename: "; var_dump(Yasc_App::params(0)); // file echo "ext: "; var_dump(Yasc_App::params(1)); // xml echo "</pre>"; } /** * @GET("/writing/*\/to\/**") * * The double wildcard '**' matches a string like this one: my/friend/juan/badass, * this string is treated as pairs, this way: param1/value1/param2/value2 etc, like * Zend Framework does, so, via Yasc_App::params() method you can get those * values using each key. * * Matches: /writing/hello/to/my/friends/from/limonade/you_guys/roxor */ function pairs() { Yasc_App::view()->layout()->disable(); echo "<pre>"; echo "params: "; var_dump(Yasc_App::params()); echo "single wildcard: "; var_dump(Yasc_App::params(0)); // hello echo "param my: "; var_dump(Yasc_App::params("my")); // friend echo "param from: "; var_dump(Yasc_App::params("from")); // limonade echo "param you_guys: "; var_dump(Yasc_App::params("you_guys")); // roxor echo "</pre>"; } /** * @GET("/update") */ function update() { /* @var $flash Yasc_Function_Helper_Flash */ $flash = Yasc_App::functionHelper("flash"); Yasc_App::view()->flash = $flash; return Yasc_App::view()->render("update"); // Use '_method' parameter in POST requests when PUT or DELETE methods // are not supported. /* <form id="put" name="put" action="<?php echo $this->url(array("uri" => "/update")) ?>" method="post"> <p>First name: <input type="text" name="first_name" /></p> <p>Last name: <input type="text" name="last_name" /></p> <p><input type="submit" value="Update" /></p> <input type="hidden" name="_method" value="PUT" id="_method" /> </form> */ } /** * @PUT("/update") */ function save_update() { Yasc_App::view()->layout()->disable(); // $mysql = Yasc_App::config()->getOption("db"); // $mysql->update("table1", array("first_name" => $_POST["first_name"], "last_name" => $_POST["last_name"])); /* @var $flash Yasc_Function_Helper_Flash */ $flash = Yasc_App::functionHelper("flash"); $flash->message("Done."); header("Location: " . Yasc_App::viewHelper("url")->url(array("uri" => "/update"))); } /** * @DELETE("/delete") */ function destroy() { Yasc_App::view()->layout()->disable(); // $mysql = Yasc_App::config()->getOption("db"); // $mysql->delete("table1", "id = {$_POST["id"]}"); header("Location: " . Yasc_App::viewHelper("url")->url(array("uri" => "/update"))); }
TODO
Support for PUT and DELETE methods.Support regex in annotations.Add PUT and DELETE annotations.Add layouts support.Add view helpers support.- Caching.
- Tests.
Improve documentation.