Skip to content
Sep 3 10

Doctrine and Oracle under Windows

by Hidde Braun

For one of our clients we are developing a touchscreen application with a symfony backend (Flash + AMFPHP amongst others).

One of the technical requirements is that it has to work with an Oracle database. Since we don’t have any experience whatsoever with Oracle, this was a tough cookie to crumble. This post is meant to be a quick start for other developers who have to use symfony/Oracle in a Windows environment.
Below are the most important things i learned and figured out on my “journey” towards a working Windows/Oracle/symfony setup.

1. Install the free Oracle Express Edition database

I downloaded the OracleXEUniv.exe Univeral edition from this page.
After installation you can login at this (local) url: http://127.0.0.1:8080/apex

Or use a pre-installed database, and get the right connection parameters from the DBA.

2. Create a user in the database with the right permissions

I Just gave the new user all permissions so the symfony doctrine:build -all command will be able to create triggers, sequences etc. Of course you have to ask (or beg) your Oracle DBA to give you these permissions so you can still use your symfony cli commands

3. Download the Oracle Instant Client from the Oracle website

You can find all sorts of downloads here (you need to create an account to download) Important thing is that you have to add the installation path to your windows PATH environment variable.

This is necessary so the Oracle PHP extension can locate the right libraries to work with (which are included in the Instant Client software).

4. Use the free SQL Developer program or a similar db management program

I used SQL Developer to manage / inspect the Oracle database. There will be other programs i don’t (yet) know about. This worked for me.

5. Configure the database connection

I had some trouble connecting to the database, since with Oracle you can connect in a few ways.

There is a file called tnsnames.ora where you can define all connection settings under a short SID (service id). You can then connect to the database, referring to this shortcut SID. The client software (i suppose) reads the tnsnames.ora file an does the rest. Because the express edition always has the same SID (which is XE) it will be simple to connect.

The location of this file is (in my case):
<Oracle-XE-install-dir>\xe\app\oracle\product\10.2.0\server\NETWORK\ADMIN\tnsnames.ora

There i found the “XE” SID for the Oracle Express Edition DB i just installed:

XE =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = XE)
)
)

You probably will get this SID from your DBA.

Don’t use the (experimental) Oracle PDO driver (crashes, crashes…)

Of course it states on the PHP Oracle PDO manual page that it’s highly experimental.  But somehow (stubbornness?) i kept trying this, and believing that i did something wrong myself, or that my configuration was faulty etc. etc. Until i stumbled upon this post . Many thanks for that. This put me on the right track finally.

So,  use the latest  oci8 driver from the windows PECL build page at  http://downloads.php.net/pierre

When creating the connection, Doctrine will first check if the PDO extension is enabled. If it is enabled (most servers will have this enabled is suppose?) it will check if a PDO driver is available. So if you use oci: in your DSN it will use the experimental PDO OCI extension (don’t, don’t!) If PDO is not loaded or if no matching PDO driver is found, it will try to create an instance of Doctrine_Adapter_<DB_TYPE>. In our case this is just fine, because we want a Doctrine_Adapter_Oracle to connect to our database. SO that’s why you have to use oracle: als the dbtype in your DNS.

For more information and details, check the post i mentined above

Just to be clear, here’s the combination of enabled / disabled extensions in my php.ini:

...
extension=php_mysql.dll
extension=php_oci8.dll
extension=php_pdo.dll
extension=php_pdo_mysql.dll
;extension=php_pdo_oci.dll
;extension=php_pdo_oci8.dll
...

So use the oracle: db type in your databases.yml. This is the only db type setting that will use the right oci extension and not the PDO one. Here’s the corresponding databases.yml setup:

doctrine:
 class: sfDoctrineDatabase
 param:
   dsn: oracle:dbname=//127.0.0.1/XE;charset=AL32UTF8
   username: yourdbuser
   password: yourdbpass
   attributes:
     quote_identifier: true

Other things

Date formats / decimals.

I had some trouble with decimals, because the default setting , (comma) and not a . (dot) as the decimal separator.
Maybe this can be done in an easier way, but i created a trigger to achieve this. This trigger will be executed after every logon. I also added the preferred way for dates, but i believe symfony already tries to set this before every query.

  CREATE OR REPLACE TRIGGER "DRIEBIT_CUSTOM_FORMATS"
AFTER LOGON ON DATABASE
BEGIN
  execute immediate 'alter session set nls_numeric_characters = ''. '' ' ;
  execute immediate 'alter session set nls_date_format = ''YYYY-MM-DD HH24:MI:SS'' ' ;
END;
/
ALTER TRIGGER "DRIEBIT_CUSTOM_FORMATS" ENABLE;

N.B. In the live environment this wasn’t necessary because it had already been done, but out of the box i had to do this to be able to succesfully save decimal values.

Column types

Because our project didn’t need to store large amounts of textual data, i could get away with using the standard string column type (which gets translated to the VARCHAR2 type in Oracle).

But there are other column types like CLOB (Character Large Object) which can store up to 8 Tb (or even more)  I don’t know how well this works with Doctrine though.

Purge Recyclebin…

In the SQL developer tool i noticed (after running the doctrine:build commands a few times) a lot of “old” database objects / triggers / sequences.
After some reseacrh i figured out that these could be purged with the query: PURGE RECYCLEBIN;
I don’t know if this is Oracle specific behavior or just a feature of the SQL Developer tool.

I will  try to update this post with new insights, corrections etc. as my insight in the combination Symfony/Oracle/Windows evolves.

Please let me know if you have any additions, clarifications, comments or corrections to this post.

Sep 1 10

Ajax Filemanager linked to Symfony sfGuard authentication

by Matthias Noback

PHPLetter.com created an Ajax Filemanager plugin for the TinyMCE rich text editor. The filemanager is very insecure. By default, anybody can upload, move or delete files. Luckily, PHPLetter provides us paranoid developers with a way to secure the filemanager (“If you have security issue concern, you could turn the access control on”). In my opinion, everybody should have “security issue concern” when it comes to online filemanagers. Because Driebit uses the Symfony framework with the sfGuardPlugin/sfDoctrineGuardPlugin, I thought it would be nice to link the login system of the Ajax Filemanager to the sfGuardUser authentication system. I will show you how to accomplish this.

First, go to the directory that contains the filemanager plugin files, probably /web/js/tinymce/plugins/ajaxfilemanager/inc/config.base.php and so that the corresponding lines look like this:

define('CONFIG_ACCESS_CONTROL_MODE', true);
define("CONFIG_LOGIN_USERNAME", '98c0vjsfniciwefuosd8v7u8jxsd8fv'); // a random username
define('CONFIG_LOGIN_PASSWORD', 'cm9sf8nwm9sfkj3iusdfhsdhkfyusfuyu93rhjkf'); // a random password

Then open the file config.php in the same directory and disable the statement session_start by turning it into a comment. It should look like this:

if(!isset($_SESSION))
{
  //session_start();
}

Finally we have to change the way the Ajax Filemanager handles the authentication. In the same directory, open the file class.auth.php and replace the contents of the isLoggedIn method, with a few lines of code that instantiate a Symfony context (in this example it is a backend application in a production environment) and ask the current user if it is authenticated.

function isLoggedIn()
{
  require_once(dirname(__FILE__).'/../../../../../../config/ProjectConfiguration.class.php');
  $configuration = ProjectConfiguration::getApplicationConfiguration('backend', 'prod', false);
  $context = sfContext::createInstance($configuration);
  return $context->getUser()->isAuthenticated();
}

If your Ajax Filemanager files are in a different the directory than the one mentioned here (/web/js/tinymce/plugins/ajaxfilemanager), you may have to change the abovementioned path to the ProjectConfiguration.class.php file.

Aug 27 10

Translatable strings used in the time_ago_in_words() helper function

by Matthias Noback

I wanted to translate the strings in the symfony helper function time_ago_in_words(). For future reference and for anybody out there who would like to translate all the strings that originate from that function, you will find the strings original strings and their dutch translations, for use in messages.xml.

<trans-unit id="56">
 <source>less than a minute</source>
 <target>minder dan een minuut</target>
</trans-unit>
<trans-unit id="57">
 <source>1 minute</source>
 <target>1 minuut</target>
</trans-unit>
<trans-unit id="58">
 <source>less than 5 seconds</source>
 <target>minder dan 5 seconden</target>
</trans-unit>
<trans-unit id="59">
 <source>less than 10 seconds</source>
 <target>minder dan 10 seconden</target>
</trans-unit>
<trans-unit id="60">
 <source>less than 20 seconds</source>
 <target>minder dan 20 seconden</target>
</trans-unit>
<trans-unit id="61">
 <source>half a minute</source>
 <target>een halve minuut</target>
</trans-unit>
<trans-unit id="62">
 <source>less than a minute</source>
 <target>minder dan een minuut</target>
</trans-unit>
<trans-unit id="63">
 <source>1 minute</source>
 <target>1 minuut</target>
</trans-unit>
<trans-unit id="64">
 <source>%minutes% minutes</source>
 <target>%minutes% minuten</target>
</trans-unit>
<trans-unit id="65">
 <source>about 1 hour</source>
 <target>ongeveer 1 uur</target>
</trans-unit>
<trans-unit id="66">
 <source>about %hours% hours</source>
 <target>ongeveer %hours% uur</target>
</trans-unit>
<trans-unit id="67">
 <source>1 day</source>
 <target>1 dag</target>
</trans-unit>
<trans-unit id="68">
 <source>%days% days</source>
 <target>%days% dagen</target>
</trans-unit>
<trans-unit id="69">
 <source>about 1 month</source>
 <target>ongeveer 1 maand</target>
</trans-unit>
<trans-unit id="70">
 <source>%months% months</source>
 <target>%months% geleden</target>
</trans-unit>
<trans-unit id="71">
 <source>about 1 year</source>
 <target>ongeveer 1 jaar</target>
</trans-unit>
<trans-unit id="72">
 <source>over %years% years</source>
 <target>meer dan %years%</target>
</trans-unit>
Aug 24 10

Is your task running out of memory?

by Jean-Marie de Boer

Sometimes when you execute a task in Symfony, it may run out of memory. Resizing images is a prime example. You could of course tweak php.ini to allow scripts to consume more memory, but you can also overwrite the ini values on the command line like so:

php -d memory_limit=1024M symfony [your-task]

Or, overwrite several values:

php -d memory_limit=1024M -d max_execution_time=0 symfony [your-task]
Jul 27 10

The form.post_configure event

by Matthias Noback

You may find yourself copying and pasting code in the configure method of several forms. For example, when you wish to change the standard format of a sfWidgetFormDate widget. for all the forms you have in your back-end application. Of course you can extend the widget class, and set the format option, but you can also use the symfony event form.post_configure to loop through all the form’s widgets and set options for them. In your application configuration class (you may find this class in /apps/backend/config/backendConfiguration.class.php, if your application is called “backend”) modify the code as follows:

class backendConfiguration extends sfApplicationConfiguration
{
  public function configure()
  {
    // connect to the form.post_configure event
    $this->dispatcher->connect('form.post_configure', array($this, 'listenToFormPostConfigure'));
  }

  /**
   * Listens to the form.post_configure event and dispatches the call to appFormMethods::postConfigure
   */
  static public function listenToFormPostConfigure(sfEvent $event)
  {
    $form = $event->getSubject();

    $callable = array('appFormMethods', 'postConfigure');
    call_user_func($callable, $form);
  }
}

Then, create a file, for example in /lib/event/, named appFormMethods.class.php with an abstract class appFormMethods and one static public method postConfigure. This is an example of the kind of things you may want to do in the appFormMethods::postConfigure method:

abstract class appFormMethods
{
  static public function postConfigure(sfForm $form)
  {
    // define default options for date widgets
    $date_format = '%day%/%month%/%year%';
    $date_empty_values = array('day' => 'day', 'month' => 'month', 'year' => 'year');

    // define default options for time widgets
    $time_format = '%hour%:%minute%';
    $time_empty_values = array('hour' => 'hours', 'minute' => 'minutes');

    // loop through all the form fields
    foreach ($form as $name => $form_field)
    {
      /* @var $form_field sfFormField */
      $widget = $form_field->getWidget();

      // set default format for each date/time widget
      switch (get_class($widget))
      {
        case 'sfWidgetFormDate':
          $widget->setOption('format', $date_format);
          $widget->setOption('empty_values', $date_empty_values);
          break;
        case 'sfWidgetFormTime':
          $widget->setOption('format', $time_format);
          $widget->setOption('empty_values', $time_empty_values);
          break;
        case 'sfWidgetFormDateTime':
          $widget->setOption('date', array('format' => $date_format, 'empty_values' => $date_empty_values));
          $widget->setOption('time', array('format' => $time_format, 'empty_values' => $time_empty_values));
          break;
        case 'sfWidgetFormInputText':
          if (!$widget->getAttribute('size'))
          {
            $widget->setAttribute('size', 45);
          }
          break;
      }
    }
  }
}

We loop through all the form’s fields and do specific things based on the type of widget that is involved. This may also be the place to globally change options for the form’s validators. The nice thing is: this way it is possible to change options of widgets and validators after all setup and configure methods of a form have been called, so by using the form.post_configure event you can override widget/validator settings for every form in the application.

Jul 26 10

URL routes with or without a trailing slash

by Jean-Marie de Boer

Say you have defined a route like so:

news:
  url:   /news
  param: { module: news, action: index }

This will be matched by http://something.something/news, but not by http://something.something/news/
You might add an additional route with a trailing slash, but you could also simply use this rewrite rule in the .htaccess file:

RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]
Jun 25 10

Overriding column getters in your Model [Updated]

by Sander Coolen

In my first days as a Symfony newbie I got to work on a relatively small and simple project. My experience with MVC, ORM and Zend Framework helped me in finding my way around Symfony and kept the learning curve quite smooth. However, there were and are some architectural oddities that in my opinion are bugs or at least OO-fallacies, but might as well be there for a reason and I just lack the knowledge to wrap my head around them.

One of the problems I stumbled upon had to do with overriding getter and setter methods in my Model classes.

Lets say I have a class with a name and a display_name property. My model class would now have two getters: getName() and getDisplayName(). What I want to achieve is that getName returns its display-name (if set) or else returns its name. This is what I coded and expected to work:

public function getName()
{
  if (null !== $this->display_name) // or whatever to test for
  {
    return $this->getDisplayName();
  }
  return parent::getName();
}

What actually happened was a fatal error:
Maximum function nesting level of ’100′ reached, aborting!

Somehow the call to its parent gets resolved somewhere back to the subclass. Weird…

Update
What Doctrine does isn’t so bizarre after all: if someone created its own getters then you probably would want your ORM to use them. That’s why they’re there. However, it’s not very nice it completely ignores any subclassing you did.

A quick workaround would be to create a new function. Something like:

public function getDisplayNameOrReallyRealNamePleaseDontCrash()
{
  ...
  return parent::getName();
}

The above would indeed solve my problem, but I still don’t know what the [insert Vuvuzela noise] is going on!

A quick dive into the Doctrine plugin classes learned the following:

  1. My Model base class (parent in this case) doesn’t have an actual getName() method either
  2. There’s a magic __call method that looks for getters and setters and forwards them to a generic get or set method in Doctrine_Record
  3. The generic get in this case, checks to see if the field name it wants to retrieve has custom accessors, which it obviously has, because that’s how we got there in the first place
  4. If it finds one (which it will) it calls it and returns the value.Goto and repeat 1 until my pants drop

Unless rewriting Doctrine, which is no need for, there is no way around this. That is, as far as I know. Another workaround, that is a little bit nicer than the previous one would be something like this:

public function getName()
{
  if (null !== $this->display_name)
  {
    return $this->getDisplayName();
  }
  return parent::_get('name'); // directly shove it up his...
}

One of many foils in my first couple of weeks. For me Symfony is a bit like a baby. Everybody can play with it and there will be shit all over the place, but in the end you get a lot in return…

Jun 18 10

Dutch PHP Conference wisdom, applied to working with the symfony framework

by Matthias Noback

Last week I was one of the several hundreds of PHP developers who traveled “all te way” to Amsterdam for the Dutch PHP Conference 2010. Though I had the impression that many PHP developers are using the symfony framework for their web applications, the speakers at this conference were friendlier towards the “father of the framework”, Fabien Potencier, than towards the framework itself. Fabien is a much admired developer himself, who is very conscious about software architecture, latest trends in PHP development and also is aware of the importance of fully covering the framework’s code with unit tests. In this article I will try to apply to the symfony framework, several comments on PHP programming and frameworks that I heard during this conference.

A few characteristics of the symfony framework don’t encourage the average PHP developer to bring forth high quality code. A framework by itself doesn’t ask of the developer who is working with it to fully take advantage of the whole programming language, in this case PHP. Many of the common tasks a developer has to complete, are for more than 50% provided by the framework itself, e.g. handling requests, URL parsing, redirecting, form handling, etc. The other half of the task at hand can be easily completed using a small subset of the PHP language, combined with some nice helper functions. This way, common tasks can be done very quickly, but the developer is also encouraged to complete the less common tasks, using the same familiar subset of the PHP language, and the tools provided by the framework over and over again. It then becomes difficult to switch to another framework or no framework at all, and still accomplish great things, because in those situations the developer can’t depend on the familiar and very convenient framework components anymore.
To stay aware of the endless possibilities of the PHP language itself, and to become not too dependent on the (symfony) framework, I encourage developers to try and learn to master their task, not only to complete the task (a phrase borrowed from Jon Jagger). Try for example using the great Standard PHP Library (SPL) classes, exceptions and functions in your code.

While learning all these great new things about the programming language, and while reading other people’s code (for example the symfony code base) you’ll become a better programmer. This makes it easier to refactor your code, which means implementing smarter or more efficient ways to do something. Refactoring – when done correctly – improves at once the readability, maintainability, and extensibility of your code, mostly by dividing large functions into several smaller ones and relocating parts of your code that belong to different or yet unexisting classes. Thus every method gets one small task, which can be easily understood by a code reviewer, can also be more easily changed by a developer and may also be much easier to extend, without copying the entire content of the parent method that is overwritten.
All the abovementioned characteristics of good refactoring seem to be applicable to the symfony framework code base. Nevertheless, symfony’s admin generator doesn’t do a good job when it comes to readability, maintainability and extensibility. Every symfony developer knows this. When he wishes to change the behavior of even the smallest part of the admin generator, he almost always ends up copying large parts of the generated code and changing only small parts of it. “This is not very D.R.Y.” as a critical code reviewer might say. One step in the right direction has of course been made, by providing the admin generator configuration and helper classes. These are nice examples of how the whole code base of the admin generator could and should be cut up into smaller pieces, which only handle a small part of the business logic, and thus could easily be extended by the PHP developer who is working with the generated module.

When it comes to another part of the framework, the symfony developers seem to be doing exactly the opposite. They are putting a lot of effort in decoupling and making the framework code base less explicit and more flexible. With Symfony 2, the biggest part of the framework’s core objects will be created and managed by a “dependency injection container”. While this allows the developer to make his own choices about implementation, some speakers at the Dutch PHP Conference worried about this tendency to “over-abstract”. It is a very good thing to avoid hard coupling in your classes, but using a dependency injection container makes your application also dependent and in a sense again “hard coupled”. This brings up the question if there should be a “dependency injection container factory” and there is no reason why one should not want a “dependency injection container factories factory”, and so on. Except for the fact that this should make it very difficult to be a PHP developer and live happily at the same time.

Another way in which symfony falls somewhat short at the moment, is the lack of a good ORM implementation. Of course this is not really a fault of the framework itself, but as it can only be integrated with two ORM implementations, the shortcomings of these implementations reflect on the framework itself. Doctrine as well as Propel in their 1.x versions are based on the “Active Record” design pattern, in which every model object that stands for a record in a database table, inherits many properties and methods from parent classes, that handle the way the object’s properties should be saved in the database table. This is bad for testing purposes, because the object and it’s persistent state in the database are tightly coupled, but also brings a lot of overhead into a project. Luckily, with Symfony 2 the new version of Doctrine (version 2) will be shipped, which is a completely redesigned ORM, based on the “Data Mapper” design pattern. This means objects don’t inherit from an “Active Record” class and can be instantiated apart from any connection to a database. This also means that model object classes are lean and mean and can more easily be subjected to unit tests, that they may extend other classes than the “Active Record” class and in theory may have nothing to do with persistent data in the first place. When it seems a good idea to store the object’s data to a database, this may be implemented at some time in the future.

Though much of the above can be seen as critical notes on symfony, I wish to state that using symfony is in the end a great idea. It is a “full stack framework”, which enables PHP developers to accomplish much more greatness than they would have been able to when only using the standard set of PHP functions and writing only PHP code that is executed serially. My comments on the framework can be “redirected” mostly to shortcomings of the developer himself or to third party software on which symfony relies. Other shortcomings will hopefully be addressed in future versions of symfony (or Symfony, as it should be spelled when the second version arrives).

One way in which symfony really makes the developer’s life better, which also is a highly underrated and not too often used feature of symfony, is it’s doctrine/propel:data-load task and the way it allows developers to define test data in YML-files, called fixtures. One way to enhance these fixtures is by using PHP functions in them, because they will be parsed by the PHP interpreter before being loaded into the database. Thus, you can create functions for generating random strings, numbers, etc. and paste them in the fixtures, so you can easily create a lot of random objects for test purposes. Like this:

<?php
function someRandomStringFuction()
{
  // ...
  return $a_random_string;
}
Product:
<?php
for ($i = 0; $i <= 100; $i++)
{
  ?>
  Product_<?php echo $i; ?>:
    name: ‘<?php echo someRandomStringFunction(); ?>’
  <?php
}
?>

Before executing the data-load task, it may be a good idea to run the PHP interpreter

php data/testfixtures/products.yml

to see if your PHP code generates the YML result you are looking for (and no errors).

After that you can run

php symfony doctrine:data-load data/testfixtures/products.yml

or the equivalent task for Propel.

Jun 4 10

Disabling output escaping in module or action

by Hidde Braun

Every now and then i get frustrated because all data in my view template is escaped by on of the symfony escaper decorator objects (sfOutputEscaperObjectDecorator, sfOutputEscaperArrayDecorator) I didn’t find a handy method to disable this. So the solution below is what works for me.

The way to disable this per module or action is to simple set the configuration value for output escaping to false, either in the preExecute method or in a specific action, like this:

public function executeEscapingtest(sfWebRequest $request)
{
  sfConfig::set('sf_escaping_strategy', false);
  [...]
}

All variables will be available unescaped in your view. Of course you should be careful with this options, since output escaping your user submitted content is still a very wise thing to do, obviously.

For more information see the escaping strategy options in the symfony reference.

Edit by JM:

Two additional ways to achieve this:

// the escaped output
echo $output;

// disable escaping
echo $sf_data->getRaw('output');

// disable escaping from class method output
echo $object->getSomething(ESC_RAW);
Jun 4 10

PHP sessions from Flash

by Jean-Marie de Boer

Normally, when you have a user that is authenticated (via sfGuard for instance), the session cookie is used to track the session.

However, when the user is submitting some data via a Flash movie embedded in your site this will not work, at least not in all browsers. This is because in some browsers Flash does not use the same cookie as the browser, so these requests are handled in a seperate session.

The solution in to have Flash submit the current session ID and then, in Symfony, explicitly start the session with that ID.

The first part is quite easy, you can simply pass the value returned by session_id() to Flash using a Flashvar, or implement some service call that provides it. Flash can then submit this in a GET or POST variable called (for instance) ‘session_id’.

In order to have Symfony use this ID, you need to overwrite the storage class.

The standard file lives here:
lib/vendor/symfony/lib/storage/sfSessionStorage.class.php

Copy the file to:
lib/vendor/driebit/driebitSessionStorage.php

Note: You need to have a correct autoload.yml to autoload from this directory.

Rename the class, and extend sfStorage:

class driebitSessionStorage extends sfStorage {

In the initialize method, read the session id from the request:

public function initialize($options = null) {
  $flash_session_id = sfContext::getInstance()->getRequest()->getParameter('session_id');
  ...

You then need to explicitly start the session with the ID

if ($flash_session_id) {
  session_id($flash_session_id);
} else {
  if (!(boolean) ini_get('session.use_cookies') && ($sessionId == $this->options['session_id'])) {
    session_id($sessionId);
  }
}

Lastly, you need to tell Symfony to use your storage, in factories.yml

all:
  storage:
    class: driebitSessionStorage
    param:
      session_name: mySession

That’s all there is to it!