Code snippets for symfony 1.x

Navigation

Refine Tags

Snippets tagged "event"

How to trigger an event from a Model Class

[UPDATE]

I've found a cleaner way to deal with it :

sfProjectConfiguration::getActive()->getEventDispatcher()->notify(new sfEvent($this, 'foo.bar'))
 

The old version of this snippet is now useless, you don't need to read it.

[/UPDATE]

This snippet is not a tutorial on symfony events, but you can find some documentation in the book and or in this good tutorial.

The event dispatcher is a very powerfull tool, but you might meet the same issue than me if you want to use it from a Model Class.

Let's take the classic Author/Article project sample.

When an article is added, it might be interesting to trigger an "article.new" event. This event coud be listened by different actors.

Like for instance :

The most obvious place to trigger the event is the Article save() method. Here is the code for Doctrine (the logic is exactly the same for Propel):

Article.class.php

public function save(Doctrine_Connection $conn = null)
{
  if ($this->isNew())
  {
    // Let's trigger the event
    sfContext::getInstance()->getEventDispatcher()->notify(new sfEvent($this, 'article.new'));
  }
  return parent::save($conn);
}
 

Unfortunatly, this code won't work. If you try the "symfony doctrine:build-all-reload" command, here is the error that will be displayed :

Cli

sfException: The "default" context does not exist.
 

Why ? Because symfony tasks don't initialise the sfContext class. And for the moment (symfony version 1.2.4) I don't think there's a clean way to access to the dispatcher object from a Doctrine Class.

Here is my solution : let's build a (very) little singleton class that will provide the dispatcher ressource everywhere in the project, and even when sfContext is not avaible

yourProjectRoot/lib/Fedex.class.php

class Fedex
{
  static protected $instance;
  protected $dispatcher;
  /**
   * The singleton logic http://en.wikipedia.org/wiki/Singleton_pattern#PHP_5
   */
  static public function getInstance()
  {
    if (!self::$instance instanceof self)
    {
      self::$instance = new self;
    }
    return self::$instance;
  }
 
  public function setEventDispatcher(sfEventDispatcher $dispatcher)
  {
    $this->dispatcher = $dispatcher;
  }
 
  public function getEventDispatcher()
  {
    return $this->dispatcher;
  }
}
 

Of course, you first have to give to the Fedex class a link the delivery ressource. Let's do it with the very first class called by the script of the project :

yourProjectRoot/config/ProjectConfiguration.class.php

public function setup()
{
  // add after all your setup stuffs
 
  require_once(dirname(__FILE__).'/../lib/Fedex.class.php');
  Fedex::getInstance()->setEventDispatcher($this->dispatcher);
}
 

That's it, you're done. The Fedex class will deliver the dispatcher ressource everywhere in your project through Fedex::getInstance()->getEventDispatcher() And it works even when the sfContext class is not avaible

Article.class.php

public function save(Doctrine_Connection $conn = null)
{
  if ($this->isNew())
  {
    Fedex::getInstance()->getEventDispatcher()->notify(new sfEvent($this, 'article.new'));
  }
  return parent::save($conn);
}
 

The important thing is that this little class doesn't modify any part of the symfony event system. It just provide you an alternative way to access to it.

by Éric Rogé on 2009-02-23, tagged doctrine  event  orm 
(5 comments)

Ajax Autocomplete - how to trigger an event after selecting an option

The Problem

The Ajax helper function input_auto_complete_tag() is great stuff. You might have seen something comparable in Google Suggest. However, you might encounter some limitations when using it. Just imagine, you want to use it as a search field. Once you found the desired keyword, you might want to retrieve the whole record related to it. Unfortunately, after selecting an entry, the input field contains a search string, and mostly this is not unique in your database. As a consequence, you want to use the id of the record to perform the database select.

The Solution

First of all we need to have a technique to unambiguously identify all options of the AutoComplete field:

<ul>
<?php foreach ($object as $key => $value): ?>
  <li id="<?php echo $key ?>"><?php echo $value ?></li>
<?php endforeach; ?>
</ul>

It's simple: We just add an id attribute to the list element. Note that this example uses an associative array containing the unique id as key and the name (appearing as option) as value.

The trouble is now: how to access the id attributes of the list elements?

The input_auto_complete_tag() function can take an option called 'after_update_element' as a hook for a user-defined function. This receives 2 parameters:

(1) the autocompletion input field
(2) the selected item

For more Details take a glance at the documentation: http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter

By including this option in our input_auto_complete_tag() function, we have the right tool for accessing the list element and doing nice things:

<?php echo form_remote_tag(array(
      'url'    => 'yourModule/calledAction',
      'update' => 'resultarea',
      'loading'  => "Element.show('indicator')",
      'complete' => "Element.hide('indicator')",
    )) ?>
    <?php echo input_hidden_tag('unique_id', '') ?>
    <?php echo input_auto_complete_tag('phrase', '', 'yourModule/autoCompleteAction', array('autocomplete' => 'off', 'size' => '30'), array('use_style' => 'true', 'after_update_element' => "function (inputField, selectedItem) { $('unique_id').value = selectedItem.id; }"));   
echo submit_tag('Go') ?>
</form>

In the function definded for 'after_update_element' we set the unique_id attribute of the previously definded hidden field by accessing the 2nd parameter. This hidden field will then provide the unique_id within the target action.

by Sascha Wiener on 2006-07-21, tagged ajax  autocomplete  event 
(3 comments)