Improving Environment Value in Aura V2

Aura v2 framework probably have missed a better way to handle environment variables. But that doesn’t make you stall. Things can be improved ;–).

Assume you are already using aura framework and is at root of the project.

We are going to make use of vlucas/phpdotenv , alternatives are there if you are interested to experiment.

1
composer require vlucas/phpdotenv

Edit the file config/_env.php and add Dotenv::load(/path/to/.env); to the first line. If you have not modified anything it will look as below

1
2
3
4
5
6
7
8
<?php
// {PROJECT_PATH}/config/_env.php
Dotenv::load(__DIR__);
// set the mode here only if it is not already set.
// this allows for setting via web server, shell script, etc.
if (! isset($_ENV['AURA_CONFIG_MODE'])) {
    $_ENV['AURA_CONFIG_MODE'] = 'dev';
}

Don’t forget to create the .env file.

You are done!

Now you can easily make use of environment variables easily from the configuration files.

Below is an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
namespace Aura\Framework_Project\_Config;
// config/Common.php

use Aura\Di\Config;
use Aura\Di\Container;

class Common extends Config
{
    public function define(Container $di)
    {
        $di->params['Aura\Sql\ExtendedPdo'] = array(
            'dsn' => getenv('dsn'),
            'username' => getenv('username'),
            'password' => getenv('password'),
        );
    }

    // more code

Speedup Dependency Injection Configuration for Aura V2

Aura v2 added auto resolution in-order to help lazy people writing configuration manually. Even though it was introduced to help, it introduced a few issues.

So auto resolution will be disabled in the future. Some of the complains/suggestions are how to easily write the di configuration.

So introducing you FOA.DiConfig

Installation

1
composer require foa/di-config

Usage

1
2
3
vendor/bin/di-config-dump
Usage : vendor/bin/di-config-dump /real/path/to/file.php
Usage : vendor/bin/di-config-dump /real/path/to/directory

Example 1

Let’s assume you have

1
2
3
4
5
6
7
8
9
10
<?php
// src/Vendor/World.php
namespace Vendor;

class World
{
    public function __construct(Baz $baz)
    {
    }
}
1
2
3
4
5
6
7
<?php
// src/Vendor/Baz.php
namespace Vendor;

class Baz
{
}

Now you can make use of

1
vendor/bin/di-config-dump src/Vendor/World.php

will output

1
$di->params['Vendor\World']['baz'] = $di->lazyNew('Vendor\Baz');

You can also pass directory path instead of file. It will read the files and display the configuration.

Example 2

Let us look into another example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// src/Vendor/Hello.php
namespace Vendor;

class Hello
{
    public function __construct(
        \Aura\Web\Response $response,
        \Aura\Web\Request $request,
        \Aura\Router\Router $router,
        World $word
    ) {
    }
}
1
vendor/bin/di-config-dump src/Vendor/Hello.php

will output

1
2
3
4
$di->params['Vendor\Hello']['response'] = $di->lazyGet('aura/web-kernel:response');
$di->params['Vendor\Hello']['request'] = $di->lazyGet('aura/web-kernel:request');
$di->params['Vendor\Hello']['router'] = $di->lazyGet('aura/web-kernel:router');
$di->params['Vendor\Hello']['word'] = $di->lazyNew('Vendor\World');

If you look carefully the Aura\Web\Response, Aura\Web\Request and Aura\Router\Router are making use of lazyGet which gets the shared instance of the Aura.Web_Kernel .

If you are not using inside the framework just pass something as 2nd argument.

1
2
3
4
5
vendor/bin/di-config-dump src/Vendor/Hello.php h
$di->params['Vendor\Hello']['response'] = $di->lazyNew('Aura\Web\Response');
$di->params['Vendor\Hello']['request'] = $di->lazyNew('Aura\Web\Request');
$di->params['Vendor\Hello']['router'] = $di->lazyNew('Aura\Router\Router');
$di->params['Vendor\Hello']['word'] = $di->lazyNew('Vendor\World');

Please make sure all the files need to be autoloadable in-order to generate this.

If you like to improve something fork and contribute.

I have purposefully left not to make use of Aura.Cli in this library. Not sure if we need to integrate or not.

Getting Started With Aura V2

Yesterday aura framework v2 stable released.

Lots of complains about documentation or missing documentation. So this is a quick start. Probably a five minutes walk through. Learn and change to make it better.

Creating your project

Create the project using composer.

1
2
composer create-project aura/web-project quick-start
cd quick-start

The minimal framework don’t come with any sort of view integrated. Let us use aura/view, the two step templating with the help of foa/html-view-bundle.

1
composer require "foa/html-view-bundle:~2.0"

We will be keeping all the templates in templates folder where views in templates/views and layout in templates/layouts.

1
mkdir -p templates/{views,layouts}

Edit config/Common.php and define service for view.

1
2
3
4
public function define(Container $di)
{
    $di->set('view', $di->lazyNew('Aura\View\View'));
}

add a way to set the path to templates. Assuming you have templates folder in the root. There is no finder in aura/view to increase the performance of loading and rendering templates. For a quick hack let us iterate through the directory and set all the views and layouts to its registry.

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
public function modify(Container $di)
{
    // more code
    $this->defineTemplates($di);
}

public function defineTemplates($di)
{
    $view = $di->get('view');
    $view_registry = $view->getViewRegistry();
    $view_directory = dirname(__DIR__) . '/templates/views/';
    $iterator = new \DirectoryIterator($view_directory);
    foreach ($iterator as $fileinfo) {
        if ($fileinfo->isFile()) {
            $view_registry->set($fileinfo->getBasename('.php'), $fileinfo->getPathname());
        }
    }

    $layout_registry = $view->getLayoutRegistry();
    $layout_directory = dirname(__DIR__) . '/templates/layouts/';
    $iterator = new \DirectoryIterator($layout_directory);
    foreach ($iterator as $fileinfo) {
        if ($fileinfo->isFile()) {
            $layout_registry->set($fileinfo->getBasename('.php'), $fileinfo->getPathname());
        }
    }
}

Edit modifyDispatcher method to

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public function modifyWebDispatcher($di)
{
    $dispatcher = $di->get('aura/web-kernel:dispatcher');

    $view = $di->get('view');
    $response = $di->get('aura/web-kernel:response');
    $request = $di->get('aura/web-kernel:request');
    $dispatcher->setObject('hello', function () use ($view, $response, $request) {
        $name = $request->query->get('name', 'Aura');
        $view->setView('hello');
        $view->setLayout('default');
        $view->setData(array('name' => $name));
        $response->content->set($view->__invoke());
    });
}

Create your basic template templates/views/hello.php

1
2
3
<?php // templates/views/hello.php ?>
<?php $this->title()->set("Hello from aura"); ?>
<p>Hello <?= $this->name; ?></p>

and a very basic layout

1
2
3
4
5
6
7
8
9
10
<?php // templates/layouts/default.php ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en-us">
  <head>
    <?php echo $this->title(); ?>
  </head>
  <body>
    <?php echo $this->getContent(); ?>
  </body>
</html>

Let us fire the php server

1
php -S localhost:8000 web/index.php

and point your browser to http://localhost:8000 .

Probably very simple way how to use aura as a micro framework!.

You can see the example over github.

What is next?

Read Aura Framework v2 : The missing Manual and report/contribute to the book.

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!