» A Great Article Series on Agavi
Vikram Vaswani has written a great article series on Agavi. The five-part series starts off with the basic but in the end goes quite deep into building a multi presentational layer web application. Go read it on the IBM developerWorks! Now!
- Part 1: Open a whole new world with Agavi
- Part 2: Add forms and database support with Agavi and Doctrine
- Part 3: Add authentication and administrative functions with Agavi
- Part 4: Create an Agavi search engine with multiple output types including XML, RSS, or SOAP
- Part 5: Add paging, file uploads, and custom input validators to your Agavi application
» Be Careful with PHP’s version_compare
Be Careful with PHP’s version_compare
var_dump(version_compare("5.2.8-0.dotdeb.1", "5.2.8", "<="));
Expected result: bool(true)
Actual result: bool(false)
The moral of the story: use < or >.
» Installing a Project-local Propel
Installing a Project-local Propel
Installing Propel is often seen as a difficult task. Official installion instructions recommend installing via Pear and say more initial work is requireq to install it manually. I usually advice not to use global Pear installations but install everything per project because it gives you better control and you are able to use different versions of libraries for different project. This article shows you how easy it actually is to have a project-local installation of Propel 1.3.
Prerequisites
- Phing 2.2.x (and, thus, Pear)
Phing is the only exception to my “no pear installations” rule. It can be installed per project but I see Phing as a development tool you can have globally on your development machine.
Suggested Directory Layout
/ project root
dev/ development-time files (docs, database schemas, code templates etc.)
db/ database development files (schema.xml, diagrams, docs etc.)
libs/ development-time libraries
libs/ runtime libraries (3rd party)
Getting Propel from the SVN
I recommend fetching Propel directly from the SVN repository simply because I see that as the easiest choice and you have full control of which version to pick. Also, should you ever want to upgrade to a newer revision (maybe there is a bugfix that isn’t officially released yet), you can just retrieve it from the repository. Personally I have 3rd party libraries set up as svn:external where possible but we don’t go into that in this article.
Propel is split into two components - generator and runtime libraries and we’ll keep those two appart. So, in your project root execute following SVN commands:
svn export http://svn.phpdb.org/propel/branches/1.3/generator dev/libs/propel svn export http://svn.phpdb.org/propel/branches/1.3/runtime/classes/propel libs/propel
And that is it. YES, I mean it!
Propel is now ready to be used. You don’t need to set PATH or include_path, you don’t need to copy executables anywhere and you don’t have to modify a single file.
Building a Propel Project
Create your schema.xml, runtime-conf.xml and build.properties files in dev/db. To build your project go to your project root and run
dev/libs/propel/bin/propel-gen dev/db
… and whatch Propel do its magic. Propel creates output files into ´dev/db/build/´
Fine-tuning The Building Process
You can control where Propel puts the output with a few build.properties directives. Here’s an example that probably needs no explanation.
#relative to propel-gen script
propel.output.dir = ../../..
propel.php.dir = ${propel.output.dir}/app/lib/propel
propel.phpconf.dir = ${propel.output.dir}/dev/db/config
propel.sql.dir = ${propel.output.dir}/dev/db/sql
What About Runtime?
Yeah, you got me there - there’s still one thing you need to take care of before everything “just works”.
//propel runtime + path to your om classes $path = '/my/project/libs' . PATH_SEPARATOR . '/my/project/app/lib/propel'; set_include_path(get_include_path() . PATH_SEPARATOR . $path);
» Agavi Tip: Automatic Output of Validation Errors
Agavi Tip: Automatic Output of Validation Errors
I decided today to stop printing my validation error messages manually in the template. I knew that Form Population Filter (one of Agavi’s many excellent features also referred to as FPF) could be used to inject error messages into the HTML form next to erroneous fields but I want my error messages above the form. Once again David was there to help me and with a few iterations of trial and error he offered a working solution for me. And the solution was so simple and nice that I just had to blog it.
Filter Configuration
global_filters.xml
<filter name="FormPopulationFilter" class="AgaviFormPopulationFilter">
<ae:parameter name="methods">
<ae:parameter>write</ae:parameter>
</ae:parameter>
<ae:parameter name="output_types">
<ae:parameter>html</ae:parameter>
</ae:parameter>
<ae:parameter name="error_messages">
<ae:parameter name="self::${htmlnsPrefix}form">
<ae:parameter name="location">before</ae:parameter>
<ae:parameter name="container"><![CDATA[<div class="errors">${errorMessages}</div>]]></ae:parameter>
<ae:parameter name="markup"><![CDATA[<p class="error">${errorMessage}</p>]]></ae:parameter>
</ae:parameter>
</ae:parameter>
</filter>
And that’s it. FPF injects all error messages above your form. Each error message in its own paragraph and all paragraphs wrapped inside a <div>
Want More?
FPF can have different rules for different kinds of errors and with XPath you can inject them pretty much anywhere you want. See the Agavi’s sample application for more examples.
» Running IE6, IE7 and IE8 Virtually
Running IE6, IE7 and IE8 Virtually
Now, this is not easy for me to admit but I just learned about an awesome Windows application by Microsoft.. from a mac user :)
Microsoft Virtual PC 2007 SP1 & Internet Explorer VPC Images
I cannot believe this has been under my radar all this time. Finally I can easily have different windows/IE setups. The software is free (yes, I found it hard to believe too but it’s true!) and Microsoft gives you ready-to-use virtual hard-drive images with operating system and IE ready.
It has been a long time since I last praised Microsoft for doing something right. And now I’m getting suspicious… what’s the catch here?!
Installation
- Download Virtual PC 2007 setup.exe, execute it and enjoy the no-reboot-required installation (yet another amazing thing).
- Download one or more hard-drive images, execute and select a directory where you want the image to be extracted.
- Start Virtual PC 2007 and create a new virtual machine. Use the extracted hard-drive image.
- Boot up the virtual machine and enjoy the IE experience
P.S. Like the original post describes you can use virtual images provided by MS with other operating systems / virtual machine hosts too.
» Agavi Tip: Validation Gotchas
Agavi Validation Gotchas
Agavi’s input validation system is extremely versatile and even people with long history with Agavi - me for example - sometimes struggle to get their head around it. So I decided to put down a few gotchas. Here goes…
Validators Can Be Grouped
You can use AgaviAndValidator, AgaviOrValidator and AgaviXorValidator to group several validators.
<validator class="or">
<validators>
<validator class="email" required="false" >
<arguments>
<argument>email</argument>
</arguments>
</validator>
<validator class="MyPhoneNumberValidator" required="false" >
<arguments>
<argument>phone</argument>
</arguments>
</validator>
</validators>
<errors>
<error>Please provide email or phone</error>
</errors>
</validator>
Validator Can Depend on Another Validator
Quite often you only want validate input B only if the user provided input A. Agavi makes this simple:
<validator ... required="false" provides="street_set">
<arguments base="contact">
<argument>Street</argument>
</arguments>
</validator>
<validator ... required="true" depends="contact[street_set]">
<arguments base="contact">
<argument>Zip</argument>
</arguments>
</validator>
Note: argument’s
baseattribute affects also provides/depends attributes (see example above) !!
Pimp My Error Messages
A validator can throw different error message based on what went wrong and error messages can be translated on the fly. Error message options vary between validators. See API docs for more.
<validator class="string" translation_domain="default.errors">
<arguments>
<argument>my_input</argument>
</arguments>
<errors>
<error for="required">Please fill this input</error>
<error for="max">Please keep it shorter than 40 characters</error>
</errors>
<ae:parameters>
<ae:parameter name="max">40</ae:parameter>
</ae:parameters>
</validator>
Validating Array Inputs
<input name=”rows[Id]”
<arguments base="rows">
<argument>Id</argument>
</arguments>
<!-- or -->
<arguments>
<argument>rows[Id]</argument>
</arguments>
<input name=”rows[1][Id]”
<arguments base="rows[]">
<argument>Id</argument>
</arguments>
<input name=”rows[]”
<arguments base="rows[]">
<argument/>
</argument>
Validator Can Normalize And Export Combined Values
This example shows how to get AgaviDateValidator to validate a compound value. But that’s not all! It’ll even export a proper timestamp for you to use in your application code.
<validator class="AgaviDateTimeValidator">
<arguments>
<argument name="AgaviDateDefinitions::DATE">day</argument>
<argument name="AgaviDateDefinitions::MONTH">month</argument>
<argument name="AgaviDateDefinitions::YEAR">year</argument>
</arguments>
<errors>
<error>Validation error</error>
</errors>
<ae:parameters>
<ae:parameter name="export">MyDatestamp</ae:parameter>
</ae:parameters>
</validator>
Remember to Validate ALL Input
Validation is not limited to GET/POST input parameters but HTTP headers and cookies can (and should) be validated too. Use the source attribute to tell the validator where to get the data from.
<validator ... source="headers"> <argument>REFERER</argument>
Validator is ran only if the parameter is non-empty.
By default the validator base class AgaviValidator checks that all the arguments are set before executing the actual validation. If the input value is empty or non-existent but required error is thrown. But if required attribute is set to False the validation just quietly continues to another validator. Normally this is not a problem but you might want to code a custom validator that exports a default value for empty parameters. In this case you need to override AgaviValidator’s checkAllArgumentsSet().
Did I forget something?
Join #agavi IRC channel and hassle me there or send email to veikko@veikko.fi.
» Agavi Tip: Checking Validation Results
Agavi Tip: Checking Validation Results
Normally when an input validator fails you’ll just want to show the form again and let FormPopulationFilter do its magic (you do know you can it have re-populate the form and inject error messages into the form, don’t you?-). But occasionally you want to decide the next move based on what validator failed. With Agavi 1.0 getting validation incidents of a named validator is this simple:
public function handleError(AgaviRequestDataHolder $rd)
{
$vm = $this->container->getValidationManager();
if (count($vm->getReport()->getValidatorResult('my_special_validator')->getIncidents())) {
return 'CriticalError';
}
else {
return 'Error';
}
}
Note: that AgaviValidationValidatorResult was missing from the core autoload.xml in 1.0 Beta 6. This has been fixed in the SVN If you aren’t using the bleeding edge version add the following line to your
config/autoload.xml.
<autoload name="AgaviValidationValidatorResult">%core.agavi_dir%/validator/AgaviValidationValidatorResult.class.php</autoload>
Agavi Debug Tools now supports Propel query logging (both FirePHP and HTML output). Just configure Propel to use DebugPDO and AdtFilter to use AdtPropelDataSource. Nothing else required.
» How to Enable Syntax Highlighting in Tumblr
How to Enable Syntax Highlighting in Tumblr
It’s alwasy nicer to read code snippets with a proper syntax highlighting but unfortunately Tumblr, although used by many code monkeys, doesn’t support this. It is however pretty simple to add syntax highlighting to Tumblr. All you need is a Javascript library (you have several to choose from) and a bit of Tumblr template editing. You of course also need a web host for these additional Javascript and CSS files.
Prerequisites
- Web host for a few additional Javascript and CSS files. You cannot upload files to Tumblr.
- Custom Tumblr template. You need to add a few lines of HTML code into your template.
SHJS - Syntax Highlighting in JavaScript
From all the alternatives Google found for me my choice was SHJS. It seemed simple enough.
1. Install SHJS
Just upload the SHJS files to your web host.
2. Edit Your Template
SHJS requires one main Javascript file plus one for each syntax you want to use. In the example only PHP syntax is loaded. You also need to load a CSS file. And the final thing to add is the onload call to body.
<head>
...
<script type="text/javascript"
src="http://mydomain.tld/blog_resources/sh_main.js"></script>
<script type="text/javascript"
src="http://mydomain.tld/blog_resources/lang/sh_php.js"></script>
<link type="text/css" rel="stylesheet"
href="http://mydomain.tld/blog_resources/css/sh_nedit.css">
</head>
<body onload="sh_highlightDocument();">
3. Start Showing off Your Mad Coding Skilz
SHJS automatically parses code wrapped inside <pre>. Use special class identifiers to tell it what syntax highlighting to use. Refer to SHJS documentation for available syntaxes/class names.
<pre class="sh_php">
$foo = new MyClass('string', array(123, 456));
</pre>
