If you need to remove a package without removing dependent packages, here is the command you need:

sudo dpkg -r –force-depends

I have no idea why this is so hard to find – you could spend an hour reading the dpkg man page and never figure it out, and most posts on forums don’t seem to even understand this issue. There seems to be an attitude that you shouldn’t do this, as though you are morally bound to rules about what software you may and may not have on your own computer. I have on several occasions had to completely remove and reinstall corrupted files. The only logical way to do this is to ignore dependency warnings. Besides, I use Linux because I don’t like people making rules about what I ought to do with my own machine. I hope this post helps someone in the same fix as I am.

The problem: make symfony use PHP’s default session behavior.
Symfony session handling is based on timed sessions – you set a time
after which the session will expire – but the default PHP behavior is to
expire when the user closes the browser window. This is also the most
commonly desired behavior for sessions. The drawback of using a timed
session is that it could expire while the user is still on the site.
This is an issue in LectureTools,
because students may sit for an hour or more without loading a new
page, and they may even have logged in before class. You can solve this
little problem easily if you are using symfony 1.1 (currently in beta).
Just set the timeout to false in settings.yml:

all:
  .settings:
    timeout:    false

But if you are using the stable 1.0 branch of symfony, this will do just
the opposite – it will make your sessions time out immediately! To make
this work, we have to override sfBasicSecurityUser‘s initialize() method. I will describe two ways
to do this; one is a short hack, the other is longer and somewhat more proper.

Here’s the short way:

class myUser extends sfBasicSecurityUser
{
  public function initialize($context, $parameters = null)
  {
    if (sfConfig::get('sf_timeout') == 0) {
      // session will expire if window is open for a day
      sfConfig::set('sf_timeout', 86400);
    }

    return parent::initialize($context, $parameters);
  }
}

This works because the sf_timeout setting is not used by
any other class (at the moment), so changing it doesn’t have any side
effects. If you set your timeout to 0 or false, symfony will always
think you have set the session timeout to 24 hours, but the session will
actually expire when the user closes the browser window.
If you are not comfortable with “hacks” like the above, you could copy the initialize() method from
sfBasicSecurityUser, change it in the appropriate place, and skip calling the parent constructor altogether.
Unfortunately, sfBasicSecurityUser calls its parent constructor, so you have to rewrite them both:

class myUser extends sfBasicSecurityUser
{
  public function initialize($context, $parameters = null)
  {
    $this->context = $context;

    $this->parameterHolder = new sfParameterHolder();
    $this->parameterHolder->add($parameters);

    $this->attributeHolder = new sfParameterHolder(self::ATTRIBUTE_NAMESPACE);

    // read attributes from storage
    $attributes = $context->getStorage()->read(self::ATTRIBUTE_NAMESPACE);
    if (is_array($attributes))
    {
      foreach ($attributes as $namespace => $values)
      {
        $this->attributeHolder->add($values, $namespace);
      }
    }

    // set the user culture to sf_culture parameter if present in the request
    // otherwise
    //  - use the culture defined in the user session
    //  - use the default culture set in i18n.yml
    if (!($culture = $context->getRequest()->getParameter('sf_culture')))
    {
      if (null === ($culture = $context->getStorage()->read(self::CULTURE_NAMESPACE)))
      {
        $culture = sfConfig::get('sf_i18n_default_culture', 'en');
      }
    }

    $this->setCulture($culture);

    // read data from storage
    $storage = $this->getContext()->getStorage();

    $this->authenticated = $storage->read(self::AUTH_NAMESPACE);
    $this->credentials   = $storage->read(self::CREDENTIAL_NAMESPACE);
    $this->lastRequest   = $storage->read(self::LAST_REQUEST_NAMESPACE);

    if ($this->authenticated == null)
    {
      $this->authenticated = false;
      $this->credentials   = array();
    }
    else
    {
      // Automatic logout logged in user if no request within [sf_timeout] setting
      if (0 != sfConfig::get('sf_timeout') && null !== $this->lastRequest && (time() -
$this->lastRequest) > sfConfig::get('sf_timeout'))
      {
        if (sfConfig::get('sf_logging_enabled'))
        {
          $this->getContext()->getLogger()->info('{sfUser} automatic user logout due to timeout');
        }
        $this->setTimedOut();
        $this->setAuthenticated(false);
      }
    }

    $this->lastRequest = time();

  }
}

That should do it!

I have redone the sfPropelTestPlugin, and it is now sfModelTestPlugin, with support for Doctrine and Propel 1.3! Also new Рyou can now specify the test data file/directory at runtime, allowing for more flexibility with your tests. I want to thank Anders Betn̩r and my readers for bug reports and patches!

If you’ve ever tried to write a symfony unit test for a model class – or for any piece of code that interacts with the database – then you know what a headache it can be. sfPropelTestPlugin to the rescue! This plugin loads all the necessary symfony components for database interaction, and goes a step further: test data is automatically reloaded to the test database at the beginning of each test case, so you don’t have to worry about your tests interacting with each other. Here’s an example of a unit test written with sfPropelTestPlugin:

class myUnitTest extends sfPropelTest
{
  public function setup()
  {
    $this->bob = UserPeer::retrieveByPK('bob');
  }

  public function teardown()
  {
    $this->diag('Test method complete!');
  }

  public function test_user()
  {
    $this->is($this->bob->getId(), 'bob', 'Bob exists!');

    $user = new User();
    $user->setFirstName('Joe');
    $user->setLastName('Smith');
    $user->setUsername('joe');
    $user->save();

    $joe = UserPeer::getBy(UserPeer::USERNAME, 'joe');
    $this->isa_ok($joe, 'User', 'Joe exists!');
  }

  public function test_dataDelete()
  {
    $this->is($this->bob->getId(), 'bob', 'Bob still exists!');

    $joe = UserPeer::getBy(UserPeer::USERNAME, 'joe');
    $this->ok(!$joe, 'Joe no longer exists.');
  }
}

$test = new myUnitTest();
$test->execute();

If you’ve written tests in Ruby on Rails, the above should look familiar. If not, let’s go through the code:

The first two lines are setup: The first line tells symfony what application to test – in this case, “myApp” – and the second line includes the code we need to test against the database. Next we define our “test case” – a class that extends sfPropelTest, which is itself a child of lime_test. Every method that begins with “test_” will be called in turn, with our test data being reloaded between each call. Also, the setup() method, if defined, will be called immediately before each test method, and the teardown() method, if defined, will be called immediately after. The last two lines create a new instance of our test suite, and call its execute() method, which runs our tests.

There you have it – a quick and painless way to run unit tests in symfony. One less excuse for not writing them!

I have updated my plugin for doing model-based validation in symfony. The new plugin uses the Propel builders instead of behaviors, so it is now called sfPropelValidatePlugin instead of the former (unwieldy) name sfPropelValidateBehaviorPlugin. If you have not investigated the Propel builder classes, I suggest you give them a look. By overriding the default classes used to build your Propel object and peer classes, you can write your modifications directly into your model’s base classes. This is a much cleaner and more readable solution than using Propel behaviors, and you avoid the performance hit that behaviors incur.

The default Propel builders can be found in the symfony source in these places:

symfony/addon/propel/builder/sfObjectBuilder.php
symfony/addon/propel/builder/sfPeerBuilder.php

The classes these inherit from are buried. They can be found here:

symfony/vendor/propel-generator/classes/propel/engine/builder/om/php5/PHP5ComplexObjectBuilder.php
symfony/vendor/propel-generator/classes/propel/engine/builder/om/php5/PHP5ComplexPeerBuilder.php

« Older entries