HWI OAuth Bundle – Custom Registration Form

I’ve been busy integrating a new application with third party / social authentication providers, specifically Tumblr, but this applies to pretty much any service as best I can tell.

In this post I want to cover how, and why, you can override the default implementation HWIOAuthBundle’s connect  configuration to specify your own account_connector.

I am using HWIOAuthBundle a little differently from how it is primarily designed to work.

HWIOAuthBundle is all about offering users of your site the ability to log in using their trusted third party / social media credentials rather than having to create yet another user account to use your site. You see this functionality a lot on the web these days, and it’s no surprise that Symfony has a bundle to deal with this.

Configuration of HWIOAuthBundle isn’t that hard, but the documentation doesn’t hand hold you as much as you might find with other bundle documentation. If you find yourself stuck or confused, the project issue tracker on Github is a great place to start digging.

Why Use A Custom account_connector ?

There are likely a good few reasons to do this.

In my case, I don’t want users to be able to register on the site with social media credentials. That in itself comes with its own set of headaches.

Users of my site must create an account the old fashioned way. This is handled through the brilliant FOSUserBundle.

Then, once authenticated, the user can connect  their account to one or more of the various social platforms – Twitter, Facebook, Google+ and what have you.

The curve ball in my situation comes from the above, but also that a User account can have many sub accounts. Think of it as in an agency looking after multiple client accounts, all from one login. None of the client accounts should be aware of the other client accounts under management, but the ‘master’ User account needs to seamlessly switch between them all.

The problem: when connecting to a new social account, how do you determine which client account to connect to which social account?

Out of the box, HWIOAuthBundle will return the ‘master’ User account object, and the social media site’s response object. From there, there is no simple way to determine the ‘active’ client account.

I didn’t want to start managing application state through a Session, as I could envisage a situation where a User may try and connect multiple accounts in multiple tabs, and end up with the wrong social media account assigned to the wrong client account. Messy.

Sending the relevant data via the URL seems like an easy solution to this problem. Perhaps though, not the right one.

Having given this a bit of thought, the next step seems to be having an input of type choice  on the connect page.

There is no bundle documentation (that I could find) to actually do this in their expected way (as in FOSUserBundle docs), though thankfully there is a handy Reference Configuration.

This is the relevant section:

# app/config.yml
hwi_oauth:
    # if you want to use 'connect' and do not use the FOSUB integration, configure these separately
    connect: ~
#        confirmation: true # should show confirmation page or not
#        registration_form_handler: my_registration_form_handler
#        registration_form: my_registration_form
#        account_connector: my_link_provider # can be the same as your user provider

As you can see, by default, we go with the built in / provided implementations.

We can override any of the default Services by specifying other Symfony Services, but exactly how these Services are configured is not explicitly described.

But what about overriding the template? Why isn’t that listed?

Well, that’s pretty common in Symfony, but it’s definitely a valid question.

Not one to turn down a challenge, I decided to do a little code diving, and see if I couldn’t come up with a DIY solution.

My Implementation

My idea is to have a modified connection form.

The connection form is displayed midway through the ‘connection’ process.

Remember, the User has already logged in to my application via their FOSUserBundle credentials.

Then, they can choose to ‘connect’ with a configured Social Media service – let’s say Tumblr, for sake of this example.

They click ‘Connect to Tumblr’, and are redirected to some URL on Twitter whereby they authenticate with their Twitter credentials (or, if already logged in, are simply shown a pop-up / modal to confirm they agree to this authorisation), and are then returned to my app with some params on the URL – their OAuth token info.

I want to save this profile info, but I need to ensure it is mapped to the correct client account under the currently logged in / locally authenticated User.

At this point, the User would have been redirected back from Tumblr to our ‘Connect’ form. Without any modification or styling, that form is going to look something like this :

hwio-oauth-connect-form

That form lives at :

/vendor/hwi/oauth-bundle/HWI/Bundle/OAuthBundle/Resources/views/Connect/connect_confirm.html.twig

We can tell it’s definitely this form by editing that template in the bundle.

I’m doing this for demo purposes, and it’s great for confirming what you already guess to be the right file, but don’t make direct edits to the bundle files (any of them), as all your changes will (potentially) be lost the next time you do a composer update on that particular bundle.

the-hwio-aiuth-connect-template-opened-in-phpstorm

Outputs:

hwio-oauth-bundle-slightly-modified-connect-formMy plan is to therefore add a checkbox on that page to allow the User to connect the given social media account to one or more of their customer / sub accounts.

We will need to handle some contingency stuff here, like that new User who doesn’t check any of the boxes and clicks ‘continue’ anyway. We don’t want this to cause an error on the back end, even though we would ideally validate this before hand on the front-end.

At this point I added in a way to stop the process before any persistence. I did this by defining my own CustomerConnector class and then turning this into a Symfony Service. This is where I would put all my implementation details:

<?php

// /src/AppBundle/OAuth/Connect/CustomerConnector.php

namespace AppBundle\OAuth\Connect;

use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class CustomerConnector extends BaseClass
{
    public function connect(UserInterface $user, UserResponseInterface $response)
    {
        dump($user);
        dump($response);
        exit('connect');
    }
}
# /app/config/services.yml
services:
    customer_connector:
        class: AppBundle\OAuth\Connect\CustomerConnector
        arguments: [@fos_user.user_manager, {}]
# app/config/config.yml
hwi_oauth:
    firewall_name: main
    connect:
        account_connector: customer_connector

This would let me go through the same process over and over, but die before anything further happens, showing me all the good stuff we would need to think about persistence.

One thing at a time.

Adding in the checkboxes

The next major hurdle is where to start with adding in our own Form implementation.

I’m not spotting a hugely easy way to achieve what we are trying to do without hacking a little.

The issue we have is that HWIOAuthBundle expects to be dealing with a User throughout the lifecycle of the connection process.

There is no easy way to override this – that I can see – and I don’t want to implement the 34 required methods of Symfony’s UserInterface on my Customer entities.

However, as it happens, the ConnectController doesn’t seem to care what we put on our form.

Good news, we have ourselves an entry point.

This means we can add extra stuff (basic HTML form elements) to the /vendor/hwi/oauth-bundle/HWI/Bundle/OAuthBundle/Resources/views/Connect/connect_confirm.html.twig  template.

But, rather than directly edit the template in the bundle – which we have already decided is a bad idea – we are going to use a little Symfony bundle inheritence magic to override the template with our own at:

/app/Resources/HWIOAuthBundle/views/Connect/connect_confirm.html.twig

This is a pretty cool Symfony feature, so if you haven’t used it before, check out the official documentation. It can come in handy for times like this.

Our template is going to replicate all the existing layout / functionality, but add in a little raw HTML to further our own goals:

{% extends 'HWIOAuthBundle::layout.html.twig' %}

{% block hwi_oauth_content %}
    <h3>{{ 'header.connecting' | trans({}, 'HWIOAuthBundle')}}</h3>
    <div class="row">
        <div class="span6">
            <p>{{ 'connect.confirm.text' | trans({'%service%': service | trans({}, 'HWIOAuthBundle'), '%name%': userInformation.realName}, 'HWIOAuthBundle') }}</p>
            <p>
            <form action="{{ path('hwi_oauth_connect_service', {'service': service, 'key': key}) }}" {{ form_enctype(form) }} method="POST" class="fos_user_registration_register">
                {{ form_widget(form) }}
                <input type="checkbox" name="accounts[]" value="value1"> value1
                <input type="checkbox" name="accounts[]" value="value2"> value2
                <div>
                    <button type="submit" class="btn btn-primary">{{ 'connect.confirm.submit' | trans({}, 'HWIOAuthBundle') }}</button>
                    <a href="{{ path('hwi_oauth_connect') }}" class="btn">{{ 'connect.confirm.cancel' | trans({}, 'HWIOAuthBundle') }}</a>
                </div>
            </form>
            </p>
        </div>
        <div class="span6">
            {% if userInformation.profilePicture is defined and userInformation.profilePicture is not empty %}
                <img src="{{ userInformation.profilePicture }}" />
            {% endif %}
        </div>
    </div>
{% endblock hwi_oauth_content %}

We’ve added in the raw HTML above, using two simple input elements to fake our data.

The basics are important – we have set the name=”accounts[]”  property on both, so that the responses are grouped together and we get an array result.

However, we still have a problem.

Even though we have added the checkboxes, and they will be being properly appended to our Symfony Request , the ConnectController  is not passing the Request object to our CustomerConnector :

// /vendor/hwi/oauth-bundle/HWI/Bundle/OAuthBundle/Controller/ConnectController.php#L209
$this->container->get('hwi_oauth.account.connector')->connect($currentUser, $userInformation);

I see this a lot, but remember, you can’t just ask for a Request object inside a Symfony Service in the same way you can in a Symfony Controller.

We do control this service. Whilst it may not directly obvious, this is actually referring to our account_connector.

We can’t change the method signature (connect(UserInterface $user, UserResponseInterface $response) ), and even if we could, that would mean we would also have to duplicate the entire ConnectController::connectServiceAction() , which we really don’t want to do.

Instead, we can use another bit of functionality available to us in Symfony: Setter Injection.

We can use setter injection to pass in Symfony’s RequestStack and then access the extra data direct from the Request object that way.

With all this configured, our CustomerConnector now looks like this:

<?php

namespace AppBundle\OAuth\Connect;

use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\User\UserInterface;

class CustomerConnector extends BaseClass
{
    /**
     * @var RequestStack
     */
    private $requestStack;

    public function injectRequestStack(RequestStack $requestStack)
    {
        $this->requestStack = $requestStack;
    }

    public function connect(UserInterface $user, UserResponseInterface $response)
    {
        dump($user);
        dump($response);
        dump($this->requestStack->getMasterRequest());
        exit('connect');
    }
}
# services.yml

services:
    customer_connector:
        class: AppBundle\OAuth\Connect\CustomerConnector
        arguments: [@fos_user.user_manager, {}]
        calls:
            - [ "injectRequestStack", [@request_stack]]

Which looks like this on screen:

result-of-connect

We need to do a little modification to the template. The default translation text is incorrect, and we need to pass in the real data, but those are both quick Twig template tweaks.

We will likely want to add some Bootstrap specific (other front end design frameworks are available ;)) CSS to our form template also.

After that, we can move on to the logic that actually handles associating the oAuthToken data with our chosen accounts.

Review

I’m not 100% happy with this implementation.

That I’ve not had to overwrite any controller action is good.

But I now have to keep my template up to date with whatever implementation changes come in HWIOAuthBundle. Likely this won’t change hugely, but almost inevitably, at some point in the future, this will break in a hard to debug manner.

Also, I’m relying on the HWIOAuthBundle controller behaving as I expect it.

This feels quite shaky. Covering the code sufficiently with tests will be crucial, but the tests themselves will be slow, difficult to write, and brittle.

This approach is pragmatic. I am happy that this is the best solution to the problem given the time frame, and the fact that I am working on a personal project / MVP.

If you know of a better way to implement this, please do leave a comment.

node-gyp rebuild Error on Ubuntu 15.04 with Node 4.x.x

I’m going to start with the tl;dr version:

if you are experiencing this issue, and you have recently installed Node 4.x.x, then this is likely your issue.

Solutions?

Find another package, or use an older version of node for now if you absolutely must use that package.

The Longer Version

I had been trying to install “webkid-react-starterkit@0.3.1” on my Ubuntu dev box for ages last night, and spent a wasted 25 minutes again on it tonight.

The error was staring at me right in the face honestly:

gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/usr/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:270:23)
gyp ERR! stack     at emitTwo (events.js:87:13)
gyp ERR! stack     at ChildProcess.emit (events.js:172:7)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:200:12)
gyp ERR! System Linux 3.19.0-30-generic
gyp ERR! command "/usr/bin/nodejs" "/usr/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/chris/Development/php/dunglas-api-test/react-example/node_modules/jest-cli/node_modules/jsdom/node_modules/contextify
gyp ERR! node -v v4.2.1
gyp ERR! node-gyp -v v3.0.3
gyp ERR! not ok 
npm ERR! Linux 3.19.0-30-generic
npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "install"
npm ERR! node v4.2.1
npm ERR! npm  v2.14.7
npm ERR! code ELIFECYCLE

npm ERR! contextify@0.1.14 install: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the contextify@0.1.14 install script 'node-gyp rebuild'.
npm ERR! This is most likely a problem with the contextify package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node-gyp rebuild
npm ERR! You can get their info via:
npm ERR!     npm owner ls contextify
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /home/chris/Development/php/dunglas-api-test/react-example/npm-debug.log

It’s likely not as easy to see here, but on my terminal output, it’s colour coded and it’s rather glaringly obvious:

npm ERR! Failed at the contextify@0.1.14 install script 'node-gyp rebuild'.

I went round many houses.

From trying to install contextify globally, to completely reinstalling node, to even getting down to specifying the exact version of the v8 profile I wanted (npm install v8-profiler@3.6.2-1 ).

Nothing worked.

Anyway, it turns out it’s incompatible with this version of node all along.

NodeJS 4.0.0 only tagged as stable on 8th September 2015, and here I am running 4.2.1.

Buckle in, it’s going to be a wild ride.

How I “fixed” Segmentation Fault in Codeception 2.1.3

I hit on a bug when upgrading from Codeception 1.8.x to Codeception 2.1.3.

I entirely skipped the 2.0.* branch of Codeception, not through any other reason than 1.8.x was working fine for me.

During a recent site update, I decided it would be a good time to update the Codeception tests suite to the latest release.

Unfortunately, the upgrade did not go smoothly.

crvuser@crv-dev:/var/www/codereview.dev$ php vendor/codeception/codeception/codecept run acceptance SignUpCest.php --debug
Codeception PHP Testing Framework v2.1.3
Powered by PHPUnit 4.8.12 by Sebastian Bergmann and contributors.
Segmentation fault

I constantly hit this issue, but only with the Acceptance test suite. The unit tests passed absolutely fine.

I even got very specific with my versions inside composer.json:

    "require-dev": {
        "phpunit/phpunit": "4.8.12",
        "codeception/codeception": "2.1.3",
        "facebook/webdriver": "1.0.2"
    },

(some other stuff removed for brevity)

But still I hit the Segmentation Fault error every single time I ran the acceptance tests.

My Fix

Alas, my fix isn’t great. But it has worked.

I figured with the major version changing, chances are something went pear shaped internally.

My test suite isn’t hugely customised, but it did have a bit of extra stuff sprinkled in here and there. Something in there may very well have caused it.

Anyway, after much debugging (difficult as it happens), I gave up and did the following:

  1. Renamed the tests/ dir to tests_bak
  2. Renamed codeception.yml dir to codeception_bak.yml
  3. Ran php vendor/codeception/codeception/codecept bootstrap

And then, piece by piece, copied all my tests and config back across to the respective files.

Don’t copy / overwrite.

Instead, copy the relevant bits from the files – especially the configs. Things have changed.

Also, I found it easiest to re-run the test suite for every individual file I copied over. One by one at first, but as I copied in more of the directories, I ended up getting quicker and quicker.

Not the most elegant of solutions, but the test suite is back to working.

Interested in learning more about Codeception? I have a full course on the site.

Ahh, but it returns…

I wanted to add something extra to this.

I hit this issue again in Codeception 2.1.3.

From what I can discern, the size of your test database (e.g. dump.sql ) seems to have some impact on causing the Segmentation Fault issue.

I found that by removing data from my tables – generally less than 50 rows per table – the Segmentation Fault issue went away.

Frustrating that I don’t know the exact cause of it, but if in doubt, strip it out.

PHPNW15 Conference Review

phpnw15-logoThose of you on the mailing list, or following along on Twitter will know that over the weekend of the 3rd & 4th October, I was out and about at PHP North West 2015.

Thankfully, this year we had a bit of a heatwave so being up and about early on both the Saturday and Sunday was not the icy frost-fest that last year entailed.

I booked my ticket as an early blind bird this year – on the day they were announced if I recall correctly – and I was still ticket #49. That should give you an idea how popular this conference is.

And there is the un-con to get too, the line-up for which isn’t announced until the day.

A quick note on the venue – super easy to find, a £2 all-day car park (each day) right next door, and plenty of space for however many delegates there were (300+? 425!). Same venue as last year, hope it’s the same next year.

Keynote – Stealing People Lessons from Artificial Intelligence

Saturday kicked off to a jam packed room with the keynote from Meri Williams.

I was left feeling really happy after this talk.

There was a slide on Motivation. I didn’t get a shot of it unfortunately, so here’s a screencap from Meri’s website:

meri-williams-phpnw15-motivation

I answered YES to each of these questions for both Code Review Videos, and for my client work. Awesome.

There was also this slide:

meri williams clue skills matrix

Finding people in the top right has enabled me to grow both personally and to help grow Code Review this year. For that I am extremely grateful.

What To Expect from PHP7

After the coffee break, I returned to the main hall to catch Lorna Jane’s talk on PHP7.

I can’t photo, but:

lorna jane - php7 is coming and it is fabulous

After listening to Lorna’s talk, I too am convinced.

I must confess to having not yet had a chance to play with PHP7. I have heard it is lovely and fast, but in truth, I always found PHP5 to be pretty fast compared to doing the same things manually… especially if you remove all the layers of ‘stuff’ that we pile on top of it.

The speed improvements do sound nice, but the syntax improvements are the bigger news for me. Particularly the null coalesce operator. A crazy name for a very useful concept. Also, Googling for this has to be easier than the first time I Googled for what turned out to be the ternary operator (‘question mark colon php’?)

A quick code sample:

// $a is not set
$b = 16;

echo $a ?? 2; // outputs 2
echo $a ?? $b ?? 7; // outputs 16

(Full credit – Lorna Jane)

Lorna has a write up on this very topic so be sure to check the credit above from the full article.

A First Look at ZF3

This was a very enjoyable and informative talk by Rob Allen, who I had previously managed to watch on YouTube regarding PSR7 (audio ain’t great unfortunately, so watch with decent headphones).

I am really interested in what the future holds for Zend Framework.

The early part of this talk was encouraging – ZF3 has got it’s act together with regards to project maintainability. Like it’s competitors, ZF3 is now much more modular and (properly) made up of composable components managed with Composer 😉

rob allen a first look at zf3

If you are a mailing list subscriber you won’t be so surprised to hear I was very much enthralled by the section on Middleware.

rob allen zf3 middleware

I genuinely think this is going to be biggest thing in PHP – except for PHP7 – this year. Ok, well… there’s not much left of 2015, but 2016 is definitely definitely going to be a big year for Middleware in PHP.

rob allen zf3 middleware detail

I also really liked what I heard about how ZF3 will enable the construction of “specific builds” – a ZF3 build for web apps (MVC), a ZF3 build for APIs, etc. That sounds awesome.

Middleware sounds like it’s going to be huge for ZF, and they are even porting integration into ZF 1.13.

Lunch Break

The food was really nice. However, hot and spicy chilli chicken with no napkins?

Come on now.

Hitting the Uncon

The uncon unfortunately didn’t have a time sheet outside the door. Instead, attendees were asked to head over to the Joind.in page to figure out what was on when. These talks were mingled in to the main track talks which was a bit messy and harder to follow than it need have been.

Please put out a proper written list in the future if possible.

The PHP Framework Engine (PPI)

The first talk I caught was by Paul Dragoonis, introducing a PHP Framework that’s not a framework – PPI.

Now, PPI is a bit of a tricky name to compete for as it’s a very spammy term and a thoroughly dodgy industry. Paul’s framework that’s not a framework had had the name before PPI became a thing, so he was sticking with it.

From what I gathered, Paul and the PPI Framework are pushing boundaries – perhaps two to three years ahead of where the mainstream frameworks are.

His idea is that you can combine all the best bits of each framework – using Aura for Routing, Symfony and Doctrine for entity management, and Laravel for templating.

I can’t say I fully understood how this all worked together, but the concept is certainly fascinating.

How to Migrate Anything with DDD

I really liked Gabriel’s presentation. He was speaking about Baleen Migrations, and managed to get a tech demo in there (that all worked flawlessly).

Gabriel Somoza How to Migrate Anything with DDD

There’s only so much that can be covered within 25 minutes, and unfortunately the architectural side of the project (the DDD part of the talk title) wasn’t covered.

As a tool however, this looks really, really nice.

Also, after having Googled for Baleen, it turns out that Baleen is a type of Whale – hence the name for a migrations library. Nice touch.

Driving Design through Examples

Ciaran McNulty’s talk on BDD and DDD with Behat and PHPSpec was perhaps the most personally relevant talk I saw all day.

The big win for me – I have been doing DDD and BDD right!

This is great as I’ve done an absolute ton of reading on BDD – how to best write specs, how to improve the specs by asking questions, and really drilling down into the detail of a problem by asking questions.

However, I still learned an absolute ton. Ciaran and the rest of the Inviqa team are – as far as I am aware – the foremost experts on this subject in the UK, and any opportunity to learn from them and improve my own processes and development is always extremely welcome.

Unfortunately, the pictures I took of this talk are amongst the worst of them all – which is saying something as the rest are pretty bad to begin with.

cairan mcnulty ddd and bdd with phpspec and behat

If you squint hard enough, what you can see here is named constructors in action. Very cool.

Ciaran’s proper slides are here.

Thoroughly enjoyed this talk!

Hello, PSR-7

A small confession. I have listened to (almost) every episode of That Podcast, so stole in extra early to this one to say hello in person to Beau Simensen. Amazingly, Dave then walked in and I got to meet him too.

And then, because I was on the front row with all the A-Listers, I got to meet Rob Allen and Lorna Jane – speakers from earlier in the day, for those not paying attention – so this was all kinds of awesome.

Everyone was super nice and that was a great way to (almost) end the day.

Beau’s talk was very interesting. Being dedicated to PSR7, and with a longer time slot than I had seen of Rob Allen’s PSR7 talk mentioned earlier (the YouTube link), I got a better / more in-depth understanding of the topic.

I came out of this talk convinced that PHP is, on some levels at least, going to be able to offer somewhat similar functionalities to something like Express JS in the not too distant future.

Hometime

That was it for me for the first day. I didn’t stay around for the closing remarks of day 1 as I had to be home to take over family duties.

In my absence, I somehow managed to win a book:

Agile Project Management and Scrum

I’m not sure who I won that from, or why, but thank you all the same.

Sunday

I arrived on the Sunday morning in good time and found the halls largely empty. Yikes. However, I need not have worried as it seemed everyone had skipped the coffee and pastries areas and headed straight for the three conference rooms.

Getting things done with ElasticSearch

I learned a ton in this talk.

I’ve used Solr for a previous project and have been wanting to properly dive into Elasticsearch for ages now.

The main thing stopping me from doing so is the seemingly over large depth of knowledge required just to get started.

elastic search in action talk

After listening to Thijs Feryn break down the overarching concepts, I did feel a little more at ease.

There’s so much cool stuff in there. Stuff that can really add value to a wide range of projects:

elastic search stuff i didnt know

Elasticsearch – or search in general – has to be the next thing to add at Code Review. It shames me that it isn’t there yet.

Ways To Measure Your ORM’s Cost

Stuart Herbert is clearly not only just a very smart and knowledgeable guy, but you can tell he has been there and earned his stripes first hand.

All the problems and solutions discussed in this talk were aimed at growing, through to larger businesses. It’s nice to have tons of traffic, but that brings with it a new set of problems.

Suddenly your site is slow. Is the solution to add more servers? Possibly, but that brings with it a new set of headaches. Those early short cuts you took with straight-outta-the-manual Doctrine :

$products = $repository->findByPrice(19.99);

What’s that really doing behind the scenes now that you have 40 other entities all hanging off it?

Those sorts of questions.

I have done some videos on this topic as it’s really not that much harder to do it right first time.

I knew from the first few slides that I was going to enjoy this one:

ways to measure an orm cost

This chart was really eye opening. Pretty obvious really when it’s pointed out to you.

Your laptop’s hard drive is nothing like your servers. You definitely need to be measuring the real world.

why dev machines lie

Great talk, with tons of take away points and a really open presenting style that brought out some interesting and relevant audience participation. 

Closing Keynote: Developers are just like humans

I ended up in the overflow room for this. That’s a nice thing in a way – proves that Sunday was very popular, just as last year.

closing keynote with skoop

I found this one a nice way to end the conference.

developers are just like humans skoop

 

Swaggles

I would have been happy just getting the Behat stickers.

The Sky bag came with a ton of freebies. Thanks, though the chocolate bar tasted like cooking chocolate… yikes. Feel free to feed that back to Rupert.

That little grey and green thing in the top centre? It’s a phone stand. No one seemed to know. I had to ask. If a conference full of devs don’t have a clue, I’d say someone at Merch HQ needs to go on a UX course.

swag from phpnw15

And so that was that.

Now I just need a weekend to recover.

How to fix libsass bindings not found

Arghhhh!

I feel like Node eats my nights for fun. Tonight I updated to Node v4.1.1 – brew upgrade node for those on OSX.

But then immediately I hit upon this:

[21:43:32] Error: `libsass` bindings not found in /Users/myusername/Development/my-project/node_modules/gulp-sass/node_modules/node-sass/vendor/darwin-x64-46/binding.node. Try reinstalling `node-sass`?
    at Object.sass.getBinaryPath (/Users/myusername/Development/my-project/node_modules/gulp-sass/node_modules/node-sass/lib/extensions.js:150:11)
    at Object.<anonymous> (/Users/myusername/Development/my-project/node_modules/gulp-sass/node_modules/node-sass/lib/index.js:16:36)
    at Module._compile (module.js:434:26)
    at Object.Module._extensions..js (module.js:452:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at Object.<anonymous> (/Users/myusername/Development/my-projectd/node_modules/gulp-sass/index.js:163:21)
    at Module._compile (module.js:434:26)

Sigh.

I then tried to brew upgrade libsass which threw back this:

Error: libsass 3.2.5 already installed

Anyway, after much back and forth, it turns out the solution was quite simple.

From your project directory:

rm -rf node_modules
npm install

🙂 Yes, whilst not exactly identifying the root cause, sometimes the blunt and brutal does the job better and faster than anything else.

Now, where was I? Oh yes… scratching my head over the next problem.