Aura Input Form Inside Slim Framework

Rob Allen wrote about Integrating ZF2 forms into Slim. I did write how you can use Aura.Input and Aura.Html to create standalone form for PHP. This time I felt I should write about integrating aura input inside Slim.

Let us install a few dependencies aura/input for building the form and aura/html for the html helpers. You of-course can skip not to use aura/html and build your own helper. I also purposefully left not integrating the powerful Aura.Filter , but you are not limited to integrate any validator you love inside Aura.Input .

The full composer.json is as below.

1
2
3
4
5
6
7
8
9
10
11
12
{
    "require": {
        "slim/slim": "2.*",
        "aura/html": "2.0.0",
        "aura/input": "1.*"
    },
    "autoload":{
        "psr-0":{
            "": "src/"
        }
    }
}

We will keep ContactForm.php under src folder. ie why you see the autoload in composer.json. The form looks as below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
// src/ContactForm.php

use Aura\Input\Form;

class ContactForm extends Form
{
    public function init()
    {
        $this->setField('name')
            ->setAttribs([
                'id' => 'contact[name]',
                'name' => 'contact[name]',
                'size' => 20,
                'maxlength' => 20,
            ]);
        $this->setField('email')
            ->setAttribs([
                'id' => 'contact[email]',
                'name' => 'contact[email]',
                'size' => 20,
                'maxlength' => 20,
            ]);
        $this->setField('url')
            ->setAttribs([
                'id' => 'contact[url]',
                'name' => 'contact[url]',
                'size' => 20,
                'maxlength' => 20,
            ]);
        $this->setField('message', 'textarea')
            ->setAttribs([
                'id' => 'contact[message]',
                'name' => 'contact[message]',
                'cols' => 40,
                'rows' => 5,
            ]);
        $this->setField('submit', 'submit')
            ->setAttribs(['value' => 'send']);

        $filter = $this->getFilter();

        $filter->setRule(
            'name',
            'Name must be alphabetic only.',
            function ($value) {
                return ctype_alpha($value);
            }
        );

        $filter->setRule(
            'email',
            'Enter a valid email address',
            function ($value) {
                return filter_var($value, FILTER_VALIDATE_EMAIL);
            }
        );

        $filter->setRule(
            'url',
            'Enter a valid url',
            function ($value) {
                return filter_var($value, FILTER_VALIDATE_URL);
            }
        );

        $filter->setRule(
            'message',
            'Message should be more than 7 characters',
            function ($value) {
                if (strlen($value) > 7) {
                    return true;
                }
                return false;
            }
        );
    }
}

The entry point web/index.php looks as below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
// web/index.php

use Aura\Input\Builder;
use Aura\Input\Filter;

require dirname(__DIR__) . '/vendor/autoload.php';
$app = new \Slim\Slim(array(
    'templates' => dirname(__DIR__) . '/templates'
));
$app->map('/contact', function () use ($app) {
    $form = new ContactForm(new Builder(), new Filter());
    if ($app->request->isPost()) {
        $form->fill($app->request->post('contact'));
        if ($form->filter()) {
            echo "Yes successfully validated and filtered";
            var_dump($data);
            $app->halt();
        }
    }
    $app->render('contact.php', array('form' => $form));
})->via('GET', 'POST')
->name('contact');

$app->run();

The template contact.php resides under templates folder.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
// templates/contact.php

use Aura\Html\HelperLocatorFactory;

$factory = new HelperLocatorFactory();
$helper = $factory->newInstance();

function showFieldErrors($form, $name) {
    $errors = $form->getMessages($name);
    $str = '';
    if ($errors) {
        $str .= '<ul>';
        foreach ($errors as $error) {
            $str .= '<li>' . $error . '</li>';
        }
        $str .= '</ul>';
    }
    return $str;
}
?>
<html>
<head>
    <title>Aura input form, inside slim framework</title>
</head>
<body>
    <form method="post" action="<?php echo $app->urlFor('contact'); ?>" enctype="multipart/form-data" >
        <table cellpadding="0" cellspacing="0">
            <tr>
                <td>Name : </td>
                <td>
                <?php
                    echo $helper->input($form->get('name'));
                    echo showFieldErrors($form, 'name');
                ?>
                </td>
            </tr>
            <tr>
                <td>Email : </td>
                <td>
                <?php
                    echo $helper->input($form->get('email'));
                    echo showFieldErrors($form, 'email');
                ?>
                </td>
            </tr>
            <tr>
                <td>Url : </td>
                <td>
                <?php
                    echo $helper->input($form->get('url'));
                    echo showFieldErrors($form, 'url');
                ?>
                </td>
            </tr>
            <tr>
                <td>Message : </td>
                <td>
                <?php
                    echo $helper->input($form->get('message'));
                    echo showFieldErrors($form, 'message');
                ?>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                <?php
                echo $helper->input($form->get('submit'));
                ?>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

NB: If you need to reuse the functionality of showFieldErrors keep it on a separate file and require it.

Thank you Andrew Smith, Christian Schorn for the proof reading and tips provided.

I hope you will find something interesting in the integration!.

Download and play with code from github

Aura Framework V2: The Missing Manual

Aura has an awesome collection of libraries for different purpose.

It has components for authentication, cli, request and response, router, dependency injection container, dispatcher, html, view, event handlers, validation, extended pdo, query builders, sql schema, marshal, build and modify uri, http, internationalization, session, forms, includer.

If you are new to aura, there is probably something you may want to figure out yourself.

Some of the components have version 1 and version 2 releases. There is a question of which branch corresponds to which version.

The v1 packages are in develop branch and v2 over develop-2 branch.

There are a few changes in v1 to v2. It is easy to understand when you look into the composer.json or if you know aura v2 follows psr-4 directory structure than the v1 that followed psr-0.

If you see a package "aura/installer-default": "1.0.0" in the require of composer.json it is for sure v1.

Composer installs every package in the vendor folder. The name of the package installed will be the package name. So basically it installs vendor/aura/<package-name> .

In aura framework v1 we have some specific folder structure and it was before composer becomes a standard. So when composer became a standard we added a way to install the framework specific installations in package folder and the rest of the library installation (other than aura framework) in the same way as composer did.

So was the existence of aura/installer-default in v1 package. In v2 we moved to composer assisted two stage configuration.

v2 Framework

There exists a micro framework/full stack framework for v2. But things are hard to find when you are new to aura and when github organization have more than 30 repositories.

Aura framework is built on top of aura libraries, and the library docs applies to the framework also. But people new to aura may be having hard time to find the specific documentation or may be stuck sometime. I don’t know whether my thoughts are right or wrong.

Documentation is one of the hardest problem when newer versions are released. Say 1.0.0 released, 1.1.0 … although the documentation is there in the installed repo, it is probably hard to make things online.

I was talking with Paul M Jones regarding the documentation lately, and he too shared some concerns. Talking with him gave me some inspiration to start the missing manual for the aura framework.

Goal

  • let people read and learn
  • promote aura with good documentation
  • at the sametime, to make a living

Yes, I am independent freelance php developer. It was a sad story that I don’t want to recall how I became a freelancer by chance.

Before my freelancing, I was down for a few months, not physically but mentally which has impacted my life with some ups and downs. But now I really love working as an independent contractor.

About the book

You can find the book over github licensed under Creative Commons Attribution-ShareAlike 3.0 Unported License

The book is available free to read online. If you find a typo, or feel something can be improved open an issue or send a pull request .

If you find it interesting you should consider buying a copy from leanpub to show your support to the project.

Thank you.

Hidden Gems of Composer

I hope everyone in the PHP world is aware of composer the dependency management tool that gives an end to Pear.

We can look into some of the hidden gems of composer. Some of them are already documented in the composer docs.

Bug Fixing :

Documented over Loading a package from a VCS repository

1
2
3
4
5
6
7
8
9
10
11
{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/igorw/monolog"
        }
    ],
    "require": {
        "monolog/monolog": "dev-bugfix"
    }
}

The above example assume you have pushed your code to github. But you can also make use of the local directory.

Assume you are organizing your code something like

1
2
3
4
5
6
home
└── github.com
    └── harikt
        ├── Aura.Router
        ├── Aura.Web
        └── monolog

Now on your project you could make use of the patches you are working on the local directory without pushing it to github.

Note : You should commit the changes though.

1
2
3
4
5
6
7
8
9
10
11
12
{
    "minimum-stability":"dev",
    "repositories": [
        {
            "type": "vcs",
            "url": "/home/github.com/harikt/monolog"
        }
    ],
    "require": {
        "monolog/monolog": "dev-bugfix"
    }
}

And you can also disable packagist for fast look up.

Experimenting your own packages

I did add packages in packagist for testing. This is really a wrong way to do, you are adding more packages that makes other people’s life hard to find a useful package.

What I learned is, you can do in a different way. See docs under Package

So your composer.json will look something like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    "minimum-stability":"dev",
    "repositories": [
        {
            "type": "package",
            "package": {
                "name": "harikt/experiments",
                "version": "3.1.7",
                "source": {
                    "type": "git",
                    "url": "/home/github.com/harikt/experiments",
                    "reference": "master"
                },
                "autoload": {
                    "classmap": ["libs/"]
                }
            }
        }
    ],
    "require": {
        "harikt/experiments": "3.1.*"
    }
}

That’s for now.

Happy PhPing!

Extending Plates With Aura Html Helpers

Aura.Html provides HTML escapers and helpers, including form input helpers, that can be used in any template, view, or presentation system.

In this post I would like to give you a short introduction to Aura.Html and how you could use with Plates a native php templating system like Aura.View.

Aura.Html was extracted from Aura.View helper functions of version 1, when we at aura noticed that people who uses Aura.Input may need some html helper functions and they may not be using a templating like Aura.View, but some other templating system.

You can see an example of a simple contact form with Aura.Input.

Installation

The easiest way to install Aura.Html is via composer. Let us create our composer.json

1
2
3
4
5
6
{
    "require": {
        "aura/html": "2.*@dev",
        "league/plates": "2.*"
    }
}

One of the good thing about Plates is you can create extensions.

Let us create an extension that can make use of Aura.Html helpers inside Plates. Any Plates extension should implement League\Plates\Extension\ExtensionInterface which contains a getFunctions method which returns the functions available within your templates.

We are going to name it as AuraHtmlExtension and call functions as aurahtml() or html() via the template.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
use League\Plates\Extension\ExtensionInterface;
use Aura\Html\HelperLocator;

class AuraHtmlExtension implements ExtensionInterface
{
    public $engine;

    public $template;

    protected $helper;

    public function __construct(HelperLocator $helper)
    {
        $this->helper = $helper;
    }

    public function getFunctions()
    {
        return array(
            'aurahtml' => 'callHelper',
            'html' => 'callHelper'
        );
    }

    public function callHelper()
    {
        return $this->helper;
    }
}

But you are not limited to name it as the same html tag helpers and form helpers.

So that will make the helpers look native Plates helpers. Thank you for this functionality to plugin the helpers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
use League\Plates\Extension\ExtensionInterface;
use Aura\Html\HelperLocator;

class AuraHtmlExtension implements ExtensionInterface
{
    public $engine;

    public $template;

    protected $helper;

    public function __construct(HelperLocator $helper)
    {
        $this->helper = $helper;
    }

    public function getFunctions()
    {
        return array(
            'anchor' => 'anchor'
            // ... more functions same as aura
        );
    }

    public function anchor($href, $text, array $attr = array())
    {
        return $this->helper->anchor($href, $text, array $attr);
    }
}

Let us use the basic example in plates and use aura html helper to show the system works as expected.

Create the templates in a templates folder or change the path in Plates Engine.

Profile Template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- profile.php -->

<?php $this->layout('template') ?>

<?php $this->title = 'User Profile' ?>

<h1>User Profile</h1>
<p>Hello, <?=$this->e($this->name)?></p>
<div>
<?php
echo $this->aurahtml()->input(array(
    'type'    => 'color',
    'name'    => 'name',
    'value'   => 'value',
    'attribs' => array(),
    'options' => array(),
));

// <input type="color" name="name" value="value" />
echo $this->html()->input(array(
    'type'    => 'date',
    'name'    => 'name',
    'value'   => 'value',
    'attribs' => array(),
    'options' => array(),
));

// <input type="date" name="name" value="value" />
?>
</div>

Layout Template

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- template.php -->

<html>
<head>
    <title><?=$this->title?></title>
</head>

<body>

<?=$this->content()?>

</body>
</html>

Autoload Extension

Make sure AuraHtmlExtension can be autoloaded. We can add in composer.json

1
2
3
4
5
6
// rest of the code
"autoload": {
    "psr-4": {
        "": "path/to/aura/html/extension/"
    }
}

Bootstrapping and Rendering

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// test.php file
require __DIR__ . '/vendor/autoload.php';
$engine = new \League\Plates\Engine( __DIR__ . '/templates');

// Create a new template
$template = new \League\Plates\Template($engine);
$factory = new \Aura\Html\HelperLocatorFactory();
$helper = $factory->newInstance();
$engine->loadExtension(new AuraHtmlExtension($helper));

// Assign a variable to the template
$template->name = 'Jonathan';

// Render the template
echo $template->render('profile');

If you run php test.php you will see something like this rendered.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
<head>
    <title>User Profile</title>
</head>

<body>


<h1>User Profile</h1>
<p>
Hello, Jonathan
</p>
<div>
<input type="color" name="name" value="value" />
<input type="date" name="name" value="value" />
</div>

</body>
</html>
</body></title>

Thank you and Happy PhPing!

Web Routing in PHP With Aura.Router

It took sometime for me to create a series of screencast on aura. So my plan to start a series of screencasts starts with Aura.Router version 2.

Yes, I have made some mistakes, but I do love to hear your feedback and interest for the future screencast.

The next one will be on Dispatcher If you want to cover something special in the Dispatcher I will try to address it.

AngularJS by Brad Green, Shyam Seshadri; O’Reilly Media

First I would like to apologize O’Reilly for the dealy it happened. So the buzz is AngularJS.

I took the book AngularJS by Brad Green, Shyam Seshadri; O’Reilly Media for review. Both authors Brad Green and Shyam Seshadri has experience working at google and angularjs.

I have noticed people rating 5/5 mentioning the book covers to the point etc. I am really new to angularjs and my reviews are based on it.

I don’t think I can recommend the book for a person who is really new to angularjs. Though it starts simple, at some point of time it jumps to advanced parts or hard to follow. Don’t think it is the problem with book itself but the concepts are new and need a better way to explain. Eg directives.

I strongly feel the introduction of yeoman, karma etc has added more frustration. But I do like the introduction of debugging tools like Batarang.

These could have been taken to the last chapters if really needed. There are many places where it could have been explained with better examples than just small snippets of code where people don’t know where to keep and figure out themselves. Though there is a github repo with code, chapter-5 doesn’t have one.

I can give a rating of 3/5.

Rentautobus Back to India

Rentautobus.com is a worldwide private transport quote comparison and reservations portal which was my first live project that made my hands dirty with Zend Framework. I was hired as a maintainer for the multilingual website.

Multilingual websites when viewed from outside is not that complex. Before you dive into write your first line of code, everyone should read The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)

Many of the developers don’t care about the characterset and finally they see weird characters displayed and your client re-opening the same tickets. I don’t blame any developers for until when you deal with something like this you will end up in trouble.

Tests!

How many of you really test your app?

Most of them, or the QA does it for you. Awesome!

But I am not talking about manual testing. Hope you have heard about automated testing tools like phpunit. How many of you write unit tests? How does that help you?

Say you have the equation (a+b)2 = a2 + 2ab + b2

What you do is write a simple class with the method which returns the result.

Everyone knows the expected result. But in most cases it may not be the same. May be there is a new feature coming, if a is less than b use

(a-b)2 = a2 – 2ab + b2

Now the complexity is increasing. And at somepoint of time you could not test each one manually and unexpected results coming.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class Algebra
{
    public function calculate($a, $b)
    {
        if ($a < $b) {
            $result = $a*$a + $b*$b - 2* $a*$b;
        } else {
            $result = $a*$a + $b*$b + 2* $a*$b;
        }
        return $result;
    }
}

In-order to get rid of the already tested one, writing unit tests is the nice way. So the test will be something like

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
class AlgebraTest extends PHPUnit_Framework_TestCase
{
    protected $algebra;

    public function setup()
    {
        $this->algebra = new Algebra();
    }

    /**
     * @dataProvider provider
     */
    public function testCalculate($a, $b, $result)
    {
        $this->assertEquals($result, $this->algebra->calculate($a, $b));
    }

    public function provider()
    {
        return array(
            array(3, 2, 25),
            array(2, 3, 25),
        );
    }
}

Here if you noticed what will happen when a and b are same?

What I am trying to point out is write tests, so the person who comes as a maintainer also can run the tests and see everything is working as expected.

Probably your client may blame you for taking more time, try to convience them that it has saved X Hours to fix the bug!.

Be brave and start writing tests, for the next maintainer don’t have to find whether it was a feature request or this is a bug.

No one can learn everything in a single day, start small to achieve big.

What rentautobus.com does?

The idea of rentautobus.com is to help both groups of people and individuals who are travelling to a different place/country to easily get quotes from private transport operators or travel agents. They can compare offers and quality, go through the reviews and feedback comments of people who have already travelled with these transport providers, how comfortable are they with the vehicle, the driver etc. The feedback system is not a new one, it’s called 5 star rating which is mostly used by travel and hotel websites.

In the promotional video below you can see the concept explained. This comparison concept is quite comon in Europe.

You can choose from a wide variety of travel agents, easily compare the price what they offer, the feedback they got from others. The 1st concept of the website was built for European countries like Spain. And
as of today the site has expanded to other countries like India.

Rentautobus recently added Car with Driver services in Cochin to the list of countries, places and services offered.

Will the concept in India work like Spain?

I’m curious to see if this European concept will have the same acceptance in India as in Spain.

Cultural differences do exist and this of-course translates into the use of internet as a research and booking tool for transport, tours or other travels. Travel arrangements in India by people over here are often done via a trusted travel agents who normally is a friend or introduced by a friend or family member.

For foreign tourists traveling to India for the 1st time, with no local contacts its of-course a good thing to have a friendly internet reservation tool for their transport arrangements.

We are not sure yet how the system should be adapted to fit the local Indian cultural requierments.

Let us know your thought and opinions!