Added by Geoffrey Tran, last edited by Geoffrey Tran on Dec 22, 2007  (view change)

Labels

 
(None)

http://www.spotsec.com/blog Zend Framework Blogs

Feed Link

SpotSec Networks Blog entries tagged 'Zend Framework'
(SpotSec Networks Blog entries tagged 'Zend Framework')
Extending Zend_Form for custom forms tip

Many people have created custom forms by extending Zend_Form and overriding __construct like so:

class MyForm extends Zend_Form
{
    public __construct($options = null)
    {
        parent::__construct($options);
        // [...] Form code
    }
}

However, without looking at the api, you'd never see you could do it like this which is slightly cleaner:

class MyForm extends Zend_Form
{
    public init()
    {
        // [...] Form code
    }
}
DIRECTORY_SEPARATOR is not needed!

Overview

One of PHP's misconceptions is that in order to write portable code, the DIRECTORY_SEPARATOR constant is needed for all folder paths. An example of this is in require's.

require_once(MY_PATH . DIRECTORY_SEPARATOR . 'foo' . DIRECTORY_SEPARATOR . 'my.php');

The alternative

PHP is smart enough to handle all paths that use a forward slash '/' on all platforms (that means windows). Using a forward slash instead of the directory separator constant where possible will make your code more readable. Zend Framework uses this method on all of its require's.

/**
* @see Zend_Controller_Front
*/
require_once('Zend/Controller/Front.php');

After running a few tests and speaking to several people, it seems that it is perfectly fine to take this alternative. For most code, as long as you are using the forward slash '/' not the windows back slash '\' portability is guaranteed.

Why have a constant? 

The constant is particularly useful because paths given by php use the native system's directory separator. The constant is particularly useful if you need to do some path mangling or exploding etc..

That's all 

While I am just giving out my opinion here as I find that the DIRECTORY_SEPARATOR use can go out of hand, it is up to you to decide. Please provide feedback on what you think ;).

References

  • http://old.alanhogan.com/tips/php/directory-separator-not-necessary
  • http://us2.php.net/manual/en/ref.filesystem.php#73954 
Zend Framework 1.5 PR - Development Moves On!

Whoo!

With the release of Zend Framework 1.5PR, the feel of the framework moving forward starts to come back. Some things to look for in this release are Zend_Form, Zend_Db and Zend_Layout as they play an important role in the framework. This release should be completely backwards compatible for those who wanted to know. (I mean to say that 1.5 should be backwards compatiable with the 1.0.x seriers).

Listed below are some additional features posted by Wil Sinclair :

  • Zend_Auth_Adapter_Ldap
  • Zend_Build/Zend_Console
  • Zend_Controller additional action helpers
    • ContextSwitch and AjaxContext
    • Json
    • AutoComplete
  • Zend_Form
  • Zend_InfoCard
  • Zend_Layout
  • Zend_OpenId
  • Zend_Search_Lucene improvements:
    • wildcard search
    • date range search
    • fuzzy search
    • Lucene 2.1 index file format support
  • Zend_View enhancements:
    • actions
    • partials
    • placeholders
  • Zend_Pdf UTF8 support
  • New Zend_Service consumables (final list TBD)
  • A whole lotta bug fixes and documentation improvements

Note for Naneau : It's been 4 months since you've posted... :(

Extending Zend_Controller_Action and keeping init()

Overview

There have been quite a lot of requests about how to extend Zend_Controller_Action in #zftalk lately, so I figured I'd post something to reference to. So what's so hard about extending Zend_Controller_Action? Nothing, it is just that for some odd reason people resort to overriding init() or calling parent::init() (I assume your too lazy to open up Action.php to grab the __construct() params ;) ). Basically the benefit of doing it the correct way allows you to use init() in your extended controller without calling parent::*. Yes, I am that lazy...

Library Directory Structure

One of the other things people have asked about when creating custom classes for ZF that are reusable is where to put them. While they can be put anywhere and there is not a specified convention, I usually put them in my own namespace in a directory layout similar to Zend Framework. It is also simpler because extended classes mirror the ZF structure which make it easier for other developers to find.

  • libraries/
    • Zend/
      • Controller/
        • Action.php
    • SpotSec/
      • Controller/
        • Action.php

The Code

require_once('Zend/Controller/Action.php');
// Stored in libraries/[Zend, SpotSec]/Controller/Action.php just for those who are wondering
abstract class SpotSec_Controller_Action extends Zend_Controller_Action
{
/**
* Class constructor
*
* The request and response objects should be registered with the
* controller, as should be any additional optional arguments; these will be
* available via {@link getRequest()}, {@link getResponse()}, and
* {@link getInvokeArgs()}, respectively.
*
* When overriding the constructor, please consider this usage as a best
* practice and ensure that each is registered appropriately; the easiest
* way to do so is to simply call parent::__construct($request, $response,
* $invokeArgs).
*
* After the request, response, and invokeArgs are set, the
* {@link $_helper helper broker} is initialized.
*
* Finally, {@link init()} is called as the final action of
* instantiation, and may be safely overridden to perform initialization
* tasks; as a general rule, override {@link init()} instead of the
* constructor to customize an action controller's instantiation.
*
* @param Zend_Controller_Request_Abstract $request
* @param Zend_Controller_Response_Abstract $response
* @param array $invokeArgs Any additional invocation arguments
* @return void
*/
public function __construct(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response, array $invokeArgs = array())
{
// Your stuff here to run before init()
// Note: $this->getRequest, $this->getResponse() and $this->getInvokeArgs() (also action helpers)
// are not available until after the construct is run, but you can use $request, $response and $invokeArgs.
parent::__construct($request, $response, $invokeArgs);
// Your stuff below here... to run after init(), but before self::preDispatch()
}
}

Done!

Simple eh? and all you had to really do is open up Action.php to read or the API docs to find out how (but I assumed you googled.... cheater).

Zend Framework BaseUrl View Helper

Overview


  • What is the BaseUrl?

    • The purpose of the base url is to provide the path to the document root of the ZF application.

  • Why should I use it?
    • Makes your applications more portable (You can place your app within subdirs without modifications to the existing paths)
    • Paths to files such as images, scripts, styles will not work.

  • Where is it located?
    • In the request object [$this->getRequest()->getBaseUrl();]



It appears that the common method people are using to access the
baseUrl in the view is by assigning from the controller through init(),
or even in the bootstrap. However, the use of a baseUrl view helper or
the placeholder helper (Note: as of this writing, it has not been
released)
just seems to make code slightly nicer. This way we eliminate
the use of a "global view variable" by encapsulation. While there are several ways to acomplish this, I will explain the placeholder and the baseUrl helper methods.

The placeholder helper

This helper, released as part of the new view enhancements in 1.5, acts similar to the registry. We can set the baseurl into it from the bootstrap and it will be available where we need it whether it is in the layout or view scripts.

// Bootstrap
$view = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->view;
$baseUrl = Zend_Controller_Front::getInstance()->getBaseUrl();
$view->placeholder('baseurl')->baseurl = $baseUrl;

Retrieving the variable from a view script isn't that hard either... (plus the fact that it won't be destroyed if someone calls $this->clearVars())

echo $this->placeholder('baseurl')->baseurl;

The helper



Usage is simple, simply place the helper in your library and make sure that the view helper paths are setup correctly.


src="baseUrl(); ?>/images/foo.png"

/**
* Zend_Controller_Front
*/
require_once('Zend/Controller/Front.php');

/**
* BaseUrl helper
*
* @author Geoffrey Tran
* @package SpotSec_View
* @subpackage Helper
* @link http://www.spotsec.com
*/
class SpotSec_View_Helper_BaseUrl
{
/**
* Returns site base url
*
* $file is appended to the base url for simplicity
*
* @param string $file
* @return string
*/
public function baseUrl($file = null)
{
return Zend_Controller_Front::getInstance()->getRequest()->getBaseUrl()
. ($file ? ('/' . trim((string) $file, '/\\')) : '');
}
}
Integrating Doctrine ORM with Zend Framework


This article is a draft, check back later


Overview



Many of us have used Zend Framework's simple SQL database interface
implementation unforgettably known as Zend_Db. While Zend_Db is a great
component, fast and light compared to Doctrine or Propel, it
lacks many features of the latter alternatives. On top of this, there
are some problems with its API design at the time of this writing
(probably due to the rush to push ZF 1.0 out the door); however, I am
sure this will be fixed in a later release of the component. For those
who pass up using Zend Framework due to the percieved lack of an Active
Record implementation that many other frameworks out there have such as
Symfony or CakePHP, luckily an alternative such as Doctrine exists.



Doctrine is an ORM (object relational mapper) for PHP 5.2.x+ that sits
on top of a powerful DBAL (database abstraction layer). One of its key
features is the ability to optionally write database queries in an OO
(object oriented) SQL-dialect called DQL inspired by Hibernates HQL.
This provides developers with a powerful alternative to SQL that
maintains a maximum of flexibility without requiring needless code
duplication.


Now, those who have not heard of Doctrine may wonder: "Why should
I use this third-party library because it is not part of Zend
Framework?". There are several obvious answers to this question, one
could yell DRY, DOCTRINERULES, or my personal favorite, it uses ZF's
conventions and looks very similar to good ole Zendy. This bonus allows
almost seemless integration of Doctrine with a ZF-based application.


Including Doctrine



Including the Doctrine framework is no different than including any other framework; however, if you are like me and like to setup svn:externals for most of your libraries, Doctrine's Doctrine.php file is annoying because it exists outside of the "Doctrine/" folder. What I just did (although I didn't like it) is:



  • application/

    • libraries/

      • Doctrine/

        • Doctrine.php

        • Doctrine/



      • Zend/

      • incubator

        • Zend



      • laboratory







From there I could setup an extra include_path to "libraries/Doctrine". Those purists can just place Doctrine.php and the folder directly into the libraries/ folder.


Bootstrapping Doctrine



Fairly self-explainatory, as all we need to include Doctrine and then register its autoloader class with SPL. If you are wondering whether registering Doctrine's autoloader prevent's you from using your own or Zend Framework's, then think again because registering via the spl_autoload handler allows you to register multiple autoloaders.


/**
* Doctrine
*/
require_once('Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));

Setting up a connection


Models in Zend Framework

Integration Classes

These are integration classes which make using Doctrine with ZF much more seemless. Currently the ones I have posted are untested.

SpotSec_Loader_Autoload_Doctrine

View

Allows registering the autoloader using Zend_Loader::registerAutoload('SpotSec_Loader_Autoload_Doctrine');. This one's just for you integration purists ;)

SpotSec_Auth_Adapter_Doctrine

An authentication adapter similar to Zend_Auth_Adapter_DbTable

SpotSec_Log_Writer_Doctrine

View

A writer similar to Zend_Log_Writer_Db. It was backported from Doctrine_Log to work with Zend_Log.

SpotSec_Sesssion_SaveHandler_Doctrine

A Zend_Session save handler using Doctrine as a medium.


Resources



#ZFTalk Log Statistics as of November 07


Well, it has been over a year since #zftalk
on freenode.net has started and I thought I would make a quick post
about some statistics I got after a few queries from the logs gathered
over the time.



  • 163991 Lines spoken

  • Most "fu**" or "wtf" said: ecoleman (who'da know)

    • 144 lines



  • ~15,000 Nicks Logged (excluding those ending with _ or __, but this still seems inflated)



Here are some user statistics:

















































































Nick # of Lines

Naneau 18899
SpotSec 11693
ecoleman 8409
mirmo 5619
StormTide 5254
norm2782 5128
ralphschindler 4832
_Ergo_ 4642
Ai 3094
Booster 2566
rocketmagnet 2540
shudder 2366
jfro 1913
cenuij 1761
cbichis 1454
Akrabat 1397
Andries 1391
cyth 1297


 

Camel-Cased Controller/Action naming and Sub-Controllers

Overview



Well, by now I assume you have read a few Zend Framework tutorials, read the gigantic manual and created or in the process of creating an application. During this point in time, I am sure that many of you will realize if camelCased module, controller or action names are possible, right? It's just one of those questions that you just have ask right? Laughing



class MyPageController extends Zend_Controller_Action
{
public function fooIndexAction() {}
}


This would map to: my-page/foo-index in the url



The quick answer is yes, but I've noticed that the answer is harder to find in the manual now... It used to be smack there and obvious when there was a note section saying what the dispatcher supported; however, even I cannot find it after 5 minutes of skimming.


ZF URL Mapping


Camel-Cased modules, controllers or actions



The default dispatcher supports '-' and '.' as word delimiter characters to map urls to modules, controllers and actions; however, on the subject of view script naming, ZF convention states that they should be '-' or dash-separated.



Since controller and action names may contain word delimiter characters such as '_', '.', and '-', render() normalizes these to '-' when determining the script name. Internally, it uses the dispatcher's word and path delimiters to do this normalization. Thus, a request to /foo.bar/baz-bat will render the script foo-bar/baz-bat.phtml. If your action method contains camelCasing, please remember that this will result in '-' separated words when determining the view script file name.

Example



Lets say we have the following controller in a module named MyModule


Directory structure


  • application

    • modules

      • default

        • controllers

          • SubController

            • IndexController.php






          • FooBarController.php



        • views

          • foo-bar

            • index.phtml










      • my-module


        • controllers





          • MyPageController.php



        • views

          • my-page

            • my-action.phtml












MyModule_MyPageController


class MyModule_MyPageController extends Zend_Controller_Action
{
public function myActionAction() {}
}

Explanation


While I may have named my modules with a dash-separated style, it is worth noting that module names can be named in any style as the dispatcher will map the url whatever the physical module directory name is. So my-module, myModule, my.module will map to /my-module, /myModule, and /my.module respectively.



Controllers names on the other hand are different as the module and controller part of naming them are camel-cased; therefore, my-module, myModule, my.module would always be MyModule_ and my-page or my.page will always be MyPageController.



On the view side, items are normalized to be dash-separated so, myPageAction would execute my-page.phtml.


Sub-Directories in the controllers folder



A little known fact is that you can have "sub-controllers" in the controllers directory albeit it is not something I like to do. This functionality is probably discouraged as it is not documented in the manual (or at least I do not remember) and has in my humble opinion, wierd naming rules.



Here is what I know so far:



  • They can start with an upper or lower-cased letter

  • They are camel cased

    • This translates to a dash-separated url

      • SubController => sub-controller





  • They have strange urls compared to normal controllers

    • URL Format: [sub-controllerDir]_[sub-controller name]/[sub-controller action]

    • /sub-controller_index/index

    • /Sub-Controller_Index/index etc..




SubController_IndexController



class SubController_IndexController extends Zend_Controller_Action
{
public indexAction() {}
}

There you have it ;)



Hopefully this was a quick to read and understand, if not, you can always check out other resources such as the ZF mailing list or #zftalk on freenode.



 


Creating custom routes with Zend Framework

The Problem

So you have setup a nice application built with Zend Framework right? But then you realize that the urls are very, lets say, unfriendly...

  • http://www.yoursite.com/account/auth/login vs. http://www.yoursite.com/login
  • http://www.yoursite.com/blog/view/id/1 vs. http://www.yoursite.com/blog/view/1

Now what? You must of sat there pondering on your choices and came to the conclusion that you can either accept "http://yoursite.com/account/auth/login" or demand "http://yoursite.com/login".

The Solution

Custom routes!

Hidden in the documentation of Zend_Controller is the delightful juices of Zend_Controller_Router_Rewrite. Rather than me explaining it, here is an excerpt of what it does:

Zend_Controller_Router_Rewrite is the standard
framework router. Routing is the process of taking a URI endpoint
(that part of the URI which comes after the base URL and
decomposing it into parameters to determine which module,
controller, and action of that controller should receive the
request. This values of the module, controller, action and other
parameters are packaged into a
Zend_Controller_Request_Http object which is then
processed by Zend_Controller_Dispatcher_Standard.
Routing occurs only once: when the request is initially received and
before the first controller is dispatched.

If you want to understand more about routing, I strongly suggest that you read the whole section and try creating some example routes as it does help.

Types of routes

Currently there are four routes with one being the default routes under the name 'default' (Remember there is a removeDefaultRoutes function just in the unlikely case you want to remove them).

  • Zend_Controller_Router_Route - Most commonly used route type, as it handles "/view/id/1" -> "/view/1" or "/login"
  • Zend_Controller_Router_Route_Regex - Right behind the standard custom route is the regex route which can handle complex urls such as "/archive/2006/02/01/Foo.html"
  • Zend_Controller_Router_Route_Static - Probably the least used on my scale, but fairly useful for performance reasons. This type of route can be used when the url needed does not require patterns or parsing of url variables. An example could be "/login" if you do not need "/login/SpotSec" or "/login/key/value" type urls.

Zend_Controller_Router_Route

Lets say we want "http://yoursite.com/login" with the ability to do "http://yoursite.com/login/SpotSec" to map to "http://yoursite.com/accounts/auth/login". First in the bootstrap we need to get the router object. It is accessable through the FrontController via:

$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();

Next, lets create the route:

$route = new Zend_Controller_Router_Route('login/:username/*', array('module' => 'accounts', 
'controller' => 'auth',
'action' => 'login',
'username' => null),
array('username' => '(.*)'));
// Add it to the router
$router->addRoute('login', $route); // 'login' refers to a unique route name which will be used when generating urls with the url helpers

Now lets break down the route definition. In "login/:username/*", :username refers to anything provided after "login" aka "/login/SpotSec". It's a shortcut to doing "/login/username/SpotSec". "SpotSec" can be retrived in the controller via $this->getRequest()->getParam('username');

The asterisk * refers to any key/values that may be provided ("/login/SpotSec/key/value/key/value"). Simple eh?

Next is the array of defaults. This array defines where the route should map to and what the default variables such as "username" equal. It also defines if variables like ":username" in the url are optional or not. If 'username' => null was not provided, "http://yoursite.com/login" would not match and you would get a 404 error, but if 'username' => null was provided, "http://yoursite.com/login" would match.

Finally, the last array is optional, but it is useful when you want to make sure in "login/SpotSec" that SpotSec is a string or a numeric value. The format of this array is 'key' => 'regex'. NOTE: This array was just thrown in for example and I have not tested it.

The result? http://yoursite.com/login || http://yoursite.com/login/SpotSec || http://yoursite.com/login/SpotSec/lang/en

Using Zend_Config to Define Routes

So you've figured out how to define simpe routes in php now right? But you then realize that this could get tedious right? The solution, moving php defined routes into ini or xml config files. Just because I am an xml fan and the manual has an ini example, I will show you the xml version.

Here we setup the bootstrap:

//  Router config
$routerConfig = new Zend_Config_Xml('application/configs/routes.xml', 'staging');

// Set config
$router->setConfig($routerConfig);

Now lets see the xml version of the route example above (Remember if you copy and paste this, the xml head is missing):







login/:username/*

accounts
auth
login



(.*)








WHOO, Naneau is a monkey!

That's all for now, for part 2, we'll get into the regex route.

Useful References

Zend_Validate StringEquals implementation

It's a little wierd that people tend to miss the part in the manual that says Zend_Validate_StringEquals is hypothetical, so we see many people asking where it is. There is a Zend Framework test case here and my own implementation below. There are several ways to not use the StringEquals validator though, one is Zend_Validate_InArray().

$validators = array(
'password' => array(
new Zend_Validate_InArray(array($this->getParam('password_confirm')))
)
);

A little strange, but it does work the same way the stringEquals validator does :/
So here's the StringEquals implementation...

/**
* SpotSec Framework
*
* LICENSE
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @category SpotSec
* @package SpotSec_Validate
* @copyright Copyright (c) 2006 SpotSec Networks
* @license GNU Public License
* @link http://www.spotsec.com
*/

/**
* Zend_Validate_Abstract
*/
require_once('Zend/Validate/Abstract.php');

/**
* Validates whether all strings in an array are equal
*
* @author Geoffrey Tran
* @license GNU Public License
* @category SpotSec
* @package SpotSec_Validate
* @copyright Copyright 2006, SpotSec Networks
*/
class SpotSec_Validate_StringEquals extends Zend_Validate_Abstract
{
/**
* Validation key for not equal
*
*/
const NOT_EQUAL = 'notEqual';

/**
* Validation failure message template definitions
*
* @var array
*/
protected $_messageTemplates = array(
self::NOT_EQUAL => "The values are not equal",
);

/**
* Construct
*
*/
public function __construct()
{}

/**
* Validate an array of values
*
* @param array $value
* @return boolean
*/
public function isValid($value)
{
// Set values
$this->_setValue((array) $value);

// Check if equals
$referenceValue = array_shift($this->_value);
foreach ($this->_value as $val) {
if ($val != $referenceValue) {
$this->_error(self::NOT_EQUAL);
return false;
}
}

return true;
}
}
Zend_Json Tutorial >_< (Are you kidding?)


Ok, laugh all you want, but someone actually asked me this…


Encoding to json
Zend_Json::encode(array(‘a’));

Decoding from json
Zend_Json::decode($json);
Zend_Auth and Zend_Auth_Adapter_DbTable Tutorial

Overview

One of the many tasks that almost every application has to deal with is authentication which defined by the Zend Framework manual as:

Determining whether an entity actually is what it purports to be (i.e., identification), based on some set of credentials. Authorization, the process of deciding whether to allow an entity access to, or to perform operations upon, other entities is outside the scope of Zend_Auth. For more information about authorization and access control with the Zend Framework, please see Zend_Acl.

While Zend_Auth and Zend_Acl are closely related, this article will only concentrate on Zend_Auth and it’s database table adapter (Zend_Auth_Adapter_Db_Table). It probably should handle the Authorization side of things, but for no, all I'll say is let Zend_Acl figure out if the user is "logged in" or not...

Two ways to use Zend_Auth

Authenticating directly through the adapter will only verify if the user has the correct credentials while authenticating through Zend_Auth will effectively “log in” the user by setting the user’s identity (username or user row object) to Zend_Auth’s storage (Normally the session).

Authenticating through the adapter

In occurrences where you would want to quickly check if a user’s credentials are valid and the persistence of the identity is not needed, authenticating through the adapter is the easiest way.

authenticate_directly_from_adapter.png

// Setup adapter
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter, 'users_table', 'username_column', 'password_column', 'SHA1(?)');

// Setup user provided username and password
$authAdapter->setIdentity($username)
->setCredential($password);

// Try Authenticating
$result = $authAdapter->authenticate();
$result->getCode(); // Zend_Auth_Result::SUCCESS
$result->getIdentity() // $username
$result->getMessages() // array() unless Zend_Auth_Result::FAILURE*

Authenticating through Zend_Auth

When authenticating through Zend_Auth, it will take care if identity persistence.

authenticate_through_zend_auth.png
(Yes, I know what's wrong here...)
// Get a Zend_Auth instance
$auth = Zend_Auth::getInstance();

// Setup adapter
$adapter = new Zend_Auth_Adapter_DbTable($dbAdapter, 'users_table', 'username_column', 'password_column', 'SHA1(?)');

// Setup user provided username and password
$adapter->setIdentity($username)
->setCredential($password);

// Authenticate
$result = $auth->authenticate($adapter);

$result->getCode(); // Zend_Auth_Result::SUCCESS
$result->getIdentity(); // $username
$result->getMessages(); // array() unless Zend_Auth_Result::FAILURE*

if ($result->isValid()) {
// Set user row object as the identity
$auth->getStorage()->write($adapter->getResultRowObject());
}

$identity = $result->getIdentity();
/*
$identity->username;
$identity->password;
$identity->email;
*/

Checking if a user is logged in

if (Zend_Auth::getInstance()->hasIdentity()) {
// We're logged in, lets do something with the identity
$identity = Zend_Auth::getInstance()->getIdentity();
}

Log out a user

Zend_Auth::getInstance()->clearIdentity(); // Simple eh? 

Example demo application

Ok, that was a bad tutorial, but hey here's my example application for you to check out... Since I wrote it, expect it to be biased and probably poorly coded as I quickly put everything together. It includes Zend Framework so just place the zend_auth-tutorial folder in your document root and browse to it (After configuring the db in config.xml ofcourse ;) ).

Zend Framework Pastebin example app (SpotSec Paste)

Since Zend Framework 1.0 has come out, there have been many people looking for a simple hello world example application that does slightly more than hello world, so here it is, "SpotSec Paste". It is a quick and dirty pastebin application based on http://www.paste2.org's simple functionality. This quicky, while it doesn't have all the best practices I would like, does show how to use several of ZF's components and a few other tricks that make life simpler.

While it currently lacks many features of an actual pastebin site, this example application should be enough for those looking for an example to figure things out. Hopefully you will figure out what's good practice and what's bad from the code I wrote O_O. There are a few things that I think are missing from Zend Framework that should be included eventually, one of them is a baseUrl helper. Since I believe that global view variables are bad practice, wrapping baseUrl into a helper just seems right. Another helper I was thinking of implementing was a view registry of some sort to offload the usage of global view variables to a registry to unclutter the view.

Some limitations are that it uses geshi and geshi does not handle large code snippets very quickly. The solution would be either to cache the output with a static html view helper or just a plain caching view helper. Anyways, maybe some other day. . .

Other known problems is a css issue in opera, but I'm also too lazy to fix that.... 

BSD licensed

Demo

Download

Zend_View_Helper_DeclareVars (Error Notice: key does not exist)

Some times the most simplest solutions to problems tend pass us by
just like the Zend Framework DeclareVars view helper. When creating
templates using Zend_View, we encounter errors using strictVars because
some variables are not defined (Error Notice: key does not exist). It
is usually a pain to define variables that are not needed in the
controller or to check if a variable exists to avoid that error. This
is why we have this handy little neglected view helper.

The
Zend_View_Helper_DeclareVars view helper enables developers to define
variable defaults for a template, here is a snippet from the manual if
you have never bothered to read it:

declareVars():
Primarily for use when using strictVars(), this helper can be used to
declare template variables that may or may not already be set in the
view object, as well as to set default values. Arrays passed as
arguments to the method will be used to set default values; otherwise,
if the variable does not exist, it is set to an empty string.

The
basic usage is simple, pass it an associative array to be assigned as
the templates defaults, if we only pass it a variable name then that
variable will be set as '' (empty string). Here is another snippet from
the docblock of the helper:


$this->declareVars(
'varName1',
'varName2',
array(
'varName3' => 'defaultValue',
'varName4' => array()
)
);

Why is this useful? It is useful when working with forms and setting form values.

<?php $this->declareVars('email', 'country', 'optIn'); ?>
<form action="action.php" method="post">
    <p><label>Your Email:
        <?php echo $this->formText('email', $this->email, array('size' => 32)) ?>
    </label></p>
    <p><label>Your Country:
        <?php echo $this->formSelect('country', $this->country, null, $this->countries) ?>
    </label></p>
    <p><label>Would you like to opt in?
        <?php echo $this->formCheckbox('opt_in', $this->optIn, null, array('yes', 'no')) ?>
    </label></p>
</form>
Zend Framework Controller Modules? Huh?

Day to day, I tend to lurk in #zftak monitoring the discussions and occasionally I myself enter into discussions that wakes up the whole chat room because everyone has a different opinion on some subject. Today it seemed like most people could not agree on a standard directory layout, while others when off in a tangent about panda bears. This issue came up mainly because of what is specified in the Zend Framework manual. The manual does not exactly get to the point (or atleast the good stuff), so most people end up either creating a list of modules and adding them manually to the frontcontroller. The other issue was the conventional modular directory structure section in the manual:


docroot/
index.php
application/
default/
controllers/
IndexController.php
FooController.php
blog/
controllers/
IndexController.php
models/
views/
news/
controllers/
IndexController.php
ListController.php
models/
views/

Several people argued that since this is the way it was specified in the manual placing modules in the root of the application folder was recommended Yell. This is not actually the case since an application consists more than just an application folder with modules in it, it consists of configs, jobs, etc... If they read the whole page of the conventional modular directory section they would have seen the goodies...

/**
* Assuming the following directory structure:
* application/
* modules/
* default/
* controllers/
* foo/
* controllers/
* bar/
* controllers/
*/
$front->addModuleDirectory('/application/modules');

As shown here, having modules within a modules folder seems logical and allows the use of addModuleDirectory() which dispite of it's name, accepts a path to a directory containing modules. So it seems, "it's not a bug in the code, it's a bug in the programmer"... (or perhaps the layout of the manual for that page isn't very skim-reader friendly as the information introduced is built on by the more important info specified at the bottom...)

Zend_Log Syslog Writer (SpotSec_Log_Writer_Syslog)

Logging is something most applications do, logs help keep everything in order and the feeling of big brother standing right beside you. Zend_Log allows a php developer to easily implement logging into their application with the use of 'writers'. One writer I found to be missing from the Zend_Log component was a Syslog adapter which I thought was part of the Zend_Log rewrite proposal, but upon checking the proposal, it appears I was wrong. Anyways, I created a quick and dirty syslog writer for Zend_Log. This is by no means production ready as I have not tested it well enough, nor does it have the features that most would want.

(I'm not sure, but tinymce tends to escape things that I wish it wouldn't so the code may have some errors. Oh anything labeled SpotSec Framework is actually bsd licensed except I never got around to changing the template. Wink)
/**
* SpotSec Framework
*
* LICENSE
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @category SpotSec
* @package SpotSec_Log
* @subpackage Writer
* @copyright Copyright (c) 2006 SpotSec Networks
* @license GNU Public License
* @link http://www.spotsec.com
*/

/**
* Zend_Log_Writer_Abstract
*/
require_once('Zend/Log/Writer/Abstract.php');

/**
* A Zend_Log Syslog writer
*
* @author Geoffrey Tran
* @license GNU Public License
* @category SpotSec
* @package SpotSec_Log
* @subpackage Writer
* @copyright Copyright 2006, SpotSec Networks
*/
class SpotSec_Log_Writer_Syslog extends Zend_Log_Writer_Abstract
{
/**
* Class constructor
*
* @param string $ident
* @param string $option
* @param string $facility
*/
public function __construct($ident, $option, $facility)
{
// Define syslog related constants
define_syslog_variables();

// Open connection to syslog
openlog((string) $ident, (string) $option, (string) $facility);
}

/**
* Formatting is not possible on this writer
*/
public function setFormatter($formatter) {
throw new Zend_Log_Exception(get_class() . ' does not support formatting');
}

/**
* Write a message to the log.
*
* @param array $event log data event
* @return void
*/
protected function _write($event)
{
// Write to log
syslog($event['priority'], "({$event['priorityName']}) " . $event['message']);
}

/**
* Perform syslog shutdown
*
*/
public function shutdown()
{
// Close connection
closelog();
}
}
What is Zend Framework View Exception error.phtml?

Well, I was checking google sitemaps the other day and I saw one search engine query that just made me laugh Laughing. It was this:

uncaught exception zend_view_exception with message script "error error phtml" not found in path

Apparently there are a few people who still get blind sighted by the ViewRenderer (VR) action plugin and the ErrorController (ER) controller plugin which were quietly slipped in for Zend Framework 1.0 RC1. During that time it caused a stirr because it was unexpected, but most developers who have been using ZF since the 0.x.x series have learned to embrace VR. Anyways for those who searched and came here because of those mysterious view script exception errors like index.phtml or error.phtml, the solution is to create that file in your view/scripts/controller folder. Reading up on the VR and the ER documentation should tell you much more than I can. Perhaps this issue needs to be addressed in a quickstart guide. This issue as stated by Matt, was fixed in 1.0 RC3 as a quickstart guide was added to the controllers section of the manual.

The basics of Zend_Layout (ahem, Xend_Layout)
Zend_Layout has made it into core as of now.

This tutorial is out of date and only relates to the prepoposal form of Zend_Layout.
In other words, do not use it! Akrabat has beaten me to an updated tutorial: http://akrabat.com/2007/12/11/simple-zend_layout-example/

Overview



Now that Zend Framework 1.0 GA was released after months of hard work, I have decided that it is about time for a few 1.0 articles to come out. The problem of many frameworks is layouts, while the two-step pattern may solve some problems, it is still not efficient enough. At the moment there are several solutions to implementing a better view: the proposed Zend_View_Enhanced and the proposed Zend_Layout (Xend_Layout) by ralphschinder. Both have their own pros and cons, but in this article I will try to bring up the basics of Zend_Layout (Xend_Layout). Here below is a snippet of what Zend_Layout does (yes I know it doesn't make sense, but ralph wrote it):



Xend_Layout attempts to solve that since rearing its ugly head

over and over, has gone by many names: Composite Views, Layouts,

Templates, Partial Views, and/or Complex Views. They all basically

attempt to describe a common problem - that of being able to maintain

a consistent look and feel throughout a site or web application while

maintaining the "Don't Repeat Yourself" principals.



While the MVC had many interpetations, a commonly held perception

is that Views should not have any large amounts of authority over the

controller as it relates to its dispatch process. Xend_Layout adheres

to this tenant in the way it presents itself as a Layout engine.


For this article, I will be using the Xend namespace as I feel that since Zend_Layout is not officially part of ZF, it is not appropriate to be using it yet in the library and besides I svn:externals ZF. Xend_Layout can be grabbed here Xend_Layout SVN and here is Zend_Layout. If you decide to use Zend_Layout, it is the same component except with a different namespace, so everything is the same, also you probably should download the extra layout view helpers that complement the layout component. They can be found here: Zend_View Extra Helpers. These helpers are located in a separate proposal.


Let's Start



First in the bootstrap, using Xend_Layout is as simple as declaring it, it basically works the same as ViewRenderer. Xend_Layout hooks into VR in order to grab the view object from it, this integration allows people with ViewRenderer and Smarty integration to use Xend_Layout also. For those of you who might *forget* the templates path is the path to the views folder which includes scripts/* (layouts *.phtml) helpers/* (any custom layout helpers) filters/* (any custom filter helpers)


/**
* Layout
*/
Xend_Layout::setup(array(
'path' => '../application/layouts/', // View templates path (contains scripts, helpers and filters folders)
));
Xend_Layout::setDefaultLayoutName('default')


Xend_Layout::setDefaultLayoutName() sets the default layout to be rendered. Xend_Layout will detect that something was put into the response object so it will render the layout that is set or if a _forwad() is set, Xend_Layout will wait for the last dispatched action(). You can also want to pass your own view object to Zend_Layout by using the 'view' array key if you want to use a custom view object different than the one in the ViewRenderer. It is worth noting that setting a default layout is not required as the layout component will be dormant until the layoutManager action helper is called.



Lets go deeper into the controllers. In the controllers you have access to the layoutManager helper which controls Xend_Layout in a similar way to ViewRender. Here is an example of using a different layout other than the default layout set in the bootstrap:


// Basic Usage, using a previously configured layout, throws exception if non existent
$this->getHelper('layoutManager')->useLayoutName('Main');


Obviously now your wondering where's the power of this layout component? Well how about subsequent requests into a layout variable? A request is similar to rendering an action into a layout variable. Here are the parameters for Xend_Layout_Request():


public function __construct($name, $action, $controller, $module = 'default', Array $params = array())


Where $name is the name of the layout variable you want to render the request into, $action, $controller, $module are self explanatory and $params is the params you want to pass to the action. (This is basically $_GET|$_POST as you should always access those from $this->getRequest->getParam() inside the action)


// Advanced Usage (adding a request)
$this->getHelper('layoutManager')->getLayout('Main')->addRequest(new Xend_Layout_Request('LatestBlogEntries', 'latest-five', 'entry', 'blog'));
// main.phtml
echo $this->LatestBlogEntries;


Ok, I'm going to address a subject that confused the heck out of me until I read through the source of Zend_Layout. How do I make the view scripts for Zend_Layout? Zend_Layout will take anything given to the default response segment (aka $this->getResponse->setBody() etc..) and set it to $this->content for the layout view object. Anything that is rendered into other response segments ($this->getResponse->setBody($body, 'foo')) will be set as a variable for the view object of the layout. So for the 'foo' segment, the view object in the layout would have $this->foo. Here we have an example layout view script, say default.phtml


/*?php*/ body: $this->content; >
/*?php*/ module:$this->foo; > // php tags are striped out so I had to do this...

Disabling Zend_Layout



(The $this->getHelper('ViewRenderer')->setNoRender() equivalent)



Xend_Layout will render a layout regardless of whether ViewRenderer runs or not. (A user would rather have a blank layout that has links rather than a blank page right?)


// Disable VR
$this->getHelper('ViewRenderer')->setNoRender();
// Disable Layouts
$this->getHelper('LayoutManager')->disableLayouts();


This is by no means comprehensive guide to Zend_Layout, as it expects you to have previous knowledge of the MVC, ViewRenderer, Zend_View, and the request object. If you still need help there is our #zftalk irc channel and zfforums. Please do comment on what you think, I appreciate feedback *cough constructive criticism*. Laughing


Other Resources



http://layout.chanterelle.ca/layout.tar.gz - A Zend_Layout Example by StormTide


Zend Framework Example Project (coderepo)

Well, it's been a few weeks after the release of Zend Framework's RC2, and it has given developers enough time to start settling in with a stable api. With the coming release of RC3 and hopefully less bugs instead of introducing new ones, RC3 will bring more converts to Zend Framework. While the ZF team is rushing to push 1.0 GA out the door, there are still bugs in ZF, there are a few that I spotted and reported, but there are more that I haven't.

With the upcoming stablish api, I think it is about time that we start a large example application that other users can learn from. Looking around and from requests on #zftalk, I found that the community is in serious need of a ZF code repository because much of the code that developers write for their own use with ZF is quite reusable and helpful for others. In a blog by naneau, he explains the differences of view helpers, action helpers, and controller plugins. These "snippets" solve small repetitive tasks that a developer will go through while writing their applications. So why not share snippets with other developers, this way small repetitive tasks can be eliminated.

Enough about what the example project is, lets talk about how we are going to do this. Since I've decided this project should be an example application that new comers to Zend Framework can have a look at and possibly 'steal' code or styles from, the ZF-CodeRepository is going to be treated as a community project. Development will be open, anyone who feels that they want can improve the project can, but all code should be up to ZF standards. Why?, this is in order for others to learn the "correct" way of doing things (ok, it might be my way occasionally). This is because I've seen several projects based on ZF and the code was just not up to standards. While they worked, the implementation was horrible.

As for information, here it is:

Database design*
Features overview*

*draft

Zend Controller Acl Plugin

The usage of Zend_Acl described on the manual are fairly vague at the moment, but most experienced PHP programmers would find their way to creating a controller plugin. Out of laziness, SpotSec_Controller_Plugin_Acl was born because I wanted an easy way to implement Zend_Acl. While Zend_Auth is not related to this plugin, the plugin leaves this up to the developer when implementing the acl plugin's adapter.

While I will not go through how to use Zend_Acl, basic usage of this is that a developer would extend SpotSec_Controller_Plugin_Acl_Adapter_Abstract to work with their setup.

Usage

// Personal extended Acl Adapter that forwards to a login page on permissions denied
$aclPlugin = new Frontend_Controller_Plugin_Acl_Adapter_Frontend(array(
'module' => 'Auth',
'controller' => 'Login',
'action' => 'index'
));
$frontController->registerPlugin(new SpotSec_Controller_Plugin_Acl($acl, $aclPlugin));
/**
* SpotSec Framework
*
* LICENSE
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @category SpotSec
* @package SpotSec_Controller
* @subpackage Plugin
* @copyright Copyright (c) 2006 SpotSec Networks
* @license GNU Public License
* @link http://spotsec.com
*/

/**
* SpotSec_Controller_Plugin_Acl_Adapter_Abstract
*/
require_once('SpotSec/Controller/Plugin/Acl/Adapter/Abstract.php');

/**
* Zend_Controller_Plugin_Abstract
*/
require_once('Zend/Controller/Plugin/Abstract.php');

/**
* Zend_Auth_Adapter_Interface
*/
require_once('Zend/Auth/Adapter/Interface.php');

/**
* Controller plugin for authorization
*
* @author Geoffrey Tran
* @license GNU Public License
* @category SpotSec
* @package SpotSec_Controller
* @subpackage Plugin
* @copyright Copyright 2006, SpotSec Networks
*/
class SpotSec_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
{
/**
* Zend_Acl Object
*
* @var Zend_Acl
*/
protected $_acl;

/**
* Adapter
*
* @var SpotSec_Controller_Plugin_Acl_Adapter_Abstract
*/
protected $_adapter;

/**
* Construct
*
* $noAcl and $noAuth require an array with the following keys defined
* 'module', 'controller' and 'action'. These are used as the destination
* to forward the request when permission was denied.
*
* @param Zend_Acl $acl
* @param SpotSec_Controller_Plugin_Acl_Adapter_Abstract $adapter
*/
public function __construct(Zend_Acl $acl, SpotSec_Controller_Plugin_Acl_Adapter_Abstract $adapter)
{
$this->_acl = $acl;
$this->_adapter = $adapter;
}

/**
* Called before an action is dispatched by Zend_Controller_Dispatcher.
*
* This callback allows for proxy or filter behavior. By altering the
* request and resetting its dispatched flag (via
* {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}),
* the current action may be skipped.
*
* @param Zend_Controller_Request_Abstract $request
* @return void
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
// pass request to adapter
$this->_adapter->setRequest($this->getRequest());

$role = $this->_adapter->getRole();
$resource = $this->_adapter->getResource();
$privilege = $this->_adapter->getPrivilege();

if (!$this->_acl->has($resource)) {
// using global resource
$resource = null;
}

// if not dispatchable, then don't check acl.
// from here something like NoRoute will take over
$isDispatchable = Zend_Controller_Front::getInstance()
->getDispatcher()
->isDispatchable($this->getRequest());

if ($isDispatchable && !$this->_acl->isAllowed($role, $resource, $action)) {
$this->_adapter->notAllowed();
}
}
}
/**
* SpotSec Framework
*
* LICENSE
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @category SpotSec
* @package SpotSec_Controller_Plugin_Acl
* @subpackage Adapter
* @copyright Copyright (c) 2006 SpotSec Networks
* @license GNU Public License
* @link http://www.spotsec.com
*/

/**
* Acl controller plugin adapter
*
* @author Geoffrey Tran
* @license GNU Public License
* @category SpotSec
* @package SpotSec_Controller_Plugin_Acl
* @subpackage Adapter
* @copyright Copyright 2006, SpotSec Networks
*/
abstract class SpotSec_Controller_Plugin_Acl_Adapter_Abstract
{
/**
* @var Zend_Controller_Request_Abstract
*/
protected $_request;

/**
* Set request object
*
* @param Zend_Controller_Request_Abstract $request
* @return Zend_Controller_Plugin_Abstract
*/
public function setRequest(Zend_Controller_Request_Abstract $request)
{
$this->_request = $request;
return $this;
}

/**
* Get request object
*
* @return Zend_Controller_Request_Abstract $request
*/
public function getRequest()
{
return $this->_request;
}

/**
* Gets the acl role
*
*/
abstract public function getRole();

/**
* Gets the acl resource
*
*/
abstract public function getResource();

/**
* Gets the acl privilege or action
*
*/
abstract public function getPrivilege();

/**
* This function is run when the request is not allowed.
*
*/
abstract public function notAllowed();
}
Zend Model Loading (ModelLoader)
ModelLoader is now a proposal under Ralph Schindler located at Zend_Controller_Action_Helper_ModelLoader

Normally models are loaded through require_once() or Zend_Loader::loadClass() with painfully long paths similar to "module/models/Model.php" or "module/models/controller/Model.php" and more likely "../models/controller/Model.php". After a few discussion on #zftalk with ralphschindler, SpotSec_Controller_Action_Helper_ModelLoader came to existence. ModelLoader does exactly what the name says, it makes loading models one step simpler by determining the path to the models folder so all you have to do is specify the model's class name.

If you are using the conventional modular directory structure then ModelLoader is already setup and ready to go. If you are not then you can setup ModelLoader using __construct();

Grab it here

Usage:  $this->_helper->ModelLoader('UserModel');
$this->getHelper('ModelLoader')->load(array('Users', 'Groups')); // Array syntax supported

/**
* Zend_Controller_Action
*/
require_once 'Zend/Controller/Action/Helper/Abstract.php';

/**
* Zend_Loader
*/
require_once 'Zend/Loader.php';

class Xend_Controller_Action_Helper_ModelLoader extends Zend_Controller_Action_Helper_Abstract
{
/**
* $_modelPathSpec
*
* @var string
*/
protected $_modelPathSpec = ':moduleDir/models';

/**
* $_modelPrefixSpec
*
* @var string
*/
protected $_modelPrefixSpec = ':moduleName_';

/**
* $_modelPostfixSpec
*
* @todo Postfixing of names?
* @var string
*/
//protected $_modelPostfixSpec = '';

/**
* setModelPathSpec()
*
* @param string $pathSpec
* @return Xend_Controller_Action_Helper_ModelLoader
*/
public function setModelPathSpec($pathSpec)
{
$this->_modelPathSpec = $pathSpec;
return $this;
}

/**
* setModelPrefixSpec()
*
* @param string $prefixSpec
* @return Xend_Controller_Action_Helper_ModelLoader
*/
public function setModelPrefixSpec($prefixSpec)
{
$this->_modelPrefixSpec = $prefixSpec;
return $this;
}

/**
* load()
*
* @param string $model
* @param unknown_type $pathSpec
* @param unknown_type $prefixSpec
*/
public function load($models, $pathSpec = null, $prefixSpec = null)
{
$models = (array) $models;
$modelPathSpec = ($pathSpec !== null) ? $pathSpec : $this->_modelPathSpec;
$modelPrefixSpec = ($prefixSpec !== null) ? $prefixSpec : $this->_modelPrefixSpec;

foreach ($models as $model) {

if (class_exists($model)) {
continue;
}

if (!isset($front)) {
$front = Zend_Controller_Front::getInstance();
$modules = $front->getControllerDirectory();
}

// strip the controller directory name to get the real module path.
foreach ($modules as $moduleName => $moduleDir) {
$modules[$moduleName] = preg_replace('//'.$front->getModuleControllerDirectoryName().'$/', '', $moduleDir);
}

// init
$validModule = null;
$strippedModel = $model;

// find module based of what was supplied from the user
if ($modelPrefixSpec != '') {
foreach (array_keys($modules) as $checkModule) {
if (preg_match('/^'.str_replace(':moduleName', $checkModule, $modelPrefixSpec).'/i', $model, $matches)) {
$validModule = $checkModule;
$strippedModel = preg_replace('/^'.$matches[0].'/i', '', $model);
break;
}
}
}

// no module based on name, find the module name we are currently in?
if (!$validModule) {
if ($this->getRequest() instanceof Zend_Controller_Request_Abstract) {
$validModule = $this->getRequest()->getModuleName();
$stripFrom = str_replace(':moduleName', $validModule, $modelPrefixSpec);
$strippedModel = preg_replace('/^'.$stripFrom.'/i', '', $model);
}
}

// if not a valid module, go default.
if (!$validModule) {
$validModule = 'default';
}

// translate the path to the place where models are stored
$translatedPath = str_replace(':moduleDir', $modules[$validModule], $modelPathSpec);

// since we will use loadFile, we need to do our own Class->File (with dir) mapping
if (strstr($strippedModel, '_')) {
$moreDir = substr($strippedModel, 0, strrpos($strippedModel, '_')+1);
$strippedModel = str_replace($moreDir, '', $strippedModel);
$translatedPath .= DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $moreDir);
}

// make sure to translate underscores to dir seperators
$strippedModel = str_replace('_', DIRECTORY_SEPARATOR, $strippedModel);

// load the file
Zend_Loader::loadFile($strippedModel . '.php', $translatedPath);

// if model doesnt exist now, we gots major problems
if (!class_exists($model)) {
throw new Zend_Controller_Action_Exception('Model by name ' . $model . ' not found in file ' . $strippedModel .'.php in path ' . $translatedPath);
}

}

}

public function direct($model, $pathSpec = null, $prefixSpec = null)
{
$this->load($model, $pathSpec, $prefixSpec);
return $this;
}

}
#ZFTalk is growing
After the seed was planted, #ZFTalk seems to be growing steadily every day. It was displayed on DevZone and on PHPDeveloper, since then it has been replicated by many sites. Perhaps it's time you joined in Cool.



irc://irc.freenode.net/zftalk
Finally a Zend Framework IRC Channel

So anyways a few of the folks over in http://zfforums.com decided there was a need for a Zend Framework irc channel, but there was no official one around so here it is the unofficial: #zftalk on irc.freenode.net

Visit the homepage: http://www.zftalk.com

 zend framework
Sigh, PHP including latency


After profiling the current code for SpotSec Network Gateway, I've found that about 50% (~300 of the 634ms) of execution time to show a login page was used to load classes... This seems just way too much time spent doing something that feels useless. Apparently it seems that IO is a big factor here and this becomes a problem because we are designing this application to run on standard hardware, not your high performance 15k rpm servers :(.



As you can see in the screenshot below, this was the output of the xdebug profiler run. The Zend_Loader::_includeFile function is run by loadFile() which usually is run by loadClass(). Obviously ~341ms was used for including classes and some more ms was used by require_once() .



Perhaps this is the problem?



echo get_include_path();



.
:/usr/share/pear
:/mnt/StorageHD/Projects/spotsecng/trunk/WebConsole/src/webconsole/application/libraries
:/mnt/StorageHD/Projects/spotsecng/trunk/WebConsole/src/webconsole/application/models
:/mnt/StorageHD/Projects/spotsecng/trunk/Framework/src/
:/mnt/StorageHD/Projects/spotsecng/trunk/Framework/src/library
:/mnt/StorageHD/Projects/spotsecng/trunk/Framework/src/incubator/library


Arrg.... Suggestions?



spotsecngexecutionlatency.png

Zend Controller NoRoute Plugin

NOTE: The NoRoute Plugin has been deprecated since 1.0 RC1 in favor of the Zend_Controller_Plugin_ErrorHandler


There are a few NoRoute plugins out there, but here is a simple one that I've been using. For those who whine about this class not having acl or auth checking, it is built under the idea that acl and auth should be separated instead of being placed into one NoRoute super plugin.



The latest version can always be found on the spotsecng fisheye instance.

/**
* SpotSec Framework
*
* LICENSE
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @category SpotSec
* @package SpotSec_Controller
* @subpackage Plugin
* @copyright Copyright (c) 2006 SpotSec Networks
* @license GNU Public License
* @link http://www.spotsec.com
*/

/**
* Zend_Controller_Action
*/
require_once('Zend/Controller/Plugin/Abstract.php');

/**
* Zend Controller No Route Plugin
*
* @deprecated Superseded by {@see Zend_Controller_Plugin_ErrorHandler}
* @author Geoffrey Tran
* @license GNU Public License
* @category SpotSec
* @package SpotSec_Controller
* @subpackage Plugin
* @copyright Copyright 2006, SpotSec Networks
*/
class SpotSec_Controller_Plugin_NoRoute extends Zend_Controller_Plugin_Abstract
{
/**
* Module to redirect to when a request is not dispatchable
*
* @var string
*/
protected $_module;

/**
* Controller to redirect to when a request is not dispatchable
*
* @var string
*/
protected $_controller;

/**
* Action to redirect to when a request is not dispatchable
*
* @var string
*/
protected $_action;

/**
* Construct
*
* @param string $module Module to redirect to
* @param string $controller Controller to redirect to
* @param string $action Action to redirect to
*/
public function __construct($module = '', $controller = '', $action)
{
$this->_module = (string) (empty($module) ? Zend_Controller_Front::getDefaultModuleName() : $module);
$this->_controller = (string) (empty($controller) ? Zend_Controller_Front::getDefaultControllerName() : $controller);
$this->_action = (string) (empty($action) ? Zend_Controller_Front::getDefaultAction() : $action);
}

/**
* Called before an action is dispatched by Zend_Controller_Dispatcher.
*
* This callback allows for proxy or filter behavior. By altering the
* request and resetting its dispatched flag (via
* {@link Zend_Controller_Request_Abstract::setDispatched() setDispatched(false)}),
* the current action may be skipped.
*
* @param Zend_Controller_Request_Abstract $request
* @return void
*/
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$frontController = Zend_Controller_Front::getInstance();
$dispatcher = $frontController->getDispatcher();

if (! $dispatcher->isDispatchable($request)) {
$request->setModuleName($this->_module)
->setControllerName($this->_controller)
->setActionName($this->_action);
}
}
}