Symfony tutorial: How to make a gallery for admin-module
A while ago I’ve read this cool article by Will Linssen on sortable list in jQuery and this inspired me to take it to the next level which is Symfony. This is a tutorial how to make a for example product gallery in Symfony backend admin modules. For this I’m using Symfony 1.4, sfJqueryReloadedPlugin , sfThumbnailPlugin and Doctrine. The main goals we want to achieve here are:
- every product is able to have many images
- the images are sortable in desired order
- we want a drag’n'drop interface to change the order
- we want to get the embeding of form to minimum
1. The schema
So just to give you an idea let’s get things started. This is how the product might look like:
Product:
columns:
name: { type: string(255), notnull: true }
description: { type: blob }
price: { type: decimal }
Once again, this is not a final product, I’m just giving you something to work on. Expanding this model is up to you.
So now it’s time for the image:
Image:
columns:
name: { type: string(255), notnull: true }
image: { type: string(255), notnull: true }
ord: { type: integer }
product_id: { type: integer }
relations:
Product:
foreignAlias: Images
local: product_id
foreign: id
onDelete: cascade
Now just build all with:
./symfony doctrine:build --all
and generate an admin module for products (I’m assuming that you already have you backend app):
./symfony doctrine:generate-admin backend Product
2. The new image form
Now the thing we want to do is to embed a “add new Image” form in our existing form of Product edition. So go to you lib/form directory and create a class like this one.
// lib/form/BackendEmbedImageForm.class.php
<?php
/**
* Description of BackendEmbedImageForm
*
* @author Karol Sójko <karolsojko@gmail.com>
*/
class BackendEmbedImageForm extends ImageForm
{
public function configure()
{
unset($this['product_id'], $this['ord']);
$this->widgetSchema['name'] = new sfWidgetFormInput();
$this->widgetSchema['image'] = new sfWidgetFormInputFileEditable(array(
'file_src' => sfConfig::get('app_product_pictures_folder') . 'thumbnail/' .
$this->getObject()->getImage(),
'is_image' => true,
'edit_mode' => !$this->isNew(),
'template' => '%file% %input%'
));
$this->validatorSchema['name'] = new sfValidatorString();
$this->validatorSchema['image'] = new sfValidatorFile(array(
'path' => sfConfig::get('sf_web_dir') . sfConfig::get('app_product_pictures_folder'),
'required' => false,
'mime_types' => 'web_images'
));
}
}
As you can see the paths to the folders where the pictures will be stored are defined in the app.yml. This form extends the ImageForm as we don’t want to mess that one up and just keep things nice and clean. And as we want to have some thumbnails let’s override the save function in Image class:
public function save(Doctrine_Connection $conn = null)
{
if($this->isModified())
{
$uploadDir = sfConfig::get('sf_web_dir') . sfConfig::get('app_product_pictures_folder');
$thumbnail = new sfThumbnail(100, 100);
$thumbnail->loadFile($uploadDir.'/'.$this->getPhoto());
$thumbnail->save($uploadDir.'/thumbnail/'. $this->getPhoto());
}
}
3. The Product form
So now we want the product form to embed the new image form and we want to override the bind function to corespond to the changes as well.
// lib/form/doctrine/ProductForm.class.php
<?php
/**
* Product form.
*
* @author Karol Sójko <karolsojko@gmail.com>
*/
class ProductForm extends BaseProductForm
{
public function configure()
{
$imageForm = new BackendEmbedImageForm();
$this->embedForm('image', $imageForm);
$this->widgetSchema['image']->setLabel('New Image');
}
public function bind(array $taintedValues = null, array $taintedFiles = null)
{
if (is_null($taintedValues['image']['name']) ||
strlen($taintedValues['image']['name']) === 0 )
{
unset($this->embeddedForms['image'], $taintedValues['image']);
$this->validatorSchema['image'] = new sfValidatorPass();
}
else
{
$this->embeddedForms['image']->getObject()->setProduct($this->getObject());
}
$output = parent::bind($taintedValues, $taintedFiles);
foreach ($this->embeddedForms as $name => $form)
{
$this->embeddedForms[$name]->isBound = true;
$this->embeddedForms[$name]->values = $this->values[$name];
}
return $output;
}
}
4. The CSS, jQuery, routing and actions
First of all let’s get some style going on here:
/* web/css/imageList.css */
<pre>sortList</pre>
#info {
display: block;
padding: 10px; margin-bottom: 20px;
background-color: #efefef;
}
#images-list {
list-style: none;
}
#images-list li {
display: block;
padding: 20px 10px; margin-bottom: 3px;
background-color: #efefef;
}
#images-list li img.handle {
margin-right: 20px;
cursor: move;
}
Then let’s install the sfJQueryReloaded plugin. This is very important as we will use the jQuery helper. So now let’s make ourselves some jQuery magic:
// web/js/sortList.js
$(document).ready(function() {
$("#images-list").sortable({
handle : '.handle',
update : function () {
var order = $('#images-list').sortable('serialize');
$("#info").load("sort-images?"+order);
}
});
});
As you can se we invoke a route sort-images with the load function. So let’s make that route in the routing.yml and let’s add a delete route while we’re at it.
product_sort_images:
url: /product/:id/sort-images
param: { module: product, action: sortImages }
product_delete_image:
url: /product/:id/delete
param: { module: product, action: deleteImage }
Here are the coresponding actions:
// backend/modules/product/actions/actions.class.php
public function executeDeleteImage(sfWebRequest $request)
{
$image = Doctrine::getTable('djProductImage')->findOneById($request->getParameter('id'));
$image->delete();
return sfView::NONE;
}
public function executeSortImages(sfWebRequest $request)
{
foreach($request->getParameter('listItem') as $position => $item)
{
$image = Doctrine::getTable('djProductImage')->findOneById($item);
if($image != null)
{
$image->setOrd($position);
$image->save();
}
}
return sfView::NONE;
}
5. The component
Now let’s make a component that will display all the available images for us. We want to call the component “showImages”, so let’s just add this to the generator.yml.
// backend/modules/product/config/generator.yml
config:
...
form:
display: [ ~showImages, image, name, description, price ]
Now let’s add a method to the components class in our product module:
// backend/modules/product/actions/components.class.php
public function executeShowImages(sfWebRequest $request)
{
$productId = $request->getParameter('id');
if($productId)
{
$query = Doctrine_Query::create()->from('djProductImage i')
->where('i.product_id = ?', $productId)
->orderBy('i.ord ASC');
$this->images = $query->execute();
}
}
The reason why i didn’t use the $product->getImages() method is that I want them to be ordered by the ord field. Now let’s create the view for this component:
<?php use_stylesheet('imageList'); ?>
<?php use_javascript('sortList'); ?>
<?php use_helper('jQuery'); ?>
<div id="info"></div>
<div id="imagesList">
<ul id="images-list">
<?php foreach ($images as $image): ?>
<li id="listItem_<?php echo $image->getId(); ?>">
<img src="/images/arrow.png" alt="move" width="16" height="16" class="handle" />
<strong><?php echo $image->getName(); ?></strong>
<?php echo image_tag(sfConfig::get('app_product_pictures_folder') .
'thumbnail/' . $image->getImage()); ?>
<?php echo jq_link_to_remote(image_tag('/images/delete.png', array()), array(
'url' => '@product_delete_image?id=' . $image->getId(),
'complete' => '$("#listItem_' . $image->getId() . '").hide();',
), array('style' => 'background-image: none;')); ?>
</li>
<?php endforeach; ?>
</ul>
</div>
As you can see we use here the jq_link_to_remote function to invoke the delete function with jQuery.
Hope this helps. Share the love
Play – a Java framework for web applications
Not long ago i came across this cool Java framework for building your own web applications. Actually I think someone posted it at Twitter ( @playframework ). At first i saw the invitational presentation which you can find here or at the framework’s page.
First Impression
This looked like fun and was very similar to what I’m used to in Symfony based web applications. So I said “what the hell” and started off with the tutorial, most of the things seemed obvious and I was pleased with the concept of writing in Java and having the ability to use any Java library I would like to.
IDE
But wait, it gets even cooler. The guys developing this framework prepared some tasks to make your project integrate with your preferable Java IDE. If it’s NetBeans, like it was in my case, or Eclipse this is a matter of typing one command in your console.
All the keys you need to use …
The coolest thing about it I think is that while developing a web application in Play you get to use all sorts of solutions like Hibernate, OpenId, JUnit, templates based on Groovy and integrate them easily with your project.
Fresh prince
Although this framework seems to be a reasonably “fresh” thing on the web (version 1.0 wright now), it has quite a good looking portfolio to speak for itself. I think this will aspire to be an awesome lite Java framework for all agile projects and web applications. Good luck and congrats to the Play team.
How to optimize frontend in Symfony (CSS & JavaScript)
What ?
If you’re looking forward to optimize the frontend in your Symfony project or to introduce different CSS or JavaScript versions to each language in your application there’s a nice plugin that will help you with that. It’s called sfMinifyTSPlugin and it integrates Google’s minify library so you know it’s good stuff
.
Why ?
What makes it stand out from the rest of Symfony minify plugins is the fact that you don’t need to change anything in your .htaccess file or any other server stuff, just an out-of-the-box cool plugin.
The other nice thing about it is that you can implement it either as a filter or with a helper.
The fun part is also that the authors implemented some symfony tasks to help you clear-cache and fix permissions.
The cache files names are generated with a date so you’ve got all the usefull info about it and speeds up your web application just like that.
So don’t hesitate to experiment with this cool plugin in your future Symfony applications.
Why Symfony Is The Best Framework To Start ?

I thought I might put in a few good words for Symfony to all of you wandering which PHP framework to choose. Because there’s a whole bunch out there some of them worth mentioning are f.e. CakePHP, Zend and Symfony.
Why Symfony ?
The tutorial
First of all, the main reason that appealed to me when I started was that there is a whole 24 day-by-day tutorial which will teach you all you need to know about Symfony to get you started. Of course you won’t get a good grip of the framework after finishing the tutorial, but it should encourage the desired way of thinking in you. The Jobeet (set of 24 tutorials) covers everything you would want to know to build a basic website, from setting up the project, through forms, to f.e. having fun with AJAX
.
The documentation
This is the first place to go whenever you feel you have doubts about writing some snippet of code. This is practically the holy book of Symfony where all the laws are writtend down. Symfony’s documentation is written in a not complicated language and when you’re looking for something in particular it’s made in a way that you won’t spend hours searching the desired topic. So basically this and the jobeet tutorial are the pros which make Symfony a framework reaching out a hand to the developers.
Plugins
Writing about plugins is basically the point where the Symfony community should get the needed applause. Whenever you’re searching for a functionality or thinking on a way to design one, go here first. There are a lot of useful ones there f.e. a plugin for Twitter, Facebook or a plugin for user authorization. And most important they are lively developed.
ORM
I’m using at the moment Propel as my primary ORM but the default choice in near future will be Doctrine. Anyway, forget about writing long and pesky SQL statements. You’ll just love the object methods that handle all the stuff for you. All you need to the is focus on your applications goal and Symfony will handle your database in neat objects, ain’t it fun
?
The tasks
This is where the fun part is as well. Building symfony and integrating it with your database is just a few words typed in the command line away. Just type ./symfony in your project’s directory and you’ll get the list of all the tasks that’ll help you on your way to finish your application. The more confident you’ll get with symfony, the more fond you’ll find yourself of those sneaky little bastards that make a developers day easier.
Because It is fun to learn !
Yeah, that’s wright. And you should check it as well. Take it for a spin, spend time with it and you’ll see that after each day you’ll get more anxious to learn new stuff and after a few weeks you’ll wonder why didn’t you find it earlier
. Of course it is hard to mention all the great stuff about Symfony, but i think I’ve drawn the picture for you, why it is the best one to start with. Have fun and good luck
!
Ubuntu tutorial: How to install Tweetdeck on Ubuntu 9.04 64 bit
Lately I’ve discovered this great tool Tweetdeck to manage and twitt from your Tweeter account. It also supports Facebook so you can see this is very handy to have all in one application. It runs in Adobe AIR enviorment so it is cross-platform, but I’ve noticed that to install it on Ubuntu 9.04 (Jaunty Jackalope) in the 64 bit version you have to do some extra steps. So here’s the tutorial:

1) Get the getlibs-all.deb package from here (If the link will break in future, try searching it on google there’s a lot of it out there)
2) Install the libraries
sudo apt-get install lib32asound2 lib32gcc1 lib32ncurses5 lib32stdc++6 lib32z1 libc6 libc6-i386 lib32nss-mdns sudo apt-get install ia32-libs sudo getlibs -l libgnome-keyring.so sudo getlibs -l libgnome-keyring.so.0 sudo getlibs -l libgnome-keyring.so.0.1.1
3) Download Adobe AIR
4) Give the downloaded file execution writes
sudo chmod +x ./AdobeAIRInstaller.bin
5) Install Adobe Air
sudo ./AdobeAIRInstaller.bin
6) Copy libraries
sudo cp /usr/lib/libadobecertstore.so /usr/lib32
7) Install Tweetdeck by going to their page and clicking download.
Have fun hope it helps and you’ll enjoy Tweetdeck
Ubuntu tutorial: How to install Firefox 3.5

A lot of people are searching for it so I thought I can write a how-to for installing Firefox 3.5 on Ubuntu 9.04 Jaunty Jackalope.
1) First of all you need to add the mozilla-daily repository:
sudo gedit /etc/apt/sources.list
and append at the end of the list:
deb http://ppa.launchpad.net/ubuntu-mozilla-daily/ppa/ubuntu jaunty main
save and close the file.
2) Now add the key:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 247510BE
3) Update
sudo apt-get update

The "True" Firefox
4) Install
sudo apt-get install firefox-3.5 firefox-3.5-gnome-support
5) Replace symbolic links
At this point you can run firefox 3.5 just by typing firefox-3.5 in the command line. But if you’re sure you don’t want to use firefox 3.0 anymore go to /usr/bin/ and remove the symbolic link:
rm -r firefox
and make it point to firefox-3.5
ln -s firefox-3.5 firefox
The Firefox-3.5 codename on Ubuntu is Shiretoko so don’t be suprised when you see your browser is named Shiretoko. That’s all, hope it helps feel free to comment
.
Dropbox – Secure backup made easy

I’ve become a big fan of Dropbox lately. I’ve been testing out their service and I must say it is just great. Not only do you get a lot of space for your files you also can get even more thanks to do referral system. You can get up to 3 GB of storage space just from inviting people to dropbox. Ofcourse that’s not all it is. The registration process is very easy and doesn’t require you to fill up a big registration form so that’s fun to do wright ?

Then they have a Dropbox client for Windows and Linux as well, and I must say I’ve tested it on both systems and I must say it works fine on both so this is really a great out-of-the-box solution for storaging all your data. You don’t have to remember to take your pendrive everywhere you go, the data just lies on the servers and you can download and upload it anytime you want, from the browser as well !

If you like you can follow them on Twitter and Facebook, sometimes they give away free space ( lately for some cool limericks
)so feel free to check them out. Definitely a must try

SilverStripe – the CMS tailored for you ?

I was going to write a tutorial on how to install SilverStripe and build a basic website, but then again it’s all basicaly on the their website. So i thought to myself – hey, why not make a simple review of what’s in SilverStripe.
Till this day I’ve been using SilverStripe for about 4 months for a few different projects and I’ve got a couple of thoughts going through my mind at the moment.
“Simple is good”
First of all if you’re planning to build some simple websites, probably most of the time static ones, this is definitely the best solution for you. For more complex websites it isn’t that bad but there are some issues that always will catch you with your pants down.
“Simple doesn’t mean flexible”
The template syntax is very poor and it sometimes leaves you with your hands tide. For example the most annoying thing for me and my colleagues were the loops (<% control %> ). They don’t support a good flexible iteration. Forget about modulation of an iterating variable. The second thing that keeps some people angry is that you can’t call functions from a template with variables as arguments. Oh man, sometimes this requires some real code stretching from you.
Like a candy…

Then again SilverStripe has got an awesome Page tree hierarchy which easily let’s you develop new types of pages. This can be very handy as you can define new types of pages and define their individual behaviour. The backend layout is very simple (good) and eye-pleasing so it doesn’t confuse the user too much.
The flaws
The security and rites and too simple, basicaly it brings it down to “Admin” being the ultimate god-like-user and “The rest”. That’s definitely too simple to talk about user groups managing.
Next thing is that SilverStripe is relativly slow. Big applications seem to cache not properly. It lacks of a good flash support module.
The bright side
But on the bright side this CMS is very rapidly growing and becoming better thanks to the community. Though

SilverStripe based sites
most of the contributors tend to write their solutions on SilverStripe forum than to publish they extensions on the website, so if you’ve got a problem with SilverStripe the forum should be the first place to look. Having all the simple extensions like blog, e-commerce, forums, user-defined forms – just to name a few, makes this CMS a really great tool to build your website.
All in all
I hope that this CMS will grow strong in time and it will be more flexible as it is today because wright now it’s my favourite out there. All in all remember only that if you’re hoping to buid some advance and complex application you better think through the whole building process and check if SilverStripe has what you need.
Google Wave , can’t wait for you !

Today i’ve heard for the first time about Google’s new project called Google Wave. Basicly it’s a new tool for collaboration and communication on the web. As i was watching the presentation some of the things totally blew my mind.
I’m very excited to see the e-mail functionalities, where you’re going to be able to put some “reply” part’s of your text inside the recieved massage instead of editing it by hand like it was so far. Then again the live-chat which was already there but now it looks so nice and tasty and it is full proof “real-time” so you just want to start using it
. The third thing that i’m interested in is the very cool looking spelling tool which hints and corrects the word instantly. This woudl be a great benefit for people all over the world. Read the rest of this entry »





