Planet-PHP

Syndicate content
People blogging about PHP
Updated: 1 hour 4 min ago

Getting Started with PHP Underscore

Wed, 16/04/2014 - 19:00

If you’ve ever used the Backbone framework for JavaScript, you’ll already be familiar with Underscore. Indeed, it’s become incredibly useful for JavaScript developers in general. But did you know that it’s been ported to PHP?

In this article I’ll take a look at Underscore, what it can do, and provide some examples of where it might be useful.

What is Underscore?

Underscore describes itself as a “utility belt library for JavaScript that provides a lot of the functional programming support that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects. It’s the tie to go along with jQuery’s tux, and Backbone.js’s suspenders.”

Most notably, Underscore provides a bunch of utilities for working with collections and arrays, some for working with objects, basic templating functionality and a number of other useful functions.

The functions which operate on collections and arrays can be particularly useful when dealing with JSON, which makes it great for handling responses from web services.

Continue reading %Getting Started with PHP Underscore%

Categories: Open Source, PHP Community

TDD: Checking the return value of a Stub

Wed, 16/04/2014 - 01:32

State verification is used to ensure that after a method is run, the returned value of the SUT is as expected. Of course, you may need to use Stubs on a test double or a real object to tell the object to return a value in response to a given message.

In Java, you declare a method’s return type in its method declaration, this means that the type of the return value must match the declared return type or otherwise you will get a compiler error. In PHP, for example, you dynamically type the return value within the body of the method. This means that PHP mocking libraries cannot check the type of the return value and provide guarantees about what is being verified.

This leads to the awkward situation where a refactoring may change the SUT behaviour and leave a stub broken but with passing tests. For example, consider the following:

Developer (A) creates 2 classes, Presenter and Collaborator:

class Presenter
{
    protected $collaborator;

    public function __construct(Collaborator $obj)
    {
        $this->collaborator = $obj;
    }

    public function doSomething()
    {
        $limit = 1;
        $stories = $this->collaborator->getStories($limit);
        // ...
        return $stories;
    }
}

class Collaborator
{
    public function getStories($limit)
    {
        return array();
    }
}

Then writes a test case:

class PresenterTest extends PHPUnit_Framework_TestCase
{
    // Behaviour verification
    public function testBehaviour()
    {
        $mock = $this->getMock('Collaborator', array('getStories'));
        $mock->expects($this->once())
            ->method('getStories')
            ->with(
                $this->logicalAnd(
                    $this->equalTo(1), $this->isType('integer')
                )
            );

        $presenter = new Presenter($mock);
        $presenter->doSomething();
    }

    // State verification
    public function testState()
    {
        $stub = $this->getMock('Collaborator', array('getStories'));
        $stub->expects($this->once())
            ->method('getStories')
            ->will($this->returnValue(array()));

        $presenter = new Presenter($stub);
        $data = $presenter->doSomething();

        $this->assertEquals(array(), $data);
    }
}

The Developer (A) uses a mock to verify the behaviour (a mockist practitioner) and a stub to verify the method worked correctly. The first test asserts that the expectation is met and the second one that the given condition is true. Finally, the Developer runs and watches all of the tests pass. Great!

The next day Developer (B) decides to makes some changes to the Collaborator class and return NULL if there are no stories:

class Collaborator
{
    public function getStories($limit)
    {
        $stories = array();
        if (count($stories) < 1) {
            return;
        }

        return $stories;
    }
}

The implementation of the method-under-test changed, it now returns a different data type, null instead of array. This means that our second test should fail, but it doesn’t. The test still asserts that the given condition is true, even though the return type is different. This is a problem. It means that our second test is unable to verify the correct state of the SUT (and its collaborator).

This is because most PHP mocking libraries are heavily influenced by Java (PHPUnit was originally a port of JUnit), and Java doesn’t have this problem. In PHP, the method’s return type is not a required elements of a method declaration, so developers can define it at run time and return whatever type they want.

The solution

You can use DocBlock annotations to make sure the data type of the returned value matches the one defined in the DocBlock. For this to work you need to set the return value using ReturnValue instead of PHPUnit_Framework_MockObject_Stub_Return. For example:

class PresenterTest extends PHPUnit_Framework_TestCase
{
    // State verification
    public function testState()
    {
        $stub = $this->getMock('Collaborator', array('getStories'));
        $stub->expects($this->once())
            ->method('getStories')
            ->will(new ReturnValue(array()));

        $presenter = new Presenter($stub);
        $data = $presenter->doSomething();

        $this->assertEquals(array(), $data);
    }
}

Now if you run the test it fails with the following error message:

PHPUnit_Framework_Exception: Invalid method declaration; return type required

The test also fails if the returned type doesn’t match the expected one defined in the DocBlock:

class Collaborator
{
    /**
     * @return int
     */
    public function getStories($limit)
    {
        // ...
    

Truncated by Planet PHP, read more at the original (another 1203 bytes)

Categories: Open Source, PHP Community

Phar: Browser caching for static files

Tue, 15/04/2014 - 17:06

Browsers are not able to cache static files delivered from PHP .phar archives, because Phar::webPhar() does not send out HTTP caching headers (Cache-Control, Expires).

The only way to intercept Phar::webPhar() before it delivers static CSS or JavaScript files is the $rewrites callback that may be passed as 5th parameter to webPhar().

A custom stub could look like this:

<?php
/**
 * Rewrite the HTTP request path to an internal file.
 * Adds expiration headers for CSS files.
 *
 * @param string $path Path from the browser, relative to the .phar
 *
 * @return string Internal path
 */
function rewritePath($path)
{
    if (substr($path, -4) == '.css') {
        header('Expires: ' . date('r', time() + 86400 * 7));
    }
    return $path;
}

Phar::webPhar(null, 'www/index.php', null, array(), 'rewritePath');
__HALT_COMPILER();
?>
Categories: Open Source, PHP Community

Implementing Multi-Language Support

Mon, 14/04/2014 - 19:00

Setting up a multilingual site may be a good way to attract new customers to your business or gain more participants in your project. Translating a simple site with a few static pages probably won’t probably be complicated, but more complex PHP web applications may require a lot of work when launching multiple language support. In this article I’ll present different types of content that need to be taken under consideration when internationalizing a site. Read on to get to know how to handle translating them into different languages.

Continue reading %Implementing Multi-Language Support%

Categories: Open Source, PHP Community

How To Modernize Your Legacy PHP Application

Mon, 14/04/2014 - 16:57

It is accomplished: “Modernizing Legacy Applications in PHP”, the book that will help you modernize your legacy PHP codebase, is complete. You can get it now it at https://leanpub.com/mlaphp.

Is your legacy PHP application composed of page scripts placed directly in the document root of the web server? Do your page scripts, along with any other classes and functions, combine the concerns of model, view, and controller into the same scope? Is the majority of the logical flow incorporated as include files and global functions rather than class methods?

If so, you already know that the wide use of global variables means that making a change in one place leads to unexpected consequences somewhere else. These and other factors make it overly difficult and expensive for you to add features and fix bugs. Working with your legacy application feels like dragging your feet through mud.

But it doesn’t have to be that way! Modernizing Legacy Applications in PHP will show you how to modernize your application by extracting and replacing its legacy artifacts. We will use a step-by-step approach, moving slowly and methodically, to improve your application from the ground up.

Moreover, we will keep your application running the whole time. Each completed step in the process will keep your codebase fully operational with higher quality. When we are done, you will be able to breeze through your code like the wind. Your code will be autoloaded, dependency-injected, unit-tested, layer-separated, and front-controlled.

From the Foreword by Adam Culp:

Developing with PHP has really matured in recent years, but it’s no secret that PHP’s low level of entry for beginners helped create some nasty codebases. Companies who built applications in the dark times simply can’t afford to put things on hold and rebuild a legacy application, especially with today’s fast paced economy and higher developer salaries. To stay competitive, companies must continually push developers for new features and to increase application stability. This creates a hostile environment for developers working with a poorly written legacy application. Modernizing a legacy application is a necessity, and must happen. Yet knowing how to create clean code and comprehending how to modernize a legacy application are two entirely different things.

But understanding how to use these refactoring processes on a legacy codebase is not straight forward, and sometimes impossible. The book you’re about to read bridges the gap, allowing developers to modernize a codebase so refactoring can be applied for continued enhancement.

Early reviews and testimonials from the feedback page:

  • “This is one of those books that PHP developers from all skill levels will be able to glean value from, and I know after just a single read-through that it will be an oft-referenced resource when I need to convert my old legacy-based procedural code into something cleaner, object-oriented, and testable.” (J. Michael Ward)

  • “As I followed the exercises in the book, my questions almost seemed to be anticipated and answered before the chapter was over. Structurally the book is very well paced. Chapters that I breezed over tended to be more useful than I thought they would be. I’ve been testing for years and I still picked up some useful tidbits about structuring my tests. Just having the step-by-step advice of an expert really made a difference.” (James Fuller)

  • “Reading through the book, it feels like you’re pair programming with the author. I’m at the keyboard, driving, and the author is navigating, telling me where to go and what to do next. Each step is practical, self-contained and moves you closer to the end goal you seek: maintainable code.” (Joel Clermont)

  • “This book helped me slay a 300k line of code giant and has allowed me to break out my shell. The refactored code has 15% code coverage for unit testing which grows every day.” (Chris Smith)

If you feel overwhelmed by a legacy application, “Modernizing Legacy Applications in PHP” is the book for you. Purchase it today and get started making your own life easier!

Categories: Open Source, PHP Community

Hawk Autentication considered harmful.

Sun, 13/04/2014 - 21:05

I was asked recently to add support for Hawk to sabre/http. It kinda seemed like a fun addition, but I'm building an increasing grudge, up to a point where I've nearly lost interest.

Missing documentation

The documentation is incomplete. The author points to his own javascript-based implementation as the reference, but 1700 lines of javascript code is simply not as easy to read as a plain-english reference.

In addition, the version of the protocol (currently 2.0) appears to be locked to the javascript library, and not the actual protocol.

This means that if bugs get fixed in the javascript source, the protocol version gets a bump. Leaving us no way to figure out something changed in the protocol, unless you're willing to go through the diffs for the source.

Uses the used hostname and port as part of the signed string

The both the hostname and the port are part of the signed string, unlike alternatives like AWS authentication and Digest.

The only case where this would actually be relevant, is if there's two endpoints with identical urls, and re-uses the same keys and secrets, and a identical request on the same url would be unwanted.

The drawback is that many service don't know what url was originally being used by a client, due to the use of reverse proxies.

Now we're forced to create a mechanism where the reverse proxy sends the original host header to the client.

Could have built upon Digest auth

Digest has a lot of good things going for it, and has a great deal of overlap in features.

Hawks strengths here are that it uses a stronger hash algorithm (hmac-sha256) and unlike Digest, it there's no need for pre-flighted requests to discover the service nonce. The latter is also the author's main concern with using Digest instead, as stated in the FAQ.

An answer to that would have been rather simple though. Any server could simply hardcode and document their server-side nonce, rendering the initial negotiation optional, but still possible.

Furthermore, digest can be easily extended with new algoritms.

What to use instead?

I'd highly recommend using simply either HTTP Digest, or if you're looking for something a little bit more fancy, use Amazon's authentication header.

Some benefits:

  • They are tried and tested for many years.
  • Not a moving target.
  • Documented.
  • Easier to implement.
  • Have lots of sample implementations.

That being said, I will probably still add support to an upcoming version of sabre/http.

Categories: Open Source, PHP Community

Tips & tricks for capifony deployment

Sun, 13/04/2014 - 14:30

In this blog post we want to share some tips & tricks for deploying with capifony which you might find useful as well.

Upload parameters files per server

Capifony already supports the upload of a parameters.yml file to servers during the deployment. This is done globally or for each stage separately, what is already documented as a cookbook. The parameters files don't need to be in the repository, they just have to be on the machine where you run the deployment.

In our project each server requires its own license key for an external service. For that reason we need a separate parameters.yml file for each server and can't use the stages to distinguish them. To solve this problem we created a capifony task which can upload a different parameters file to each server.

First, we define the separate files for the servers.

# app/config/deploy/prod.rb
server 'server1.example.com', :app, :web, :primary => true, :parameters_file => 'production1.yml'
server 'server2.example.com', :app, :web, :primary => true, :parameters_file => 'production2.yml'

The directory of the files is set as a variable.

# app/config/deploy.rb
set :parameters_dir, "app/config/parameters"

Now comes the main part, we create a new task for uploading the file.

# app/config/deploy.rb
task :upload_parameters, :except => { :parameters_file => nil } do
  servers = find_servers_for_task(current_task)
  servers.each do |server|
    parameters_file = server.options[:parameters_file]

    origin_file = parameters_dir + "/" + parameters_file if parameters_dir && parameters_file
    if origin_file && File.exists?(origin_file)
      ext = File.extname(parameters_file)
      relative_path = "app/config/parameters" + ext

      if shared_files && shared_files.include?(relative_path)
        destination_file = shared_path + "/" + relative_path
      else
        destination_file = latest_release + "/" + relative_path
      end

      run "#{try_sudo} mkdir -p #{File.dirname(destination_file)}", :hosts => server

      capifony_pretty_print "--> Uploading " + parameters_file + " to " + server.host
      top.upload(origin_file, destination_file, { :hosts => server })
      capifony_puts_ok
    end
  end
end

This task is very similar to the one of the cookbook. We use the :except option to run this task only for servers which have the parameters_file property defined.

Then you can run the task.

  • For a shared parameters file: after 'deploy:setup', 'upload_parameters'
  • For an unshared parameters file: before 'deploy:share_childs', 'upload_parameters'
Generate parameters files per server

Instead of uploading the parameter files they can also be generated during the deployment. This can be used if you don't want to copy around files and just want to import another parameters file inside the parameters.yml. For this a slightly different task is needed.

# app/config/deploy.rb
task :generate_parameters, :except => { :parameters_file => nil } do
  servers = find_servers_for_task(current_task)
  servers.each do |server|
    parameters_file = server.options[:parameters_file]
    ext = File.extname(parameters_file)
    relative_path = "app/config/parameters" + ext

    if shared_files && shared_files.include?(relative_path)
      destination_file = shared_path + "/" + relative_path
    else
      destination_file = latest_release + "/" + relative_path
    end

    run "#{try_sudo} mkdir -p #{File.dirname(destination_file)}", :hosts => server

    capifony_pretty_print "--> Generating parameters file on " + server.host
    run "#{try_sudo} echo -e \"imports:\\n    - { resource: parameters/#{parameters_file} }\" >#{destination_file}", :hosts => server
    capifony_puts_ok
  end
end

The rest remains the same as for uploading the parameters files.

With this solution, the parameters.yml files have to be committed to the repository. We decided to do this because it makes the maintenance easier, e.g. we see the changes directly in our merge/pull requests.

Update schema with multiple entity managers

If you need an entity manager for updating the schema, which is not the default one, you can set a variable. All doctrine tasks in capifony will use this variable.

set :doctrine_em, 'custom_em'

But if you have multiple entity managers and want to update the schema for all of them, a little more work is required.

# Default entity manager
after 'deploy:create_symlink', 'symfony:doctrine:schema:update'

# Custom entity manager 1
after 'deploy:create

Truncated by Planet PHP, read more at the original (another 1015 bytes)

Categories: Open Source, PHP Community

Can Great Apps Be Written in PHP – An Interview Series

Sat, 12/04/2014 - 20:00

I read an old post, circa 2010, on the MailChimp blog a little while ago, about their experience using PHP.

It struck a chord with me, because the sentiments they shared I’ve felt myself, and heard echoed many times over the years. What are these sentiments, you may ask?

They’re the ones which infer that PHP, despite all its successes, really isn’t a true programming language. They’re the ones which intimate that, no matter how good you are, no matter what you’ve achieved, if you’re a PHP programmer, well, you’re really not a true developer, yet.

They’re the ones which suggest, or is that presuppose, that you should really become one of the cool kids developing in Ruby, Python, or Go; basically anything other than PHP. After all, what can you really do with PHP, right?

Continue reading %Can Great Apps Be Written in PHP – An Interview Series%

Categories: Open Source, PHP Community

Getting Started with Assetic

Fri, 11/04/2014 - 19:00

There was a time when asset management meant little more than inserting a tag or two and a couple of <script> tags into your html.

Nowadays, though, that approach just won’t cut it. There’s performance, for one thing. Assets are a significant performance drain both in terms of file size and the number of HTTP requests - optimizing both has become an essential part of the development process. This has been exacerbated by the proliferation of mobile devices.

Also, as client-side applications have become more and more sophisticated, managing dependencies amongst scripts and libraries has become increasingly complex.

Furthermore, technologies such as Less, Compass and Coffeescript require assets to be compiled, adding yet another step to the process of managing assets.

In this article I’m going to look at a PHP package called Assetic which helps manage, compile and optimize assets such as scripts, stylesheets and images.

Continue reading %Getting Started with Assetic%

Categories: Open Source, PHP Community

PHP 5.6.0beta1 released

Fri, 11/04/2014 - 02:00
The PHP development team announces the immediate availability of PHP 5.6.0beta1. This release adds new features and fixes bugs and marks the feature freeze for the PHP 5.6.0 release. All users of PHP are encouraged to test this version carefully, and report any bugs in the bug tracking system. THIS IS A DEVELOPMENT PREVIEW - DO NOT USE IT IN PRODUCTION! PHP 5.6.0beta1 comes with a number of new features, including: A new method called fread() to the SplFileObject classA new static method called createFromMutable() to the DateTimeImmutable classA new function called hash_equals()Support for marks to the PCRE extensionSupport for asynchronous connections and queries to the Pgsql extensionFor more information about the new features you can check out the work-in-progress documentation or you can read the full list of changes in the NEWS file contained in the release archive. For source downloads of PHP 5.6.0beta1 please visit the download page. Windows binaries can be found on windows.php.net/qa/. Our second beta should show up on the 24th of April. Thank you for helping us make PHP better.
Categories: Open Source, PHP Community

PHP mysqlnd memory optimizations: from 49MB to 2MB

Thu, 10/04/2014 - 20:58

Inspired by Antony, Andrey has implemented a memory optimization for the PHP mysqlnd library. Depending on your usage pattern and the actual query, memory used for result sets is less and free’d earlier to be reused by the PHP engine. In other cases, the optimization will consume about the same or even more memory. The additional choice is currently available with mysqli only.

From the network line into your script

Many wheels start spinning when mysqli_query() is called. All the PHP MySQL APIs/extensions (mysqli, PDO_MySQL, mysql) use a client library that handles the networking details and provides a C API to the C extensions. Any recent PHP will default to use the mysqlnd library. The library speaks the MySQL Client Server protocol and handles the communication with the MySQL server. The actions behind a users mysqli_query() are sketched below.

The memory story begins in the C world when mysqlnd fetches query results from MySQL. It ends with passing those results to the PHP.

PHP script mysqli extension/API mysqlnd library MySQL *.php *.c mysqli_query()     PHP_FUNCTION(mysqli_query)     MYSQLND_METHOD(query)     simple_command(COM_QUERY)     COM_QUERY   store_result()     return result set  

The new memory optimization is for buffered result sets as you get them from mysqli_query() or a sequence of mysqli_real_query(), mysqli_store_result(). With a buffered result set, a client fetches all query results into a local buffer as soon as they become available from MySQL. In most cases, this is the desired behaviour. The network line with MySQL becomes ready for a new command quickly. And, the hard to scale servers is offloaded from the duty to keep all results in memory until a potentially slow client has fetched and released them.

The result buffering happens first at the C level inside the mysqlnd library. The buffer holds zvals. A zval is internal presentation structure for a plain PHP variable. Hence, think of the mysqlnd result buffer as a list of anonymous PHP variables.

PHP script mysqli extension/API mysqlnd library MySQL *.php *.c …   store_result()     Buffer with zvals (MYSQLND_PACKET_ROW),
think: PHP variables   The default: reference and copy-on-write

When results are to be fetched from the mysqlnd internal buffers to a PHP script, the default behaviour of mysqlnd is to reference the internal buffer from the PHP script. When code like $rows = mysqli_fetch_all($res) is executed, first $rows gets created. Then, mysqlnd makes $rows reference the mysqlnd internal result buffers. MySQL results are not copied initially. Result set data is kept only once in memory.

PHP script mysqli extension/API mysqlnd library MySQL *.php *.c …   store_result()     Buffer with zvals ("/>

Truncated by Planet PHP, read more at the original (another 16365 bytes)

Categories: Open Source, PHP Community

How to Speed Up Your App’s API Consumption

Thu, 10/04/2014 - 18:00

In the process of creating a PHP application you may come to a point when keeping it isolated from remote resources or services may become a barrier in its development. To move along with the project you may employ different API services to fetch remote data, connect with user accounts on other websites or transform resources shared by your application.

The ProgrammableWeb website states that there are currently more than ten thousand APIs available all over the web so you’d probably find a lot of services that can be used to extend your PHP app’s functionality. But using APIs in an incorrect way can quickly lead to performance issues and lengthen the execution time of your script. If you’re looking for a way to avoid it, consider implementing some of the solutions described in the article.

Continue reading %How to Speed Up Your App’s API Consumption%

Categories: Open Source, PHP Community

OpenSSL Serious Security Bug: Does it Affect Your PHP sites?

Thu, 10/04/2014 - 11:39
By Manuel Lemos
Just a few days ago it was publicly announced a serious security bug called Heartbleed that affects secure sites based on the OpenSSL library.

Read this article to learn more about this security problem, how to test if your Web server or SSH server is vulnerable, how it may affect your PHP sites, what you should do to fix the problem.
Categories: Open Source, PHP Community

Introduction to JadePHP

Wed, 09/04/2014 - 19:32

There are dozens of templating engines out there, with options such as Smarty, Twig (used in the upcoming version of Drupal) and Blade (the default for Laravel) among the best known - as well as vanilla PHP, of course. Stepping away from PHP specifically, eRuby / ERB and Haml for Ruby / Ruby on Rails, and Javascript has scores of popular choices including Mustache, Handlebars, Hogan and EJS. Some have subtly different syntax, some more markedly so.

One which differs quite significantly from most is Jade, an engine usually associated with Javascript applications - it’s supported out-of-the-box by Express for Node.js, for example. It’s Jade I’m going to look at in this article; or more specifically the PHP port JadePHP.

Haml and Jade

It would be remiss to talk about Jade without mentioning Haml, from which Jade takes its inspiration - and indeed there are several libraries for using Haml with PHP. Jade shares its overall philosophy, which is to make templating “beautiful” and use what the authors describe as templating “haiku”. Whatever that actually means, there’s no denying Haml and Jade do share some characteristics which make them fundamentally different to most templating languages.

What’s the Difference?

Most templating engines involve writing the target markup and “injecting” it with placeholders and / or basic logic - a superset, in a sense. Jade still has placeholders and logic, but also provides a shorthand for writing XML-like elements. Generally that means html, although you can also use it for things like RSS as well as XML itself.

In fact if you wanted to, you could just use Jade as a shorthand for html without taking advantage of its more “traditional” templating features.

How to use the Repository

Rather frustratingly, the code is not currently available via Composer - although it should be a simple enough task to package it up, if anyone has an hour or two. You can get it to to work, however, by cloning the repository and include‘ing or require‘ing the included autoload.php.dist (the Github repository includes Symfony’s UniversalClassLoader).

Here’s an example, adapted from the one in the project’s README, which assumes that the repository has been downloaded into a directory called jade:

require('./jade/autoload.php.dist');

use Everzet\Jade\Dumper\PHPDumper,
        Everzet\Jade\Visitor\AutotagsVisitor,
        Everzet\Jade\Filter\JavaScriptFilter,
        Everzet\Jade\Filter\CDATAFilter,
        Everzet\Jade\Filter\PHPFilter,
        Everzet\Jade\Filter\CSSFilter,
        Everzet\Jade\Parser,
        Everzet\Jade\Lexer\Lexer,
        Everzet\Jade\Jade;

$dumper = new PHPDumper();
$dumper->registerVisitor('tag', new AutotagsVisitor());
$dumper->registerFilter('javascript', new JavaScriptFilter());
$dumper->registerFilter('cdata', new CDATAFilter());
$dumper->registerFilter('php', new PHPFilter());
$dumper->registerFilter('style', new CSSFilter());

// Initialize parser & Jade
$parser = new Parser(new Lexer());
$jade   = new Jade($parser, $dumper);

$template = __DIR__ . '/template.jade';

// Parse a template (both string & file containers)
echo $jade->render($template);

This will compile the file template.jade and echo its contents.

Where you actually use this depends on your workflow, whether you’re using a framework, and so on. You could, perhaps, use a service such as Watchman, Guard or Resource Watcher to watch the filesystem for changes to your Jade templates, and compile them at the appropriate time during the development process.

Continue reading %Introduction to JadePHP%

Categories: Open Source, PHP Community

Cursors and the Aggregation Framework

Wed, 09/04/2014 - 10:29
Cursors and the Aggregation Framework

With MongoDB 2.6 released, the PHP driver for MongoDB has also seen many updates to support the features in the new MongoDB release. In this series of articles, I will illustrate some of those.

In this article, I will introduce command cursors and demonstrate how they can be applied to aggregations. I previously wrote about the Aggregation Framework last year, but since then it has received a lot of updates and improvements. One of those improvements relates to how the Aggregation Framework (A/F) returns results. Before MongoDB 2.6, the A/F could only return one document, with all the results stored under the results key:

<?php $m = new MongoClient;
$c = $m-?>demo->cities;

$pipeline = [
     [ '$group' => [
          '_id' => '$country_code',
          'timezones' => [ '$addToSet' => '$timezone' ]
     ] ],
     [ '$sort' => [ '_id' => 1 ] ],
];

$r = $c->aggregate( $pipeline );
var_dump( $r['result'] );
?>

This code would output something like:

array(242) {
  [0] =>
  array(2) {
     '_id' => string(2) "AD"
     'timezones' => array(1) { [0] => string(14) "Europe/Andorra" }
  }
  [1] =>
  array(2) {
     '_id' => string(2) "AE"
     'timezones' => array(1) { [0] => string(10) "Asia/Dubai" }
  }
  [2] =>
  array(2) {
     '_id' => string(2) "AF"
     'timezones' => array(1) { [0] => string(10) "Asia/Kabul" }
  }
  …

MongoCollection::aggregate() is implemented under the hood as a database command. The method in the PHP driver merely wraps this, but you can also call A/F through the MongoDB::command() method:

<?php $m = new MongoClient;
$d = $m-?>demo;

$pipeline = [
     [ '$group' => [
          '_id' => '$country_code',
          'timezones' => [ '$addToSet' => '$timezone' ]
     ] ],
     [ '$sort' => [ '_id' => 1 ] ],
];

$r = $d->command( [
     'aggregate' => 'cities',
     'pipeline' => $pipeline,
] );
var_dump( $r['result'] );
?>

Because a database command only returns one document, the result is limited to a maximum of 16MB. This is not a problem for my example, but it can can certainly be a limiting factor for other A/F queries.

MongoDB 2.6 adds support for returning a cursor for an aggregation command. With the raw command interface, you simply add the extra cursor element:

$r = $d->command( [
     'aggregate' => 'cities',
     'pipeline' => $pipeline,
     'cursor' => [ 'batchSize' => 1 ],
] );
var_dump( $r );

Instead of a document with all results inline, you get a cursor definition back:

array(2) {
  'cursor' =>
  array(3) {
     'id' => class MongoInt64#5 (1) {
          public $value => string(12) "392201189815"
     }
     'ns' => string(11) "demo.cities"
     'firstBatch' => array(1) {
       [0] =>
       array(2) {
          '_id' => string(2) "AD"
          'timezones' => array(1) { [0] => string(14) "Europe/Andorra" }
       }
     }
  }
  'ok' => double(1)
}

The cursor definition contains the cursor ID (in id), the namespace (ns), and whether the command succeeded (in ok). The definition also a portion of the results. The number of items in firstBatch is configured by the value given to batchSize in the command.

To create a cursor that you can iterate over in PHP, you need to convert this cursor definition to a MongoCommandCursor object. You can do that with the MongoCommandCursor::createFromDocument() factory method. This factory method takes three arguments: the MongoClient object ($m in my example), the connection hash, and the cursor definition that was returned. The hash is required so that we can fetch new results from the same connection that executed the original command.

To obtain the connection hash, we need to include a by-ref variable as the third argument to MongoCollection::command():

<?php $m = new MongoClient;
$d = $m-?>demo;

$pipeline = [
     [ '$group' => [
          '_id' => '$country_code',
          'timezones' => [ '$addToSet' => '$timezone' ]
     ] ],
     [ '$sort' => [ '_id' => 1 ] ],
];

$r = $d->command(
     [
          'aggregate' 

Truncated by Planet PHP, read more at the original (another 2607 bytes)

Categories: Open Source, PHP Community

My HHVM talk slides from yesterday's Webtuesday

Wed, 09/04/2014 - 08:39

Yesterday I gave a talk about HHVM and Hack at the monthly webtuesday here in Zurich. The slides can be found here

It was a great evening, thanks to Netcetera for hosting it, thanks to Joel and the webtuesday crew for organizing it and also thanks to Johannes for chiming in when we talked about PHP internals.

If you have any question abut HHVM or related things, just ask in the comments, contact me on twitter or meet me personally, if you're nearby (aka in Switzerland).

Categories: Open Source, PHP Community

Three Great New Speakers!

Wed, 09/04/2014 - 02:24

This summer’s Crafting Code Tour is coming together, and we have confirmed three speakers to come along to various locations!

We are proud to announce that Adam Culp will be joining the tour for stops in Tampa Bay, Atlanta and Nashville. Adam will be speaking on Refactoring 101, offering up his wisdom on how to refactor legacy applications.

Paul M. Jones will be joining the tour for Dallas, Austin, Oklahoma and Kansas City, speaking about code modernization, a great talk that he’s given at numerous conferences in the past year.

And Larry Garfield will join the tour for Minneapolis, Milwaukee and Cincinnati. He’ll be doing a reprise of his SunshinePHP keynote, so if you missed it, don’t miss it on these stops!

Plus, we are pleased to announce that Mandrill will be providing pizza for all the tour stops.

Categories: Open Source, PHP Community

Finally! 1.1.0-RC1

Tue, 08/04/2014 - 06:00

Once we released 1.0, we did not sit idle. Instead we immediately began work on improving the CMF. In fact there was such a continuous stream of good ideas and things that felt like a must have, that we let ourselves slip quite far from our defined release process. Or lets say we had every intention of aliging ourselves with the Symfony2 core release cycle by releasing within 1-2 months of core which would have meant a 1.1 release in January. Instead it tooks us 6 months to get to RC1, which on the upside is inline with what we intended for future releases.

As we feared, it turns out that we had to do a few minor BC breaks which we tried to document as much as possible in the CHANGELOG.md files in the respective packages. We also have updated the documentation already with lots of details on the new features we added. Unfortunately due to limitation in the current symfony.com website, we cannot provide a rendered version just yet. So for now please review the dev branch. Hopefully we will eventually also be able to provide multiple versions of the CMF documentation just like it is possible for the core documentation.

Let me briefly highlight some of the key improvements that are coming with 1.1:

  • A lot of effort was spend in making the CMF more resilent towards edge cases and given better more helpful error messages.
  • Support for newer version of Jackalope and PHPCR ODM, that bring lots of bug fixes, speed improvements, and better debugging and profiling (including Symfony2 debug toolbar support).
  • The routing system was made even more flexible, meaning there is even less code to write when implementing a new storage backend. As a result much less code is now needed in SimpleCmsBundle for routing.
  • The menu system has seen several tweaks, most noteably it is now possible to configure a fetch depth, which can give drastic performance improvements for deeply nested menu structures.
  • A new Bundle was added for handling SEO meta data.
  • A totally reworked Standard Edition that is based on the core Standard Edition to make it easier to understand what is necessary to add to a Symfony2 application to integrate the CMF.

So what is still left until we can go stable? For now we want to give at least 2 weeks from now to allow the community to do some testing and to focus on bringing all the documentation up to date. So expect a stable release at the earliest towards the end of April at the latest sometime in May. Other than this the main areas where we might still see some changes are:

To get an idea of what is needed to update to 1.1, have a look at the PR to update this website to the new version. Also note that the CMF sandbox has also already been upgraded to 1.1.

We are also very happy with the growing eco-system around PHPCR. Most noteably there is now a PHPCR shell to interact with a PHPCR repository as well as finally a PHPCR GUI that supports reading and writing via a web interface!

Categories: Open Source, PHP Community

Getting Started with PHP Extension Development via Zephir

Mon, 07/04/2014 - 19:00

Thien Tran Duy explains how we can get started with PHP Extension development through Zephir, the new language and direct competition to Hack and HHVM from the Phalcon team

Continue reading %Getting Started with PHP Extension Development via Zephir%

Categories: Open Source, PHP Community

Composer-Assisted Two-Stage Configuration in Aura

Mon, 07/04/2014 - 18:06

After a long period of consideration, research, and experiment, we have found a non-static solution for programmatic configuration through a DI container. It is part of a two-stage configuration process, implemented through a ContainerBuilder.

The two stages are “define” and “modify”:

  • In the “define” stage, the Config object defines constructor params, setter method values, and services. This is the equivalent of the previous single-stage Solar and Aura v1 configuration system.

  • The ContainerBuilder then locks the Container so that its definitions cannot be changed, and then begins the “modify” stage. In this second stage, we retrieve service objects from the Container and modify them programmatically.

So now, instead of each Aura package carrying a pair of define and modify includes in a subdirectory named for the config mode, we have a single class file for each config mode. The class file is in a subnamespace _Config under the package namespace. Here are two examples, one from the Aura.Web_Kernel package, and one from the Aura.Web_Project package.

Because they are classes, you can call other methods as needed, subclass or inherit, use traits, create instance properties and local variables for configuration logic, and so on. You could even call include in the methods if you wanted, keeping the class as a scaffold for much larger configuration files. This gives great flexibility to the confguration system.

To make sure the Aura project installation can find all the package config files, we use the {"extra": {"aura": { ... } } } elements of the composer.json in each package to provide a mapping from the config mode to the config class.

Read the whole article at Composer-Assisted Two-Stage Configuration.

Categories: Open Source, PHP Community