Article

Learn symfony: a Beginner's Tutorial

Page: 1 2 3 4 5 6 7 Next

Using Plugins

The current photo upload feature suffers from one major drawback: large pictures don't render well in the list and edit views. We need to save a thumbnail of the picture when it's uploaded. Fortunately, symfony can generate thumbnails thanks to the sfThumbnail plugin. Plugins are extensions to the framework that are installed for a given application. To install a plugin, just call the plugin-install task with the symfony command, as follows:

$ php symfony plugin-install http://plugins.symfony-project.com/sfThumbnailPlugin

This command uses PEAR to download and install a symfony plugin package. If you don't have PEAR installed, you can download the sfThumbnailPlugin package and unpack it under the plugins/ folder. Clear the cache (to enable the autoloading system to find the classes located in the new sfThumbnailPlugin/ directory), and the plugin is ready to be used.

$ php symfony clear-cache

We'll use the sfThumbnail class provided by the plugin to create a thumbnail of each uploaded file. The best place to do this is in the setFilePath() method of the Photo class. Add the following to the Photo.php file:

// in lib/model/Photo.php    
public function setFilePath($value)    
{    
 parent::setFilePath($value);    
 $this->generateThumbnail($value);    
}    
public function generateThumbnail($value)    
{    
 parent::setFilePath($value);    
 $uploadDir = sfConfig::get('sf_upload_dir');    
 $thumbnail = new sfThumbnail(150, 150);    
 $thumbnail->loadFile($uploadDir.'/'.$this->getFilePath());    
 $thumbnail->save($uploadDir.'/thumbnail/'.$this->getFilePath(), 'image/png');    
}

The setFilePath method above first calls the setFilePath method defined in the BasePhoto class from which the Photo class inherits. Then it creates a 150x150px thumbnail based on the original file, and saves it under the uploads/thumbnail/ directory. In the generateThumbnail class, we used the sfConfig class to retrieve the path to the upload directory. The upload directory of the current application is accessible via the sf_upload_dir parameter. Note that the sfThumbnail plugin uses the GD extension, so you must enable it in your php.ini if it's not enabled yet. Also, in order for the save method to work, the uploads/thumbnail/ directory must exist, so don't forget to create it before you try to upload a new picture:

$ cd web/uploads    
$ mkdir thumbnail    
$ chmod 777 thumbnail

We also want the _photo partial column to use the thumbnail instead of the original picture, so edit the _photo.php as follows:

// in apps/frontend/modules/photo/templates/_photo.php    
<?php echo image_tag('/uploads/thumbnail/'.$photo->getFilePath()) ?>

Now try uploading new pictures, and you'll see that the generated photo module displays the thumbnail instead of the full-sized picture.

1566_fig9

We will also use a plugin to make the photo module secure. Symfony already has built-in security features to allow only authenticated users with special credentials to access a module, but the sfGuard plugin automates all the user management. Install it just like the sfThumbnail plugin, with the plugin-install command (remember to return to the root project directory first):

$ php symfony plugin-install http://plugins.symfony-project.com/sfGuardPlugin

The plugin comes with a module, but you can't access the module unless it's enabled in the application settings. Also, this module can replace the default login page that's bundled with symfony. Open the apps/frontend/config/settings.yml file, and add the following before the commented lines (comments in YAML start with #):

// in apps/frontend/config/settings.yml    
all:    
 .actions:    
   login_module:           sfGuardAuth    
   login_action:           signin    
 .settings:    
   enabled_modules:        [default, sfGuardAuth, sfGuardUser]

You also need to tell symfony to use the sfGuardPlugin for all the user security features. To do this, just change the parent class that the class myUser extends. myUser is the class that handles user sessions in symfony. It usually extends sfBasicSecurityUser, so change the myUser.class.php file as follows:

// in apps/frontend/lib/myUser.class.php    
class myUser extends sfGuardSecurityUser    
{    
}

You must also tell symfony that all the actions of the photo module now require authentication. To do so, create a file named security.yml in the modules/photo/config/ directory and write in:

// in apps/frontend/modules/photo/config/security.yml    
all:    
 is_secure: on

We're almost there! The sfGuardPlugin comes with a user management module, which allows the addition of new users, and the changing of their ids and passwords. Of course, the password is not stored in clear view in the database, as this would pose serious security risks. The user management module relies on a few database tables and model classes. A schema is included in the plugin, so all we need is the propel-build-all task to upgrade the model classes and the database with it. But be careful -- this task rebuilds the database from scratch, erasing all existing data. You probably already have data in the database (at least from the previous tests), so type the three following commands to dump the data into a YML file, clear the cache, build the model and database, and load the data into the database again:

> php symfony propel-dump-data frontend testdata.yml    
> php symfony cc    
> php symfony propel-build-all-load frontend

Tip: If, at this point, the command line throws a fatal error saying, "Call to undefined function imagecreatefromjpeg()", it means that the gd extension is activated in the php.ini used by the web server, but not in the php.ini used by the command line (usually in the php/ directory). Activate it in both, and the problem should go away.

That's it; the user security features are ready. Try to browse to http://localhost/sf_sandbox/web/frontend_dev.php/photo.

1566_fig10

You'll see an authentication screen asking for a login and a password. The sfGuardPlugin comes with a test user (id: admin, password: admin) so you can reach your module's pages even if you haven't created any users. Use these two values, and you can get to the photo module again.

If you want to add more users, or change the default id and password, make a request to the sfGuardUser module by entering the following URL: http://localhost/sf_sandbox/web/frontend_dev.php/sfGuardUser.

One last word before we focus on the end user interface. Every URL that we've explored so far has contained the filename frontend_dev.php. This is called the development environment front controller. Symfony has the ability to provide several environments for each application. In the development environment, for instance, the configuration is checked at every request, a lot of details are logged during the processing of the request, and these details are made available in the web debug toolbar (the grey line on the top-right corner of the window). Try clicking on its icons to see how useful this tool can be as you try to debug an application.

By default, the front-end application comes with another environment: the production environment. This environment is optimized for speed, so symfony skips all the logging and debugging work and proceeds directly to the rendering of the page. The production environment front controller is called index.php, so you can access it with the URL http://localhost/sf_sandbox/web/index.php/photo.

If you tried browsing the production environment before making any changes to this section, you will probably need to clear the cache by issuing the php symfony cc command. If you have mod_rewrite enabled on your server, take advantage of the rewrite rules bundled in the default project to call the following URL, which is equivalent to the previous one http://localhost/sf_sandbox/web/photo.

Try browsing the generated application in the production environment -- it will feel faster and more responsive. Environments are a great feature, giving you what you need when you need it: development tools when you're developing, and speed when your application needs to respond to real requests.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links