SpiffyJr's Blogaroo

Happenings of the man known as SpiffyJr

  • Home
  • About
    • Inspiration
    • Resume
  • Projects
    • Blitzaroo
    • phpRaider
    • Zend Calendar
  • Docs
    • Blitzaroo API
    • SpiffyCalendar Docs
    • SpiffyDb Docs
  • Downloads
  • Technologies
    • Doctrine ORM
    • Dojo
    • PHP
    • Zend Framework
  • Other
    • License
Twitter RSS

Super sexy URLs with ZF and the joy of controller plugins!

Posted on April 1, 2011 by SpiffyJr
No comments

I’m in a bit of a hurry so this one will be short and sweet. I wanted to be able to use sexy uris (/your-homepage-rocks) instead of the lame-o /module/controller/action/id/# URIs. I also wanted error handling to work properly if they tried to access a page that didn’t exist so, what to do!? Build a controller plugin of course – ain’t (English police get me) they sexy?

// My\Controller\Plugin\Page.php

// I'm a huge-mongous fan of namespaces
namespace My\Controller\Plugin;
use Zend_Controller_Plugin_Abstract, Zend_Controller_Front;

class Page extends Zend_Controller_Plugin_Abstract
{
        // predispatch so that we can take over before routing kicks in
	public function preDispatch($request)
	{
		$front = \Zend_Controller_Front::getInstance();
		$dispatch = $front->getDispatcher();

		// normally when something isn't dispatchable an exception is thrown and we're whisked away to the errorController
		if (!$dispatch->isDispatchable($request)) {
			$bootstrap = $front->getParam('bootstrap');
			$website = $bootstrap->getResource('website');

			// did we find a page?
			$page = \My\Service::getRepository('Website\Page')->findOneBy(
				array('website' => $website->getId(), 'slug' => $request->getControllerName()));

			if ($page) {
				// page exists, reroute by setting controller, action, and an additional "page" param
				$request->setModuleName('default')
					->setControllerName('page')
					->setActionName('index')
					->setParam('page', $page);
			}
		}
	}
}
// application\controllers\PageController

class PageController extends Zend_Controller_Action
{
	// before dispatching, verify a few page properties
	public function preDispatch()
	{
		// grab the page from earlier - if it doesn't exist it will be handled with an exception
		$page = $this->_request->page;
		if (!$page || !$page->getPublished()) {
			// page must exist and be published
			throw new \My\Exception\NotFound();
		} elseif (!$page->isAllowed('read')) {
			// user must have read permission
			throw new \My\Exception\AccessForbidden();
		}

		// send it to the view to take care of
		$this->view->page = $page;
	}

	public function indexAction()
	{}
}

And, it works! You can handle the case where a page doesn’t exist as usual with the errorController. If a page does exist then everything is routed over to the pageController to display as normal. The only downside to this sexy magic is the additional query when an invalid request is dispatched. Fortunately, the overhead on that is minimal.

GD Star Rating
loading...
Categories: Zend Framework

Formatting your API to work with dojox.data.JsonRestStore (#dojo)

Posted on March 30, 2011 by SpiffyJr
No comments

Greetings! Long time no post, I know. I’ve been busy with PetWise and Blitzaroo as well as the occasional game of Heroes of Newerth and/or WoW arenas. This little post will attempt to help those working with JsonRestStore (JRS) when their API doesn’t output exactly what JRS is expecting. What we’re going to be doing is extending dojox.data.JsonRestStore and creating our own store in its place while overriding the _processResults() method.

The first thing you will want to do is register a Dojo module path so that Dojo knows exactly where to find your custom store. In my example, I’m going to be using Zend Framework so in my application.ini file I simply include a line like resources.dojo.modulePaths.blitz = “/js/dojo/blitz”. We’ll also want to be sure that we require the appropriate class when working with our new store. You can do this globally in the application.ini by adding resources.dojo.requireModules[] = “blitz.data.JsonRestStore” or by adding it to whatever page the store will be used in.

Next, you’ll need to declare the class by creating the file. In my example, I create a file called JsonRestStore.js in /js/dojo/blitz/data.

// /js/dojo/blitz/data/JsonRestStore.js

dojo.provide("blitz.data.JsonRestStore");
dojo.require("dojox.data.JsonRestStore");

// declare the store extending from JsonRestStore
dojo.declare("blitz.data.JsonRestStore", dojox.data.JsonRestStore, {
        // process results takes the results from getQuery and turns them into something the store can handle
	_processResults:function(results, deferred) {
		// custom format for blitz api
		results = results.result; // this simple line causes JsonRestStore to work with my own API implementation
		// index the results
		var count = results.length;
		// if we don't know the length, and it is partial result, we will guess that it is twice as big, that will work for most widgets
		return {totalCount:deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: results};
	}
});

Here’s a dump of my profiles API inside of Blitzaroo to show why this works. Notice that all the data comes from the result key which is why I have the line results = results.result. This allows me to include extra information about the request whenever the API is hit.

{
  -request: {
    uri: "/api/profiles"
    format: "json"
    action: "list"
  }
  -result: [
    -{
      id: 1
      userId: 1
      name: "Igatchew"
      private: false
      -created: {
        date: "2011-03-25 15:50:20"
        timezone_type: 3
        timezone: "America/Chicago"
      }
    -updated: {
        date: "2011-03-25 15:50:22"
        timezone_type: 3
        timezone: "America/Chicago"
      }
    }
   -{
      id: 2
      userId: 1
      name: "Snaggins"
      private: true
      -created: {
        date: "2011-03-25 20:32:34"
        timezone_type: 3
        timezone: "America/Chicago"
      }
      -updated: {
        date: "2011-03-25 20:32:36"
        timezone_type: 3
        timezone: "America/Chicago"
      }
    }
  ]
}

Hope that’s helpful!

GD Star Rating
loading...
Categories: Zend Framework

Zend Framework 1.11 + Doctrine 2 – Let’s play nice, part 2

Posted on December 17, 2010 by SpiffyJr
2 comments

Hello! It’s been a while since my last post but I ran into a rather frustrating issue yesterday and didn’t want anyone else to have to repeat it. According to the official Doctrine 2 docs you should try to flush a limited number of times per request.

Note Do not invoke flush after every change to an entity or every single invocation of persist/remove/merge/… This is an anti-pattern and unnecessarily reduces the performance of your application. Instead, form units of work that operate on your objects and call flush when you are done. While serving a single HTTP request there should be usually no need for invoking flush more than 0-2 times.

Source

While debating how to go about this I remembered controller plugins and how handy they can be for controlling very stages of the request. For anyone who hasn’t read it I’d suggest checking out the Front Controller Plugins in Zend Framework DevZone post by Matthew O’Phinney. A quick summary of hooks can be found below:

  • routeStartup(): prior to routing the request
  • routeShutdown(): after routing the request
  • dispatchLoopStartup(): prior to entering the dispatch loop
  • preDispatch(): prior to dispatching an individual action
  • postDispatch(): after dispatching an individual action
  • dispatchLoopShutdown(): after completing the dispatch loop

The majority of the work from the EntityManager will come from the controller action’s so the hook we’re interested in is the postDispatch() hook. A few minutes later and we have our plugin.

// File located at My/Controller/Plugin/EntityManager.php

namespace My\Controller\Plugin;
use Zend_Controller_Plugin_Abstract, Zend_Controller_Front;

class EntityManager extends Zend_Controller_Plugin_Abstract
{

	/**
	 * Flush the EntityManager.
	 *
	 * (non-PHPdoc)
	 * @see Zend_Controller_Plugin_Abstract::dispatchLoopShutdown()
	 */
	public function postDispatch($request)
	{
		$bootstrap = Zend_Controller_Front::getInstance()->getParam('bootstrap');
		$em = $bootstrap->getResource('EntityManager');
		$em->flush();
	}
}
// APPLICATION_PATH/configs/application.ini

resources.frontController.plugins[] = "My\Controller\Plugin\EntityManager"

Once that’s setup your ready to go with one small caveat.  If you’re a fan of $this->_helper->redirector() in the controller’s you going to have an issue because the redirector forces an exit after redirecting the response. In order for this to work properly you will need to change those to $this->_helper->redirector->setGotoSimple(); which doesn’t force an exit. You do not need to change all the redirector’s. Only ones where a flush is required. For example,

use Services\Game, Services\Profile;

class EditProfileController extends Zend_Controller_Action
{
	public $gameService;
	public $profileService;

	public function preDispatch()
	{
		$this->profileService = new Profile();

		$profile = $this->profileService->findProfile($this->_request->id);
		if (!$profile || !$profile->getGame() || !$this->profileService->isAllowed('update')) {
      // postDispatch isn't needed so we save a cycle or two and just call redirector per normal
			return $this->_helper->redirector('index', 'profiles');
		}

		$form = $profile->getProfileForm(
			array(
				'game' => $profile->getGame(),
				'method' => 'post',
				'action' => '/edit-profile/process?id=' . $this->_request->id));

		$form->populateFromModel($profile);

		$this->view->profileForm = $form;
		$this->view->profileModel = $profile;
		$this->view->gameModel = $profile->getGame();
	}

	public function indexAction()
	{}

	public function processAction()
	{
		$request = $this->getRequest();
		if (!$request->isPost()) {
      // postDispatch isn't needed so we save a cycle or two and just call redirector per normal
			return $this->_helper->redirector('index', 'profiles');
		}

		if (!$this->profileService->updateProfile($request->getPost())) {
			return $this->render('index');
		}

     // The update profile call was successful so we need to make sure the postDispatch() gets ran.
		$this->_helper->redirector->setGotoSimple('index', 'profiles');
	}
}

Welp, that about sums it up! I hope I saved someone else the hassle I went through trying to understand why Doctrine 2 wasn’t flushing (quick! someone jiggle the handle). Cheers.

GD Star Rating
loading...
Categories: Random
Page 2 of 1312345...10...»Last »
  • Recent Posts

    • Keep your Git fork clean
    • Get started with Zend Framework 2 modules!
    • More Doctrine 2 and Zend Framework integration goodies!
    • Super sexy URLs with ZF and the joy of controller plugins!
    • Formatting your API to work with dojox.data.JsonRestStore (#dojo)
  • Categories

    • Other
      • Random
    • Projects
      • Blitzaroo
      • phpRaider
      • SpiffyDb
      • View Helpers
      • Zend Calendar
    • SpiffyJr
    • Technologies
      • Dojo
      • PHP
      • Zend Framework
  • Tag Cloud

      Ajax Algorithm api Blitzaroo Blog BSD licenses calendar Cascading Style Sheets CSS database Data Formats Dojo Dojo Toolkit event Framework game Google HTML HTML element JavaScript JQuery json Languages mapper Marketing mmorpg model php Programming Projects Scripts Source code Style sheet Style Sheets Twitter Website zend Zend Framework
  • Archives

    • December 2011
    • November 2011
    • July 2011
    • April 2011
    • March 2011
    • December 2010
    • November 2010
    • October 2010
    • March 2010
    • February 2010
    • November 2009
    • October 2009
    • September 2009
© SpiffyJr's Blogaroo. Proudly Powered by WordPress | Nest Theme by YChong