Random thoughts | Hari KT

On programming

Standalone Form for PHP

Yesterday I wrote about Standalone Forms and Validation. It may need a little bit knowledge on how the Aura.Filter works. But that is a good start if you want to know how you can integrate the pieces of Aura.

Today I think I need to show you the very minimal approach you can take to build the form and validate your form. If you want to use a powerful validation and filtering use something like Aura.Filter or bind your favourite components which does the validation Respect, Symfony2 Validator, valitron and filtering with something like DMS-Filter.

You can see how you can integrate with different components as I did with Aura.Filter in the example in master branch.

I assume you know a bit about composer and how to install.

The composer.json file

1
2
3
4
5
6
7
{
    "minimum-stability": "dev",
    "require": {
        "aura/input": "1.0.0-beta1",
        "aura/view": "1.1.2"
    }
}

The page which you need to bring the form.

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
<?php

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

$loader = require __DIR__ . '/vendor/autoload.php';

class ContactForm extends Form
{
    public function init()
    {
        $this->setField('name')
            ->setAttribs([
                'id' => 'name',
                'size' => 20,
                'maxlength' => 20,
            ]);
        $this->setField('email')
            ->setAttribs([
                'size' => 20,
                'maxlength' => 20,
            ]);
        $this->setField('url')
            ->setAttribs([
                'size' => 20,
                'maxlength' => 20,
            ]);
        $this->setField('message', 'textarea')
            ->setAttribs([
                '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;
        });
    }
}

$form = new ContactForm(new Builder(), new Filter());

if ($_POST && $_POST['submit'] == 'send') {
    $data = $_POST;
    $form->fill($data);
    if ($form->filter()) {
        //
        echo "Yes successfully validated and filtered";
        var_dump($data);
        exit;
    }
}

$helper = new Aura\View\HelperLocator([
    'field'         => function () {
        return new Aura\View\Helper\Form\Field(
            require dirname(__DIR__) . '/vendor/aura/view/scripts/field_registry.php'
        );
    },
    'input'         => function () { return new Aura\View\Helper\Form\Input(
            require dirname(__DIR__) . '/vendor/aura/view/scripts/input_registry.php'
        );
    },
    'radios'        => function () { return new Aura\View\Helper\Form\Radios(new Aura\View\Helper\Form\Input\Checked); },
    'repeat'         => function () { return new Aura\View\Helper\Form\Repeat(
            require dirname(__DIR__) . '/vendor/aura/view/scripts/repeat_registry.php'
        );
    },
    'select'        => function () { return new Aura\View\Helper\Form\Select; },
    'textarea'      => function () { return new Aura\View\Helper\Form\Textarea; },
]);

$field = $helper->get('field');
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 Form, to make it standalone</title>
</head>
<body>
    <form method="post" action="" enctype="multipart/form-data" >
        <table cellpadding="0" cellspacing="0">
            <tr>
                <td>Name : </td>
                <td>
                <?php
                    echo $field($form->get('name'));
                    echo showFieldErrors($form, 'name');
                ?>
                </td>
            </tr>
            <tr>
                <td>Email : </td>
                <td>
                <?php
                    echo $field($form->get('email'));
                    echo showFieldErrors($form, 'email');
                ?>
                </td>
            </tr>
            <tr>
                <td>Url : </td>
                <td>
                <?php
                    echo $field($form->get('url'));
                    echo showFieldErrors($form, 'url');
                ?>
                </td>
            </tr>
            <tr>
                <td>Message : </td>
                <td>
                <?php
                    echo $field($form->get('message'));
                    echo showFieldErrors($form, 'message');
                ?>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                <?php
                echo $field($form->get('submit'));
                ?>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

That’s it. Pretty clear I guess. Still having trouble? The whole code lies in the minimalview branch of the form-example.

Standalone Forms and Validation

Update : I wrote a very minimal approach here

Recently Aura.Input was tagged Beta1. I would like to show you how you can use Aura.Input, Aura.Filter and Aura.View to create form.

The Aura.Input itself contains a basic filter implementation. As shown in earlier post Aura Turns 2

But in this post let us use the power of Aura.Filter. As Aura.Input doesn’t have a rendering capability you may need to use Aura.View as templating system ( see Using Aura.View ) or use the helper classes provided by Aura.View ( see below Without using Aura.View completely ) or create your own helper classes to render the same from the hints ( see Hints for the view ).

The whole example is in https://github.com/harikt/form-example repo. If you don’t have composer, you can download it from http://getcomposer.org and install the dependencies via composer.

In a nut shell

1
2
3
4
git clone https://github.com/harikt/form-example
cd form-example
php composer.phar install
php -S localhost:8000 web/index.php

Point your browser to the url http://localhost:8000

Let us look into some details

Inorder to use Aura.Filter with Aura.Input we need to implement the Aura\Input\FilterInterface.

This is just extending the Aura\Filter\RuleCollection and implementing the Aura\Input\FilterInterface as below.

1
2
3
4
5
6
7
8
9
<?php
namespace Domicile\Example;

use Aura\Filter\RuleCollection;
use Aura\Input\FilterInterface;

class Filter extends RuleCollection implements FilterInterface
{
}

Let us create the form class.

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
<?php
namespace Domicile\Example;

use Aura\Input\Form;

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

        $filter = $this->getFilter();

        $filter->addSoftRule('name', $filter::IS, 'string');
        $filter->addSoftRule('name', $filter::IS, 'strlenMin', 4);
        $filter->addSoftRule('email', $filter::IS, 'email');
        $filter->addSoftRule('url', $filter::IS, 'url');
        $filter->addSoftRule('message', $filter::IS, 'string');
        $filter->addSoftRule('message', $filter::IS, 'strlenMin', 6);
    }
}

Create the filter object and pass it on instantiation of form.

Please note that the $rootpath in this example is just above the vendor folder of the composer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$filter = new Domicile\Example\Filter(
    new RuleLocator(array_merge(
        require $rootpath . '/vendor/aura/filter/scripts/registry.php',
        ['any' => function () {
            $rule = new \Aura\Filter\Rule\Any;
            $rule->setRuleLocator(new RuleLocator(
                require $rootpath . '/vendor/aura/filter/scripts/registry.php'
            ));
            return $rule;
        }]
    )),
    new Translator(require $rootpath . '/vendor/aura/filter/intl/en_US.php')
);

$form = new Domicile\Example\ContactForm(new Builder, $filter);

The Aura.Input has two methods we can make use.

1 ) fill() method helps us to fill the data values

2 ) filter() method which helps to filter and validate data according to the rules specified in the form.

The code will looks like

1
2
3
4
5
6
7
8
9
10
if ($_POST && $_POST['submit'] == 'send') {
    $data = $_POST;
    $form->fill($data);
    if ($form->filter()) {
        //
        echo "Yes successfully validated and filtered";
        var_dump($data);
        exit;
    }
}

The form element gives you hints for the view. An example from the above

Hints for the view

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// get the hints for the name field
$hints = $form->get('name');

// the hints array looks like this:
$hints = array (
  'type' => 'text',
  'name' => 'name',
  'attribs' => 
  array (
    'id' => 'name',
    'type' => NULL,
    'name' => NULL,
    'size' => 20,
    'maxlength' => 20,
  ),
  'options' => 
  array (
  ),
  'value' => NULL,
)

Without using Aura.View completely

If you are not planning to use Aura.View entirely as templating, you can make use of Aura.View helpers which can render to make the form.

For that you need to instantiate Aura\View\HelperLocator and get the field object 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
$helper = new Aura\View\HelperLocator([
    'field'         => function () { 
        return new Aura\View\Helper\Form\Field(
            require dirname(__DIR__) . '/vendor/aura/view/scripts/field_registry.php'
        ); 
    },
    'input'         => function () { return new Aura\View\Helper\Form\Input(
            require dirname(__DIR__) . '/vendor/aura/view/scripts/input_registry.php'
        ); 
    },
    'radios'        => function () { return new Aura\View\Helper\Form\Radios(new Aura\View\Helper\Form\Input\Checked); },
    'repeat'         => function () { return new Aura\View\Helper\Form\Repeat(
            require dirname(__DIR__) . '/vendor/aura/view/scripts/repeat_registry.php'
        ); 
    },
    'select'        => function () { return new Aura\View\Helper\Form\Select; },
    'textarea'      => function () { return new Aura\View\Helper\Form\Textarea; },
]);

$field = $helper->get('field');
echo $field($form->get('name'));
echo $field($form->get('message'));

// echo $field($form->get('form-element'));

The above will output something like

<input id="name" type="text" name="name" size="20" maxlength="20" />

Using Aura.View

But you can use Aura.View to render it nicely. An example is

1
2
3
<?php
    echo $this->field($this->form->get('name'));
?>

You can still look more closely on the templates to see how it is used in the example.

If you have any problems or confusions, let me know by comments. I will try to address the same.

I would like to express huge Thanks to Paul M Jones for spending his valuable time on the project, giving valuable feedback on the implementations.

Happy PhPing!

Seriously? Tab vs Spaces

I have created a repo seriously, and have 3 commits as of now .

It has a file hell.php. I have created it by logging into user X and with vim as the editor without any settings in .vimrc.

vim with no settings, and used tab

Then from user harikt I have edited with vim which has some .vimrc setting like 1 tab = 4 spaces. Look into the code and see how beautiful it is.

Opening with geany it looks

Oh from geany with settings 1 tab = 4 spaces

Let us don’t create problems, but solutions!

It is just one line you need to mention

“According to your editor settings set 1 tab = 4 spaces.” . no?

Or you don’t need to convert the tab at all?

Is your tabs 4 spaces, 8 spaces, 2 spaces?

Please fork and commit with your favourite editor mentioning the settings, editor in your commit.

As as user I prefer consistency . And as I work with Aura, Symfony2, ZF1, ZF2 I love to follow spaces, than individual projects choosing their own styles which is a main benefit probably mostly to its users like me than the core developers of individual system who don’t care about other projects or its users?

After all when your project says we use tabs, do you care people who love to use spaces there? Do you merge when something like this comes?

Aura Turns 2

Looking over the commits on Aura.Router, Aura.Signal etc you will notice, aura project has turned 2.

And today, I would like to introduce you, the new born baby still under active development and refactoring based on user feedback, the form library for php, Aura.Input.

The Aura.Input, doesn’t have a rendering functionality. But you can always use Aura.View or create your own helpers.

A basic filtering based on closure exists in Aura.Input. But you are not limited, you can use your own filtering components or integrate Aura.Filter.

Let us look at some code.

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
<?php
// use composer or require '/path/to/Aura.Input/src.php';

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

$filter = new Aura\Input\Filter();

// validate
$filter->setRule('name', 'Name should be alpha 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;
});

class ContactForm extends Form
{
    public function init()
    {
        $name    = $this->setField('name');
        $email   = $this->setField('email');
        $url     = $this->setField('url');
        $message = $this->setField('message', 'textarea');
    }
}

$form = new ContactForm(new Builder, $filter);

$values = [
    'name' => 'Hari K T',
    'email' => 'oh will it works!',
    'url' => 'google.com',
    'message' => 'Aweso'
];

$form->setValues($values);

$passed = $form->filter();

// 'foo' is invalid
if (! $passed) {
    // get all messages
    $actual = $form->getMessages();
    var_dump($actual);
}

Try it out, we have some more documentation for the Aura.Input. I warn the api is still not stable for Aura.Input and is not yet released a Beta.

But it is a good start!

Aura.Http : Request and Response

The Aura.Http package provide you the tool to build and send request and response.

Instantiation:

The easiest way is

1
$http = require 'path/to/Aura.Http/scripts/instance.php';

What it gives you is an object of Aura\Http\Manager. If you want to create manually you can look into the instance.php

Building your Response

Probably you may not have bothered too much on building the http response either the framework does it for you, or until you need to send the correct response.

To create a proper http response via Aura.Http we need to create a response object.

1
$response = $http->newResponse();

Now you have the response object. You can set the header via

1
$response->headers->set('Header', 'Value');

If you have an array of headers you can use setAll

1
2
3
4
5
6
7
8
$response->headers->setAll([
    'Header-One' => 'header one value',
    'Header-Two' => [
        'header two value A',
        'header two value B',
        'header two value C',
    ],
]);

So a basic example of setting header value is

1
$response->headers->set('Content-Type', 'text/plain');

Setting Content

The header values are for the browser to understand what is coming from server, and how it should render etc.

So we need to set the content. This can be achieved via setContent method.

1
$response->setContent('<html><head><title></title></head><body>Hello World!</body></html>');

You can always get the content via calling getContent.

Setting and Getting Cookies

Sometimes we may want to set the cookies. You can do it as

1
2
3
4
5
6
7
8
$response->cookies->set('cookie_name', [
    'value'    => 'cookie value', // cookie value
    'expire'   => time() + 3600,  // expiration time in unix epoch seconds
    'path'     => '/path',        // server path for the cookie
    'domain'   => 'example.com',  // domain for the cookie
    'secure'   => false,          // send by ssl only?
    'httponly' => true,           // send by http/https only?
]);

The array keys mimic the setcookie parameters. If you have an array you can use setAll.

1
2
3
4
5
6
7
8
$response->cookies->setAll([
    'cookie_foo' => [
        'value' => 'value for cookie foo',
    ],
    'cookie_bar' => [
        'value' => 'value for cookie bar',
    ],
]);

You can get a cookie by calling get method on cookies.

1
$response->cookies->get('cookie_name');

Setting and Getting Status

By default the status code is 200. But at some point of time like the one I explained earlier in Status Code 304, we don’t need to send the whole content. But just the status code.

This is possible via setStatusCode and setStatusText

1
2
$response->setStatusCode(304);
$response->setStatusText('Same As It Ever Was');

Sending your response

And finally we can send the response back. We can call the send method and pass the response object.

1
$http->send($response);

The full source code of example is

1
2
3
4
5
6
$http = require 'path/to/Aura.Http/scripts/instance.php';
// send a response
$response = $http->newResponse();
$response->headers->set('Content-Type', 'text/plain');
$response->setContent('<html><head><title></title></head><body>Hello World!</body></html>');
$http->send($response);

From terminal start the server by php -S localhost:8000 example.php and pointintg to localhost:8000 in your browser.

In order to render just Hello World! in the browser the Content-Type we added should be text/html.

We can always change the header status code, content-type etc before we call send() method.

Let us modify the example at Status Code 304

1
2
3
4
5
6
7
8
9
10
11
$http = require 'path/to/Aura.Http/scripts/instance.php';
$response = $http->newResponse();
if ( isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && 
    $_SERVER['HTTP_IF_MODIFIED_SINCE'] == 'Tue, 15 Jan 2011 12:00 GMT' ) {
    $response->setStatusCode(304);
} else {
    $response->headers->set('Content-Type', 'text/html');
    $response->headers->set('Last-Modified', 'Tue, 15 Jan 2011 12:00 GMT');
    $response->setContent('<html><head><title></title></head><body>Hello World!</body></html>');
}
$http->send($response);

You would have noticed I have used $_SERVER variable. In Aura.Http, there is no methods to access the global server values. This is because the $_SERVER values are not the exact http requested header. The server modifies the request and we will be only getting the manipulated values if we use $_SERVER, $_GET, $_POST values.

Aura.Http only helps you to build, create, modify response and request.

Creating Http Request

We talked about response so far. What does Request actually mean?

Client -> Request something -> Server Responds

So that means we are trying to be a client or a browser, and making the necessary headers and sending to server to get the corresponding response.

We can get all the repos of a user in github via curl.

1
curl -i https://api.github.com/users/pmjones/repos

The same can be achieved via Aura.Http. The Aura.Http provides a means to do the same with PHP. It uses curl if it is available or stream to make this happen.

You need to create a Request object.

1
$request = $http->newRequest();

Set the url via setUrl method and send.

1
2
3
4
5
6
$request->setUrl('https://api.github.com/users/pmjones/repos');
$stack = $http->send($request);
$repos = json_decode($stack[0]->content);
foreach ($repos as $repo) {
    echo $repo->name . PHP_EOL;
}

There are more things to say. It can do basic authentication, post values etc. Browse the documentation examples, source code, tests, and api.

Source Code : https://github.com/auraphp/Aura.Http

Documentation : http://auraphp.github.com/Aura.Http/version/1.0.0/

API : http://auraphp.github.com/Aura.Http/version/1.0.0/api/

Our Awesome Php People

Recently github introduces contributions chart. So I peeped into some of the people of our php community. It seems @fabpot is the one who contributes almost every day. Just 21 days without any contribution.

Contributions by fabpot Contributions by weierophinney Contributions by pmjones Contributions by willdurand Contributions by Seldaek Contributions by markstory Contributions by taylorotwell Contributions by WanWizard Contributions by drak Contributions by nikic Contributions by avalanche123 Contributions by shama Contributions by vrana Contributions by philsturgeon Contributions by DASPRiD Contributions by mvriel Contributions by c9s Contributions by weaverryan Contributions by bschussek Contributions by nateabele Contributions by garak Contributions by beberlei Contributions by codeguy Contributions by lsmith77 Contributions by stof Contributions by EavnDotPro Contributions by nateabele Contributions by kriswallsmith Contributions by nrk Contributions by naderman Contributions by gwoo Contributions by jwage Contributions by chartjes Contributions by Tocacar Contributions by FrenkyNet Contributions by till Contributions by Ocramius Contributions by odino Contributions by josegonzalez Contributions by dereuromark Contributions by HosipLan Contributions by alganet Contributions by ezimuel Contributions by auroraeosrose Contributions by enygma Contributions by ralphschindler Contributions by AD7six Contributions by ADmad Contributions by augustohp Contributions by BlaineSch Contributions by alexbilbie Contributions by narfbg Contributions by dg Contributions by schmittjoh Contributions by jschreuder Contributions by Geczy Contributions by dzuelke Contributions by evert Contributions by akrabat Contributions by seejohnrun Contributions by guilhermeblanco Contributions by Maks3w Contributions by kore Contributions by dragoonis Contributions by daschl Contributions by wilmoore Contributions by TheFrozenFire Contributions by nickl- Contributions by lorenzo Contributions by rchavik Contributions by davidpersson Contributions by henriquemoody Contributions by Freeaqingme Contributions by dbu Contributions by dshafik Contributions by Vrtak-CZ Contributions by padraic Contributions by saltybeagle Contributions by Hounddog Contributions by ceeram Contributions by jmikola Contributions by cweiske Contributions by rdohms

and I too did some contributions in 2012 for auraphp and other projects.

Contributions by harikt

The list is not complete, if you feel I missed your name or someone you feel needs to be added just give a tweet to me or fork the repo from github and send a PR.

Thoughts on Package/Component Structure

Comparing a software X with Y will not make anything worst, but makes it better. But many of them will think it as a promotional stuff. It is not anyones’s problem. Some like to build it that way, some like the other way.

So I am not comparing X with Y here.

Not talking about package like Guzzle:

I am not mentioning building something like Guzzle, which is a framework that includes the tools needed to create a robust web service client.

But I am interested in talking about the packages which can be used to build something like Guzzle when you look into the require of composer.json.

That means something like Aura.Http which can be used to make a request to google and do the search if needed or post etc.

Structure of Package or Component:

1 ) We need to name a package.

Let us go for the PSR-0 naming.

Each namespace must have a top-level namespace (“Vendor Name”), and a Package name. Probably you will end up with Vendor.Package or Vendor_Package .

2 ) Composer/Eath, are great tools which help you to manage the dependency management in your PHP projects. So we need a composer.json or package.yml .

3 ) We are creating a package or component, so obviously it will contain source files and test files. It will be a mess when we keep all tests and source files in a same place. Most of them uses either src folder or lib or library to keep source files and tests to keep test files. Probably you have some documentation, a docs folder may help. May be some executable scripts. You can also add a scripts or bin folder.

Now your structure will be something like

1
2
3
4
5
6
7
8
9
10
Vendor.Package
  ├── composer.json
  ├── package.yml
  ├── docs
  ├── src
  │   └── Vendor
  │       └── Package
  └── tests
      └── Vendor
          └── Package

The above structure follows a PSR-0 naming convention for package/component.

NIH : We all create new packages for we don’t like some other package invented here, not for its not invented here or probably to make use of newer stuffs like traits, closures etc available in PHP 5.4 than sticking with PHP 5 or sometimes it is not inveneted here.

So add your depenedencies to composer.json or package.yml

Let us assume we are going to create a Validation pacakge. Probably you love annotations or yml format. It is always a better idea to keep the annotations, yaml etc on a bridge than in the Validation package. Remember you have composer, let the bridge package composer.json helps you to download validation package, annotation library. This also helps you to write your integration tests in bridge package than making a dependency on the Validation package.

And also help people to use different annotations library than a single one or you will end up messing with more annotation classes.

I guess this helps people to

1 ) fork and contribute

2 ) Even if there is no documentation, it helps to look into the source and get the point. Else a lot of classes confuses people.

Nothing is developed to make it bad, everything is made for good. Though at-times it acts badly.

These are some of the principles I learned looking at various projects like Aura, Symfony2, ZF2, Lithium, Fuel2, Illuminate… you name it.

The Moving From Drupal7 to Octopress

Recently I ported the blog from Drupal7 to octopress for certain reasons. The php script that helped me to do the porting from drupal to octopress is given below. This is a port of the ruby script with some additional fixes on the SQL. This needs pandoc to be installed to convert from Html to Markdown. There is also slight isssue with the syntaxhighlighter, which you may want to manually fix.

drupal7 to octopress
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
<?php
function drupalProcess($dbname, $username, $password, $host = 'localhost') {
    $dsn = "mysql:host=$host;dbname=" . $dbname;
    $pdo = new Pdo($dsn, $username, $password, $options = array(
          PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
      )
    );
    $sql = "SELECT n.nid, 
            n.title, 
            n.created, 
            n.changed, 
            b.body_value AS 'body', 
            b.body_summary, 
            b.body_format, 
            n.status, 
            l.alias AS 'slug', 
            GROUP_CONCAT( d.name SEPARATOR ', ' ) AS 'tags' 
        FROM node AS n 
        JOIN field_data_body b ON b.entity_id = n.nid 
        JOIN taxonomy_index t ON t.nid = n.nid 
        JOIN taxonomy_term_data d ON t.tid = d.tid 
        LEFT JOIN url_alias AS l ON l.source = CONCAT( 'node/', n.nid ) 
        WHERE n.type = 'blog' AND b.revision_id = n.vid 
        GROUP BY n.nid";
    $sth = $pdo->prepare($sql);
    $sth->execute();
    $rows = $sth->fetchAll();
    $bool = array(0 => 'false', 1 => 'true');
    foreach ($rows as $row) {
        $fp = fopen('htmlcontents.html', 'w');
        fwrite($fp, $row['body']);
        fclose($fp);
        $datetime = new DateTime();
        $datetime->setTimestamp($row['created']);
        $date = $datetime->format('Y-m-d');
        $contents = '---' . "\n";
        $contents .= 'layout: post' . "\n";
        $contents .= 'title: ' . $row['title'] . "\n";
        $contents .= 'categories: [' . $row['tags'] . ']' . "\n";
        $contents .= 'published: ' . $bool[$row['status']] . "\n";
        $contents .= 'date: ' . $datetime->format('Y-m-d H:i') . "\n";
        $contents .= '---' . "\n";
        if (!empty($row['slug'])) {
            $list = explode('/', $row['slug']);
            if (count($list) > 1) {
                $row['slug'] = end($list);
            }
        } else {
            $row['slug'] = 'node-' . $row['nid'];
        }

        $pandoc = '';
        exec('pandoc -t markdown -f html htmlcontents.html', &$pandoc);
        $contents .= implode(' ', $pandoc);
        $url = 'source/posts/' . $date . '-' . $row['slug'] . '.markdown';

        $contents .= "\n";
        if ( !file_exists($url)) {
            $fp = fopen($url, "w");
            fwrite($fp, $contents);
            fclose($fp);
        } else {
            echo "File exists issue : " . $row['slug'] . "\n";
        }
    }
}
//optional hostname
drupalProcess('dbname', 'username', 'password');

Happy porting!

Resize Image Keeping Aspect Ratio in Imagine

I was working with Imagine recently. I want to create a standard width and height for the image that is created. Eg: 500 X 300 .

The user will be uploading different size images and I want to resize the image to X width and Y height. I was using imagine and the code helps to make this happen filling the blank space with white color without loosing aspect ratio.

resize image with imagine
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
$source = 'image.jpeg';
$destination = 'resize.jpg';
$width  = 300;
$height = 500;

$imagine   = new Imagine\Gd\Imagine();
$size      = new Imagine\Image\Box($width, $height);
$mode      = Imagine\Image\ImageInterface::THUMBNAIL_INSET;
$resizeimg = $imagine->open($source)
                ->thumbnail($size, $mode);
$sizeR     = $resizeimg->getSize();
$widthR    = $sizeR->getWidth();
$heightR   = $sizeR->getHeight();

$preserve  = $imagine->create($size);
$startX = $startY = 0;
if ( $widthR < $width ) {
    $startX = ( $width - $widthR ) / 2;
}
if ( $heightR < $height ) {
    $startY = ( $height - $heightR ) / 2;
}
$preserve->paste($resizeimg, new Imagine\Image\Point($startX, $startY))
    ->save($destination);

A normal image of size 500 X 500

a kitten

when resized to 300 X 200

resized image

and 300 X 400

resized image

A huge Thanks to the person who helped me on Symfony2 irc to find the different modes. I am not recalling the irc handle currently. I will update once I remember the same.

Image courtsey http://placekitten.com/