YASB – Yet Another Symfony Blog

June 21, 2008

A Symfony Quickie: Finding a File

Filed under: General, Tips and tricks — Krof Drakula @ 8:10 pm

It’s been a while, but I’ve finally made the plunge and did the first in the series of cookbook-related screencast tutorials for Symfony.


Edit: here’s the gist of the video.

== The sfFinder class ==

Symfony comes bundled with the sfFinder class that lets you conveniently search for files and directories. It has a simple fluent interface that lets you tell what you’re looking for and where to look for it:


To illustrate this example, let’s use an action that lists the contents of the upload folder. Inside an action, we assign the array returned by sfFinder to the template:

$this->images = sfFinder::type('file')->name('*.jpg')->relative()->in(sfConfig::get('sf_upload_dir'));

Since, by default, sfFinder returns absolute paths, we tell it to return everything relative to the search directory – this will include subdirectories as well.

In a template, we can now iterate over the images to list them:

foreach($images as $image):
  echo '<li>' . image_tag('/uploads/' . $image); . '</li>';

February 27, 2008

Installing Symfony 1.1 SVN and Symfony 1.0 PEAR packages side-by-side: A Windows Vista How-To (and XP, too)

Filed under: General, PHP, Tips and tricks — Krof Drakula @ 4:37 pm

As a tie-in to this excellent how-to for installing both versions of Symfony, I’ve decided to extend the method to apply to Vista as well.

EDIT: Symlinks don’t work this way because of the working directory being in C:\PHP where the symlink is located. See below for modified instructions.

First, check out the SVN branch for 1.1 to a directory of your choosing – this can be located anywhere on any storage volume. When the checkout’s done, open a command prompt and navigate into your PHP directory where symfony.bat is already located. In my case, this is C:\PHP and my checkout is D:\Projects\symfony-1.1. As Vista comes with an NTFS file system capable of UNIX-like (not quite, but close enough) symlinks (thanks to camason on #symfony for pointing that out to me), you can create a symlink to Symfony 1.1’s batch file using mklink (you’ll need a command prompt with elevated privileges for this to work):

C:\PHP> mklink symfony-1.1.bat d:\Projects\symfony-1.1\data\bin\symfony.bat

This creates a symbol link to the symfony.bat executable – now I can (assuming I have PATH set to C:\PHP) run symfony-1.1 at the command prompt from anywhere and can use the new branch with the same ease of use as the original article.

Unfortunately, due to symlinks executing with the working directory being in C:\PHP, you’ll get Symfony v. 1.0.x instead. To overcome this, delete the symlink and create a symfony-1.1.bat with the following contents:

@cmd /c d:\Projects\symfony-1.1\data\bin\symfony.bat %*

That will fix the working directory problem and correctly execute Symfony 1.1.

February 6, 2008

Tired of setting up your presentation/testing environment?

Filed under: General, Tips and tricks — Krof Drakula @ 12:45 am

Yeah, I’ve been away a while, had no time to update this blog, but still have been active on freenode’s #symfony channel.

Just a quick tip for anyone interested or looking for a better solution than XAMP – it’s called The Uniform Server. It unzips into a convenient folder anywhere on your computer and sits there until invoked. It’s portable (USB key server, anyone?), self-contained and can be secured and managed via the control panel after you get the server up and running.

It took me just 10 seconds to unzip and start the server (including opening the command prompt and typing Start_server.bat). That’s the fastest Apache/PHP5/MySQL setup I’ve ever done. Maybe not very newbie friendly, but for anyone used to working with LAMP, it should be a breeze.

October 17, 2007

Reaching deep into the I18n core

Filed under: General, Tips and tricks — Krof Drakula @ 11:56 am

When creating truly internationalized content, you need to think of a few things – first, what country your are in, and secondly, what the locale is in that country. Why should you care? User input.

While Symfony does have handy features via sfI18N, it doesn’t expose some of the methods needed to correctly parse strings. While string parsing isn’t meant to be the scope of this post, I’ll explain how to get your hands on the number formatting information to enable your application to correctly parse input strings and/or display them in templates (although, I might remind you of the Number helper and its application within the view layer, to aviod logic duplication when that’s already been taken care of).

When you want to get number format information, you simply create an instance of sfCultureInfo, like so:

// lang php
$culture_info = new sfCultureInfo(sfContext::getInstance()-&gt;getUser()-&gt;getCulture());
$number_format_info = $culture_info-&gt;getNumberFormat();
$negative_sign = $number_format-&gt;getNegativeSign();
$decimal_sign = $number_format-&gt;getDecimalSeparator();

This gives you the chance to write your own number parser according to the expected format and/or use locale-specific settings for different purposes for user-friendly input, not just sfI18N::getTimestampForCulture().

July 23, 2007

More gotchas from the Symfony world

Filed under: General, PHP, Tips and tricks — Krof Drakula @ 5:00 pm

Well, it seems there’s a few other things that aren’t as they seem in Symfony – if they’re expected or not, they are things I’ve noticed and needed a few minutes (or in a another case) or just over two hours to figure out.

All of them have to do with Symfony’s output escaper using PHPView. The first one is concerned with custom ResultSet objects that you pass into the template using a simple $this-&gt;anything assignation within an action or a component. Say you’re got a simple SQL query within a component or action that you want returned as a ResultSet (using Creole):

// lang php
$SQL = "
  FROM app_user
  WHERE insertion_time &gt; DATE_DIFF(CURDATE, INTERVAL ? DAY)
$stmt = Propel::getConnection()-&gt;prepareStatement($SQL);
$this-&gt;results = $stmt-&gt;executeQuery(
  array(7), ResultSet::FETCH_ASSOC

You’d expect to have $results contain a ResultSet object that you can iterate over using a while($results-&gt;next()) {}, but you’re in for a surprise – it doesn’t work.

If you look closely at the variable within the template printed out using print_r(), you can see that the object is wrapped within an sfOutputEscaper (or variant of) object that intercepts certain functions. This is what seems to happen when using a ResultSet object – the wrapper escaper object overloads the methods and prevents ResultSet’s methods from being invoked.

The solution? Place $results = $results-&gt;getRawValue() somewhere before the while loop and everything works fine.

I’ll probably enter a ticket for this one, after I grab something to eat. ;)

July 14, 2007

RobotReplay, a usability testing tool

Filed under: Ajax, Browsers, General, Tips and tricks — Krof Drakula @ 4:54 pm

If you’ve ever asked yourself just why your web site or web app doesn’t perform as well as you’ve thought it would, since you’ve given a lot thought into the design of the page and user interface, then you might ask yourself – are you the proper person to be judging the design?

In comes usability testing. It’s giving the end user a chance to work with your product (in our case, a web page or application) and having a system measure the user interaction – how long it takes them to locate a certain function, where they have the most difficulty identifying a certain feature, finding information, etc. There’s already great software that does exactly this (Morae, for example), but the problem here is that you still need a lab to conduct such experiments.


June 22, 2007

A PHP gotcha within Symfony

Filed under: General, PHP, Tips and tricks — Krof Drakula @ 10:45 am

There’s an interesting aspect about using functions within partials, which I’ve written about before – the existence of functions and the dangers of redeclaring them.

The problem here is using partial-specific functions within partials. We’ve had an instance where we needed a function to solve a recursive problem when displaying data within the partial (a complex tree structure).

The quick’n'dirty solution was to declare the function within the partial, which solves the problem. There was no PHP fatal error right up until functional testing. The reason why this error wasn’t spotted before was because the partial was used only once (if it was ever used within a view), thus never realising itself.

When running functional tests, sfTestBrowser instantiates an instance of the sfContext class and runs the application within a single runtime, which means that all registered global functions exist at all times. And because the partial is used by many views, the second the test encountered the second view that used the aforementioned partial, the test died with a PHP fatal error.

As mentioned in the article from before, the solution is to never declare any functions within template PHP files. Any functions that you need (even if it’s used by a single template file) should be declared within a helper and included appropriately. This way, Symfony guarantees the helper will be included exactly once, avoiding the fatal error that would otherwise crash the application.

May 20, 2007

Using jQuery to manipulate a foreign DOM

Filed under: Browsers, HTML, Javascript, Tips and tricks — Krof Drakula @ 9:39 am

This is somewhat of an old topic, but digging through a myriad of ways of including jQuery into a website that doesn’t use it (eg. Wordpress having Prototype and such), I stumbled upon a bookmarklet written by John Resig that loads jQuery into the current DOM and enables you to run an onload function that executes when the library’s ready to use.

Here’s the page where the process is documented with an example of manipulating Digg using jQuery. The approach used with this bookmarklet is useful because it enables you to turn on the noConflict mode without manually waiting for the library to load. You do this by replacing the comment fragment in the bookmarklet with jQuery.noConflict() inside the onload handler and hey presto! you have jQuery enabled and available via jQuery.*.

May 11, 2007

Easier I18n XLIFF message generation

Filed under: General, PHP, Tips and tricks — Krof Drakula @ 1:43 pm

If you’re like me and you don’t trust yourself to catch all of the breadcrumbs you leave behind you, you tend to rely on an arsenal of tools to keep you in check. This is especially true with XLIFF and Symfony.

There’s an i18n generation script that scans your actions, YAMLs and templates for the use of the __() function. The scanner routine is pretty robust and only adds missing entries, but leaves others intact. A great tool if you’re translating applications.

But there’s a problem: when you try to write your own validators and have I18n enabled in your application, the sfRequest::setError() expects 2 parameters: the name of the request parameter and the value of the error, the problem here being that ::setError() expects the second parameter to be the source language for translation, which in turn means that you don’t need to use __() to wrap your error message, so that it works directly with your validation YAML files.

That’s very smart, because you don’t have to translate your YAML validation files, since it already wraps it in __(). But not good, if you want to generate your own XLIFF files and not use the __() function (since the current implementation only scans for occurences of that function).

The problem was elegantly solved by fatg, who proposed testing the script for the detection of *__() functions – and it works. So, if you’re using any function which ends with __, the init-i18n script WILL detect it and add it to the XLIFF.

But how exactly does that solve anything? Well, instead of writing something like:

// lang php
$this-&gt;getRequest()-&gt;setError("my_parameter", "my_error");

…you write:

// lang php
$this-&gt;getRequest()-&gt;setError("my_parameter", i18n__("my_error"));

Okay, so the script now detects "my_error" as being an XLIFF source, but the application will fail with a fatal error in this case. That part is easily solved by adding

// lang php
function i18n__($message) { return $message; }

to apps/[myapp]/config/config.php, which creates the i18n__() function within the myapp application.

Although this isn’t the ideal solution (it would be nice if Symfony auto-generated the XLIFF by itself when using the __() function), it’s way better than duplicating the source keys inside comments like:

// lang php
// __("this is a source string");

Not only is it a pain to edit, it bloats the code significantly.

Anyways, hats off to fatg. Nice work.

April 2, 2007

A list of handy browser-specific CSS selectors

Filed under: Browsers, HTML, Tips and tricks — Krof Drakula @ 7:12 am

Well, not exactly breaking front page news, but I thought I’d share this handy library of CSS selectors for targeting specific browsers:

CSS Hacks

Older Posts »

Powered by WordPress