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.

http://www.vimeo.com/1209869

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:

sfFinder::type('file')->name('*.jpg')->in(sfConfig::get('sf_upload_dir'));

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>';
endforeach;

May 21, 2008

Initial commit of sfToboAds plugin now available

Filed under: General, PHP — Krof Drakula @ 9:35 pm

We’ve just released the initial version of sfToboAds, a Symfony plugin allowing for integration with ToboAds, an advertising network offering contextual text and graphic advertising to the masses (banners are contextual!). The initial release is pending PEAR packaging before being offered as a compressed download, for now, it’s available via the subversion repository on the following URL:

http://toboads-plugins.googlecode.com/svn/trunk/symfony_plugin

This is part of our wider package of plugins for different platforms and is fully LGPL licensed. A solid release with updated documentation will be available soon.

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 19, 2008

Tuesday weirdness: a Symfony on Symbian phones

Filed under: Exotic, General, PHP — Krof Drakula @ 6:59 pm

A while back, I’ve stumbled upon an interesting, yet exotic, project – PAMP. It promises to bring the full Apache/MySQL/PHP stack to the Symbian phone. So, on a whim, I decided to try it out.

After following the installation instructions (installing on a Nokia N95 with the installation for memory cards) and starting up the PAMP stack, I’ve connected to the home LAN network and navigated my computer’s browser to the phone’s LAN IP. Lo and behold – the almighty “It works!” sign showed up. Even phpinfo() says it’s got most of the bundled extensions enabled (including GD2 and mbstring!).

So, on another whim, I decided to stress test the bugger and see if it runs Symfony. To spare you the excitement – it doesn’t run. Copying the files via USB messes up the file casing, so I had to re-copy the whole shebang using the phone’s sync software (which I’m still doing).

One thing to add though – while copying, I’ve noticed some files will not copy and I’m guessing the culprit is the lenght of the absolute path and name of the file. The first one in question is located inside $sf_data_dir/sfPropelCrud/ somewhere (the damn thing won’t show me which), there are probably more (I’m still copying files by hand). While I’m not using the generator in the test application, it seems there will have to be some workaround to get it working on a this phone (but the question really is – is Symfony really meant to run on phones?).

More to follow.

Edit:

It seems that using the phone software’s bundled File Manager solves the file casing issue. I still haven’t managed to copy all the files, but those that can’t be copied I’m sure won’t get used anyways (some generator skeletons and such).

Edit nr.2:

Well, all things said and done, it seems PHP segfaults before symfony has even a chance of running anything, but no way of seeing what error is produced, exactly. I haven’t been able to find any Apache logs written anywhere. And no, no Symfony logs to speak of as of now (it segfaults before that point). It could be something to do with UTF-8 encoding – I’ve tried opening a file on the phone with the default file manager and all the YAML files were messed up. I’m not even sure which encoding the phone is using. It’d be a shame if it was limited to ISO-8859-2 or such.

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 = "
  SELECT *
  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.

(more…)

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 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.

Older Posts »

Powered by WordPress