Using Cakephp Migration as Standalone

Cakephp version 3 have a nice ORM. When using the cakephp/orm, it may be nice to integrate cakephp/migration than any other migration libraries, even though it uses phinx under the hood.

Lets see how we can install and integrate cakephp/migration in our application.

1
composer require cakephp/migrations:dev-master

The dev-master is currently passed for we need the latest version of master branch. Before this pull request, it was having dependency on cakephp/cakephp, which is not needed.

Our migration console script

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
#!/usr/bin/env php
<?php
use Cake\Cache\Cache;
use Cake\Core\Configure;
use Cake\Core\Configure\Engine\PhpConfig;
use Cake\Datasource\ConnectionManager;
use Migrations\MigrationsDispatcher;

$projectDirectory = dirname(__DIR__);
$file   = $projectDirectory . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
$loader = null;

if (file_exists($file)) {

    $loader = require $file;

    if (!defined('CACHE')) {
        define('CACHE', $projectDirectory . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
    }
}

if ( ! $loader) {
    throw new RuntimeException('vendor/autoload.php could not be found. Did you run `composer install`?');
}

if (!defined('PHINX_VERSION')) {
    define('PHINX_VERSION', (0 === strpos('@PHINX_VERSION@', '@PHINX_VERSION')) ? '0.6.6' : '@PHINX_VERSION@');
}

try {
    Configure::config('default', new PhpConfig($projectDirectory . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR) );
    Configure::load('app', 'default', false);
} catch (\Exception $e) {
    exit($e->getMessage() . "\n");
}

Cache::setConfig(Configure::consume('Cache'));
ConnectionManager::setConfig(Configure::consume('Datasources'));
$application = new MigrationsDispatcher(PHINX_VERSION);
$application->run();

You may notice the constant CACHE. We can get rid of constants if needed. Normally I copy portions of config/app.default.php and keep in /config/app.php file which uses some of these constants.

Once done, we can run the migration script as

1
bin/cake-phinx

You may probably want to allow necessary permission for the script to execute. You can do via chmod +x bin/cake-phinx

There is another PR 312 waiting for approval. If it is merged you will get all the functionalities of https://book.cakephp.org/3.0/en/console-and-shells/orm-cache.html

PS : If you came across some errors regarding migration plugin not loaded etc. You may want to add the below code before calling MigrationsDispatcher

1
2
3
Cake\Core\Plugin::load('Migrations', [
    'path' => $projectDirectory . '/vendor/cakephp/migrations/',
]);

Building Modular Applications With PSR-7

PSR-7, the HTTP message interfaces opened a new door of creating modular applications.

Sadly many of the PSR-7 implementations added many helper methods.

So if someone is creating a library that needs a PSR-7 implementations they tie the particular library with the PSR-7 implementation and use these convinient helper methods.

So was PSR-15: interfaces for HTTP Middleware and PSR-17: interfaces for HTTP Factories was proposed.

When creating a module one of the most challenging part is how to serve the javascript, css and images. We are going to use hkt/psr7-asset which is a fork of Aura.Asset_Bundle . What you want to do is only map the path to the assets folder.

We can discuss more on the features later and start writing our first module. The source code of the module is hosted at github.

1
mkdir -p {src/{Middleware},templates,public/{css,images,js}}

The command will create folder structure as below.

If you are not using *nix probably you want to create each folder separately.

1
2
3
4
5
6
7
├── public
│   ├── css
│   ├── images
│   └── js
├── src
│   └── Middleware
└── templates

Lets create our Welcome middleware.

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
<?php
namespace Hkt\Psr7AssetExample\Middleware;

use Interop\Http\Factory\ResponseFactoryInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Interop\Http\ServerMiddleware\DelegateInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Expressive\Template\TemplateRendererInterface;

class Welcome implements MiddlewareInterface
{
    private $template;

    private $responseFactory;

    public function __construct(
        TemplateRendererInterface $template,
        ResponseFactoryInterface $responseFactory
    ) {
        $this->template = $template;
        $this->responseFactory = $responseFactory;
    }

    public function process(
        ServerRequestInterface $request,
        DelegateInterface $delegate
    ) {
        $response = $this->responseFactory->createResponse();
        $response = $response->withHeader('Content-Type', 'text/html');
        $response->getBody()->write(
            $this->template->render('hkt-psr7-asset-example::welcome', [])
        );
        return $response;
    }
}

You can see we have not tied the Welcome class to any PSR-7 implementation. But instead to many interfaces. This helps us to use Welcome middleware with any PSR-7 based frameworks.

How can we serve the static files?

This can be solved with zf-asset-manager. What it does is copy the assets to the public folder and the files are served by webserver.

But what about if you need to alter the behaviour of the file?

Eg : You want to override the hello.js contents with something like

1
2
3
$(function () {
    alert("Hello World");
});

This is possible with the hkt/psr7-asset.

What you need is get the asset locator and set the path to vendor/package as

1
2
$assetLocator = $di->get('Hkt\Psr7Asset\AssetLocator');
$assetLocator->set('hkt/psr7-asset-example', dirname(dirname(__DIR__)) . '/public');

alternatievely you can set individual paths or files also.

1
2
$assetLocator = $di->get('Hkt\Psr7Asset\AssetLocator');
$assetLocator->set('vendor/package/images/someimage.png', '/path/to/different-image.png');

The full source code of the example module is at https://github.com/harikt/psr7-asset-example

How can we make use of this module in your application?

Any frameworks that supports psr-7, psr-15 and psr-17 interfaces should work. We will use zend expressive with Aura.Di as dependency injection container and Aura.Router.

1
composer create-project zendframework/zend-expressive-skeleton expressive

Below is selection process

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
Installing zendframework/zend-expressive-skeleton (2.0.1)
  - Installing zendframework/zend-expressive-skeleton (2.0.1) Loading from cache
Created project in expressive
> ExpressiveInstaller\OptionalPackages::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies

  What type of installation would you like?
  [1] Minimal (no default middleware, templates, or assets; configuration only)
  [2] Flat (flat source code structure; default selection)
  [3] Modular (modular source code structure; recommended)
  Make your selection (2): 3
  - Adding package zendframework/zend-expressive-tooling (^0.3.2)
  - Copying src/App/src/ConfigProvider.php

  Which container do you want to use for dependency injection?
  [1] Aura.Di
  [2] Pimple
  [3] Zend ServiceManager
  Make your selection or type a composer package name and version (Zend ServiceManager): 1
  - Adding package aura/di (^3.2)
  - Copying config/container.php
  - Copying config/ExpressiveAuraConfig.php
  - Copying config/ExpressiveAuraDelegatorFactory.php

  Which router do you want to use?
  [1] Aura.Router
  [2] FastRoute
  [3] Zend Router
  Make your selection or type a composer package name and version (FastRoute): 1
  - Adding package zendframework/zend-expressive-aurarouter (^2.0)
  - Copying config/routes.php
  - Copying config/autoload/router.global.php

  Which template engine do you want to use?
  [1] Plates
  [2] Twig
  [3] Zend View installs Zend ServiceManager
  [n] None of the above
  Make your selection or type a composer package name and version (n): 2
  - Adding package zendframework/zend-expressive-twigrenderer (^1.4)
  - Copying config/autoload/templates.global.php
  - Copying src/App/templates/error/404.html.twig
  - Copying src/App/templates/error/error.html.twig
  - Copying src/App/templates/layout/default.html.twig
  - Copying src/App/templates/app/home-page.html.twig

  Which error handler do you want to use during development?
  [1] Whoops
  [n] None of the above
  Make your selection or type a composer package name and version (Whoops): 1
  - Adding package filp/whoops (^2.1.7)
  - Copying config/autoload/development.local.php.dist

Once the installation is finished we can start integrating the module.

1
cd expressive

Add to your composer.json the below configuration.

1
2
3
4
5
6
7
8
9
10
11
12
"repositories": [
    {
        "type": "git",
        "url": "https://github.com/harikt/psr7-asset-example"
    }
],
"require": {
    "http-interop/http-factory-diactoros": "^0.2.0",
    "hkt/psr7-asset-example":"1.*@dev",
    "hkt/psr7-asset":"1.*@dev",
    ...
},

I think the dependencies are self explanatory. In case you need any help feel free to comment on the post.

We need a few things for the assets to be displayed.

  1. Add the asset router. So that any request coming to /asset/* can be served by Hkt\Psr7Asset\AssetAction.
  2. Configure the Interop\Http\Factory\ResponseFactoryInterface to return an instance of Http\Factory\Diactoros\ResponseFactory.
  3. Add a route to serve the example welcome action ‘Hkt\Psr7AssetExample\Middleware\Welcome’

Below is what we can do with Aura.Di configuration.

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
<?php
// src/App/src/Config/Common.php
namespace App\Config;

use Aura\Di\Container;
use Aura\Di\ContainerConfigInterface;
use Zend\Expressive\Router\Route;

class Common implements ContainerConfigInterface
{
    public function define(Container $di)
    {
        $di->set('Interop\Http\Factory\ResponseFactoryInterface', $di->lazyNew('Http\Factory\Diactoros\ResponseFactory'));
    }

    public function modify(Container $di)
    {
        $router = $di->get('Zend\Expressive\Router\RouterInterface');

        // PSR-7 asset Router

        $route = new Route('/asset/{vendor}/{package}/{file}', 'Hkt\Psr7Asset\AssetAction', ['GET'], 'hkt/psr7-asset');
        $route->setOptions([
            'tokens' => [
                'file' => '(.*)'
            ]
        ]);
        $router->addRoute($route);
        $router->addRoute(new Route('/', 'Hkt\Psr7AssetExample\Middleware\Welcome', ['GET'], 'hkt/psr7-asset-example:welcome'));
        // Try modifying the below lines
        // $assetLocator = $di->get('Hkt\Psr7Asset\AssetLocator');
        // $rootPath = dirname(dirname(dirname(dirname(__DIR__))));
        // $assetLocator->set('hkt/psr7-asset-example/images/white-image.png', $rootPath . '/public/zf-logo.png');
    }
}

Now we can load the Aura.Di configuration in config/container.php .

1
2
3
4
5
6
7
8
9
<?php
.... more code.

return $builder->newConfiguredInstance([
    new ExpressiveAuraConfig(is_array($config) ? $config : []),
    Hkt\Psr7Asset\Container\AssetConfig::class,
    Hkt\Psr7AssetExample\Container\Common::class,
    App\Config\Common::class,
]);

What it does, is load different configurations of different modules.

If you run

1
php -S 0.0.0.0:8080 -t public public/index.php

and point to http://localhost:8080 you can see the welcome screen of example module.

Try modifying the hkt/psr7-asset-example/images/white-image.png path to a different image and browse http://localhost:8080/asset/hkt/psr7-asset-example/images/white-image.png

It will render that image.

All source code is accompanied at https://github.com/harikt/psr7-asset-example-zendexpressive

Caching

We can use psr7-asset-cache to cache all public files in production.

Hope this will be helpful to someone to begin writing modular applications.

Aura.Di 2.x to 3.x Upgrade Guide

3.x has a very minimal BC break. But if you are not sure what are they, then you may feel the pain. I am trying to document most of them, incase I missed please edit and send a pull request.

I will try to eventually pushed to the main Aura.Di repo.

BC Breaks

Instantiation

The way di container is instantiated has been changed from

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Aura\Di\Container;
use Aura\Di\Factory;
use Aura\Di\ContainerBuilder;

$di = new Container(new Factory);

// or 

$container_builder = new ContainerBuilder();
$di = $container_builder->newInstance(
    array(),
    array(),
    $auto_resolve = false
);

to

1
2
3
4
5
6
7
8
9
10
11
use Aura\Di\ContainerBuilder;

$container_builder = new ContainerBuilder();

// use the builder to create and configure a container
// using an array of ContainerConfig classes
$di = $container_builder->newConfiguredInstance([
    'Aura\Cli\_Config\Common',
    'Aura\Router\_Config\Common',
    'Aura\Web\_Config\Common',
]);

setter vs setters

$di->setter is now $di->setters. Please note there is an additional s in the end. https://github.com/auraphp/Aura.Di/issues/115.

Automatic locking

Automatic locking of container once an object is created by container. So make sure everything is lazy call, else you will run something like Cannot modify container when locked.

Config vs ContainerConfig

Version 2 Aura\Di\Config is now Aura\Di\ContainerConfig

Features

lazyGetCall

Example taken from Radar

1
$di->params['Radar\Adr\Handler\RoutingHandler']['matcher'] = $di->lazyGetCall('radar/adr:router', 'getMatcher');

Here the matcher assigned is taken from the RouterContainer getMatcher method.

Instance Factories

Create multiple instances of the class. You can read the docs

Cakephp ORM and Logging Queries

Working with cakephp/orm library, I needed to log all the queries. Cakephp provides a way to do it via cakephp/log.

1
2
3
4
5
6
7
8
use Cake\Log\Log;

Log::config('queries', [
  'className' => 'File',
  'path' => '/my/log/path/',
  'file' => 'app',
  'scopes' => ['queriesLog']
]);

But you are not limited, if you need to configure it to a PSR-3 logger like monolog/monolog

1
2
3
4
5
6
7
8
9
use Cake\Log\Log;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

Log::config('default', function () {
    $log = new Logger('cli');
    $log->pushHandler(new StreamHandler('php://stdout'));
    return $log;
});

That was pretty simple and it logs to cli.

Thank you José Lorenzo Rodríguez for providing the necessary information.

How about logging the queries to a debugbar?

Install fabfuel/prophiler

1
composer require fabfuel/prophiler

Configuring debugbar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Cake\Log\Log;
use Fabfuel\Prophiler\Profiler;
use Fabfuel\Prophiler\Toolbar;
use Fabfuel\Prophiler\DataCollector\Request;
use Fabfuel\Prophiler\Adapter\Psr\Log\Logger;

$profiler = new Profiler();
$toolbar = new Toolbar($profiler);
// add your data collectors
// $toolbar->addDataCollector(new Request());

Log::config('db', function () use ($profiler) {
  $log = new Logger($profiler);
  return $log;
});

Using a PSR-7 framework like zend-expressive, bitExpert/prophiler-psr7-middleware is your friend.

CakePHP ORM and Illuminate Pagination

Do you know CakePHP version 3 has a lovely ORM which can be used as standalone?

Thank you José Lorenzo Rodríguez and every contributor, for your hard work.

1
composer require cakephp/orm

That’s it.

Working on I noticed I need to do some pagination. Oh, remember we have illuminate/pagination. Why not use it?

Problem, there seems no one have implemented it. How could we achieve it? Lets do it.

1
composer require illuminate/pagination

If you are using a psr-7 request / response here is the middleware for you.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Illuminate\Pagination\Paginator as IlluminatePaginator;
class PaginatorMiddleware
{
    public function __invoke( ServerRequestInterface $request, ResponseInterface $response, callable $next = null )
    {
        IlluminatePaginator::currentPageResolver(function ( $pageName = 'page' ) use($request )
        {
            $params = $request->getQueryParams();
            return empty($params[$pageName]) ? 1 : $params[$pageName];
        });

        IlluminatePaginator::currentPathResolver(function () use($request )
        {
            return $request->getUri()->getPath();
        });

        return $next($request, $response);
    }
}

What we did above are a few things for Illuminate to give the url path when it is doing the pagination. So for example /article?page=<page-number> will come instead of just ?page=<page-number>.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
use Cake\ORM\TableRegistry;
use Illuminate\Pagination\Paginator;
use Illuminate\Pagination\LengthAwarePaginator;

$table = TableRegistry::get('Articles');
$currentPage = 1;
$perPage = 20;
$query = $table->find('all');
$total = $query->count();
$items = $query->page($currentPage, $perPage);
$paginator = new LengthAwarePaginator($items, $total, $perPage, $currentPage, [
  'path' => Paginator::resolveCurrentPath(),
]);
echo $paginator->render();

The above code is querying the articles and rendering the pagination with the returned results.

By default the Presenter is Illuminate\Pagination\BootstrapThreePresenter, but you can create your own.

I hope you will love the integration.

Thank you everyone for your support and hard work on components to make PHP better every day.

Eloquent and Pagination Inside Zend Expressive

Recently working with eloquent (Laravel’s orm), zend expressive and zend view, I wanted to integrate pagination.

It was simple as registering a Paginator middleware.

1
2
3
4
5
6
7
8
9
10
11
use Illuminate\Pagination\Paginator;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

IlluminatePaginator::currentPageResolver(function ($pageName) use ($request) {
    $params = $request->getQueryParams();
    return empty($params[$pageName]) ? 1 : $params[$pageName];
});
IlluminatePaginator::currentPathResolver(function () use ($request) {
    return $request->getUri()->getPath();
});

and you can call paginate on the Model.

Eg : Consider you have a Post model.

1
$posts = Post::paginate(20);

and in view you can iterate through the $posts and render the pagination. The $posts is an object of LengthAwarePaginator.

You can also modify the presenter accordingly. Default comes with BootstrapThreePresenter

1
2
3
4
5
6
7
8
<?php
foreach ($this->posts as $post) {
?>
    <?= $post->title . "<br />" ?>
<?php
}
?>
<?= $this->posts->render() ?>

Note : Please be aware of the issues/10909.

Integrating Zend Form in Zend Expressive and View

Example is based using Aura.Di. But the functionality will be same for any containers. First register the service Zend\View\HelperPluginManager, so that we can access the same object.

To register the form helpers, create the object of Zend\Form\View\HelperConfig and pass the Zend\View\HelperPluginManager service.

Example code with Aura.Di version 3 configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
use Aura\Di\ContainerConfig;
use Aura\Di\Container;
use Zend\Form\View\HelperConfig;

class ViewHelper extends ContainerConfig
{
    public function define(Container $di)
    {
        $di->set('Zend\View\HelperPluginManager', $di->lazyNew('Zend\View\HelperPluginManager'));
    }

    public function modify(Container $di)
    {
        $serviceManager = $di->get('Zend\View\HelperPluginManager');
        $helper = new HelperConfig();
        $helper->configureServiceManager($servicemanager);
    }
}

Creating your own zend-view helper

  1. Create your helper class
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
namespace App\View\Helper;

use Zend\View\Helper\AbstractHelper;

class HasError extends AbstractHelper
{
    // add as many parameters you want to pass from the view
    public function __invoke()
    {
        // some code
    }
}
  1. Registering your helper class.

First get the Zend\View\HelperPluginManager service.

2.a ) Registering as a factory

1
2
3
$serviceManager->setFactory('hasError', function () {
    return new \App\View\Helper\HasError();
});

2.b ) As an invokable

1
$serviceManager->setInvokableClass('hasError', 'App\View\Helper\HasError');

Now you can access inside zend-view as $this->hasError(). If your view helper need dependencies don’t use the setInvokableClass method. Use factory and get the object from the container.

1
2
3
$serviceManager->setFactory('hasError', function () use ($di) {
     return $di->get('App\View\Helper\HasError');
});

I wished if $serviceManager can understand the aura’s lazyNew functionality so that we don’t need to register it as a service.

Eg : Below will not work.

1
$serviceManager->setFactory('hasError', $di->lazyNew('App\View\Helper\HasError'));

This is what I love to see it working for this a closure, but with namespaced.

Custom Events in Symfony2 Bundle

In this tutorial we will create a custom event for symfony2 bundle.

Assuming you have downloaded the symfony-standard distribution to play.

Create HktEventBundle via sensio generator bundle.

1
php app/console generate:bundle --namespace=Hkt/EventBundle --dir src --no-interaction

Create the event class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// src/Hkt/EventBundle/Event/PageViewed.php
namespace Hkt\EventBundle\Event;

use Symfony\Component\EventDispatcher\Event;

class PageViewed extends Event
{
    protected $name;

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

    public function getName()
    {
        return $this->name;
    }
}

Add as many methods/properties which are needed from the listener. Instead of creating an event class we can make use of generic event also.

Dispatching Event

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
//src/Hkt/EventBundle/Controller/DefaultController.php
namespace Hkt\EventBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Hkt\EventBundle\Event\PageViewed;

class DefaultController extends Controller
{
    /**
     * @Route("/hello/{name}")
     * @Template()
     */
    public function indexAction($name)
    {
        $event = new PageViewed($name);
        $this->get('event_dispatcher')->dispatch('hkt.event.page_viewed', $event);
        return array('name' => $name);
    }
}

Listener

Create the listener to do what you want to do with the dispatched/triggered event.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
// src/Hkt/EventBundle/EventListener/PageViewedListener.php
namespace Hkt\EventBundle\EventListener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Hkt\EventBundle\Event\PageViewed;

class PageViewedListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return array(
            'hkt.event.page_viewed' => 'handler',
        );
    }

    public function handler(PageViewed $event)
    {
        // $event->getName();
        // do what you want with the event
    }
}

In order to get the PageViewedListener to be called, we need to register the listener to the event_dispatcher.

Add the below lines in services.yml or services.xml accordingly.

1
2
3
4
5
# src/Hkt/EventBundle/Resources/config/services.yml
hkt.event.page_viewed:
    class: Hkt\EventBundle\EventListener\PageViewedListener
    tags:
        - {name: kernel.event_listener, event:hkt.event.viewed, method:handler} 

or in xml as

1
2
3
4
5
<services>
    <service id="hkt.event.page_viewed" class="Hkt\EventBundle\EventListener\PageViewedListener">
        <tag name="kernel.event_listener" event="hkt.event.page_viewed" method="handler"/>
    </service>
</services>

There may be better ways to do this. If you think so do share your knowledge.

Thank you.

20 Years of PHP

First my apologies being late! I hope you all know PHP is celebrating its 20th years of existence in the web.

There is something that makes PHP unique that helps to standout with other languages.

In this opporchunity I would like to thank the creator, the contributors, the maintainers, and all the users (past/present) to make this memorable.

My Story

I got an exposure to learn and use internet in my college days. In those period I look html as a very complex language. I wasn’t aware there exists editors which help you.

Around 2006, iirc Ganesh sir was the one who introduced me to PHP, and then with the guidance and help of Jose Antony.

College life ended in 2007. The search begins to find a job, and I managed to get one.

In 2009, I wrote a blog post A simple Blog using Zend framework 1.9 which got lots of attraction.

I wasn’t aware phpdeveloper.org and devzone.zend.com was changing my life and getting more closer to the people in the PHP community.

Some people praised, some disagreed which I came across a tool called phpunit.

In 2010, I attended my first conference osidays and met some of the awesome people like David Coallier, Fabien Potencier, Jacob Vrana, Dave Hall and many more.

Into the world of open-source

I would like to thank Paul M Jones the man behind auraphp.com for all the help, support and mentoring.

Started with stupid questions, and slowly as a small contributor.

Contributing to open-source gave me some confidence and it opened some help from the community.

Thank you Beau D Simensen, CalEvans.

Start a habit of learning, you will not regret joining NomadPHP it is awesome!.

Thank you all, and thanks for all the help and support you guys are showing.

Happy PhPing!

Zend Feed and Guzzle

You may have worked with Zend Feed as a standalone component. I don’t know whether you have integrated Zend framework Feed with Guzzle as Http Client.

This post is inspired by Matthew Weier O’Phinney, who have mentioned the same on github.

Our composer.json looks

1
2
3
4
5
6
7
8
9
10
11
12
{
    "require": {
        "guzzlehttp/guzzle": "~5.2",
        "zendframework/zend-feed": "~2.3",
        "zendframework/zend-servicemanager": "~2.3"
    },
    "autoload": {
        "psr-0": {
            "": "src/"
        }
    }
}

Zen\Feed\Reader\Reader have a method importRemoteFeed which accepts an instance of Zend\Feed\Reader\Http\ClientInterface.

The Zend\Feed\Reader\Http\ClientInterface have only one method get which returns Zend\Feed\Reader\Http\ResponseInterface.

So any http client that satisfy the interface will work. Let’s create them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
// src/GuzzleClient.php
use GuzzleHttp\Client;
use Zend\Feed\Reader\Http\ClientInterface;

class GuzzleClient implements ClientInterface
{
    protected $guzzle;

    public function __construct(Client $guzzle)
    {
        $this->guzzle = $guzzle;
    }

    public function get($uri)
    {
        $response  = $this->guzzle->get($uri);
        return new GuzzleResponse($response);
    }
}
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
<?php
// src/GuzzleResponse.php
use GuzzleHttp\Client;
use GuzzleHttp\Message\Response;
use Zend\Feed\Reader\Http\ClientInterface;
use Zend\Feed\Reader\Http\ResponseInterface;
use Zend\Feed\Reader\Reader;

class GuzzleResponse implements ResponseInterface
{
    protected $response;

    public function __construct(Response $response)
    {
        $this->response = $response;
    }

    public function getStatusCode()
    {
        return $this->response->getStatusCode();
    }

    public function getBody()
    {
        return (string) $this->response->getBody();
    }
}

Wiring up,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require __DIR__ . '/vendor/autoload.php';

use GuzzleHttp\Client;
use Zend\Feed\Reader\Reader as FeedReader;

$client = new GuzzleClient(new Client());
$feed = FeedReader::importRemoteFeed('http://feeds.feedburner.com/harikt/YKAJ', $client);

echo 'The feed contains ' . $feed->count() . ' entries.' . "\n\n";
foreach ($feed as $entry) {
    echo 'Title: ' . $entry->getTitle() . "\n";
    // echo 'Description: ' . $entry->getDescription() . "\n";
    echo 'URL: ' . $entry->getLink() . "\n\n";
}

You can run from the command line.

Once PSR-7 is accepted, and if both guzzle and zend framework (zf3) is built on top of it, we may not need to do the same.

Happy PhPing.