Zend Framework 2 - Subqueries (Subselect) and Table Gateway

This one can be a bit of a pain, and I had a few folks ask me how to do this, thought I'd share here and pass a link around.  The question takes many shapes!

How can I perform a subquery in ZF2?

How do I properly escape a subquery in my Table Gateway?

I'm trying to echo my query to debug it and am getting warning messages from ZF2?

It's not terribly difficult, but the docs are a bit piecemeal on the net.  I've tried to find links on StackOverflow to help as well, but haven't found any good ones.  Here goes - hope it helps!

 

The function in your AbstractTableGateway will look like such, pay attention to fetchAllWithVotes:


namespace Application\Model\Table;

use Zend\Db\Adapter\Adapter;
use Zend\Db\Adapter\AdapterAwareInterface;
use Zend\Db\Sql\Expression;
use Zend\Db\Sql\Select;
use Zend\Db\TableGateway\AbstractTableGateway;

class SongsTable extends AbstractTableGateway implements AdapterAwareInterface
{
    protected $table = 'songs';

    public function setDbAdapter( Adapter $adapter)
    {
        $this->adapter = $adapter;
    }

    public function fetchAllWithVotes( $user_id )
    {
        $adapter   = $this->getAdapter();
        $resultset = $this->select( function( Select $select ) use ( $user_id, $adapter ) {

            $sub1   = new Select( 'votes' );
            $sub1->columns( array( 'total' => new Expression('COUNT(*)') ) )
                    ->where( array( 'id' => new Expression( 'song_id' ) ) );

            $sub2   = new Select( 'votes' );
            $sub2->columns( array( 'total' => new Expression('COUNT(*)') ) )
                    ->where( array( 'id' => new Expression( 'song_id' ) ) )
                        ->where( array( 'user_id' => $user_id ) );

            $select->columns(
                array(
                    'id',
                    'title',
                    'ytlink',
                    'total_votes' => new \Zend\Db\Sql\Expression( '?', array( $sub1 ) ),
                    'your_votes' => new \Zend\Db\Sql\Expression( '?', array( $sub2 ) ),
                )
            );

            var_dump( $select->getSqlString( $adapter->getPlatform() ) );

        });

        return $resultset->toArray();
    }
}

Pretty self-explanatory - all the guts are there!  Hope this helps :)

VirtualBox: Mounting Shared Folders on Ubuntu Server 13

Want to mount VirtualBox folders on Ubuntu under an OSX 10.8 host?  Differences between aptitude packages and the VirtualBox Guest Additions ISO, compounded to  "security fixes" in recent versions of VirtualBox that disable symlinks can be a pain.  Read below, it's actually quite simple.  

Starting, I assume that you have VirtualBox 4.3.4+ installed, and have loaded up your Ubuntu Server VM -- but don't spin it up yet.

Configuring Your Shared Folder

Inside VirtualBox, head to your VM's Settings panel and visit the Shared Folders tab.  Click the Add (+) icon on the right hand side and specify the folder on your host (OSX) that'll get shared in your guest (Ubuntu).  Check Auto-mount & Make Permanent, click Ok. [I noticed a strange thing, "Make Permanent" isn't always visible.  Click "OK" to save & close, then double-click your shared folder entry to make it reappear in the modal dialog.] 

Make a mental note your share's name; you'll need it in the steps that follow.  Mine is webroot in the screenshot affixed.

Screenshot of shared folder config panel

Screenshot of shared folder config panel

 

Enabling Symlinks (optional)

If you need Symlinks in your guest, run this command before you start your VM.  This gotcha was a pain.  Switch out "webroot" for your share's name, and VM_NAME for the actual name you give your VM.

VBoxManage setextradata VM_NAME VBoxInternal2/SharedFoldersEnableSymlinksCreate/webroot 1

 

Start & Prep Your VM

Start your VM, log in via SSH, and then:

  1. insert the Guest Additions CD image (Devices > Insert Guest Additions CD image in the menu)
  2. mount the CD with: sudo mount /dev/cdrom /media/cdrom
  3. before we can install what's on the CD, we need to build a few requirements:  sudo apt-get install -y dkms build-essential linux-headers-generic linux-headers-$(uname -r)
  4. now we can use what's on the CD, install with: sudo /media/cdrom/VBoxLinuxAdditions.run

Because you are on Ubuntu Server, it'll crap out at the last step where it tries to install X11 dependencies - but don't worry about it - it'll still work(Could not find the X.Org or XFree86 Window System.)

Reboot your VM at this point, then shell back in.

 

Mount Your Folders, Like Magic

I wanted to mount something that'd get used by nginx; so I mounted them under the www-data uid and gid (33).  I also added www-data to vboxsf.

sudo adduser www-data vboxsf

Mount with this command thereafter (recall your share name noted earlier):

sudo mount -t vboxsf -o uid=33,gid=33 webroot /var/www/html/

You can discover a user's  ID with the id command.

AWS Kinesis, PHP, CURL and Signature V4

Well - I got my hands on a limited preview of AWS Kinesis!  It promises to  be one of the most insane realtime data-grepping vacuums ever built.  Remains to write, I was very excited to tackle it this afternoon (got my welcome email last night).

After I plowed through the morning's chores, I made a coffee, read the docs -- and then Googled around to see if any low-level libraries were available; I knew inside that I was in for the library build given our needs, but I was hopeful to avoid building the signature.  Quickly found a piece I'd met before, the AWS SDK for PHP and its Signature V4 class. This thing is rigged to be configurable, and despite my intuition, I loaded it up and ran a few tests.  It was far too slow.  That old adage about performance vs. configurability always holds doesn't it. The abstractions and options might be great for multipurpose usage, but my Kinesis usage is scheduled to fire several thousand times a second - the overhead on the SDK is simply too great.

Back to the drawing board then, I built a test from scratch that used cURL - with success (after some hacking at it admittedly, the API error messages are a bit cryptic at times).  I thought others could benefit from this, and so I post it here!  

https://gist.github.com/Saeven/7832090

(I put a Gist up for now, sorry to make you jump through hoops)

I'll follow up with our real world experience on the Kinesis

Capturing auth events with ZfcUser

Had a hell of a time trying to find how to tap into ZfcUser's auth event (the registration events are really well documented, but this one...).  Figured I'd write about it while the glue-it-back-hair-glue gently massaged onto my scalp dries.