Hooks In Yii

Hi,

I am building an application for multiple clients. I’d like to have one core application that serves as a basic core components and possibly some customisations for different clients to meet the different requirements.

I think one way to achieve this is via a hook that is inserted in the core application and call the function if it’s implemented. I’m not sure if Yii already has something like this in place.

Let say I want to prefix a product code for one client but not another.

For client A, I will install a core application with an extension which contains the hook functions.

For client B, I will install a core application without an extension.

The advantage of a hook is that if the hook function does not exist, it is simply being ignored. I know there may be a performance trade-off.

Example:

core application




class Product extends CActive Record {

  public function getProductCode() {

      $product_code = $this->product_code

      Hook::register('product_getProductCode', $product_code);

      return $product_code;

  }

}



Customisation for client A




class Client_Hook {

   function product_getProductCode(&$product_code) {

       // For this client, I need to prefix product code with 'Foo'

       $product_code = 'FOO-'.$product_code;


       // I dont need to return $product_code because it is passed by reference

   }

}



If you can suggest another way of achieving this please come forward. Basically I want to maintain a core application and be able to plug customisations in.

Thanks!

Just an idea





// Product model's behavior method

public function behaviors()

{

	return array(

		'ProductVariations' => array(

			'class' => 'path.to.ProductVariationBehavior' // This is the default behavior for ALL applications

		)

	)

}


// Base behavior

class ProductVariationBehavior extends CBehavior

{

	public function getProductName()

	{

		return $this->owner->productName;

	}

}


// Client Foo specific behavior

class ClientFooBehavior extends ProductVariationBehavior

{

	public function getProductName()

	{

		return "FOO-" . parent::getProductName();

	}

}


// Client Bar specific behavior

class ClientBarBehavior extends ProductVariationBehavior

{

	public function getProductName()

	{

		return "BAR-" . parent::getProductName();

	}

}


// To implement ClientFooBehavior & ClientBarBehavior, attach these to the model instance in the early stages of the app's lifecycle.

// Sorry, can't think of the best place to attach them yet - somewhere central where all the client specific logic can be easily accessed. base controller's beforeAction??

// Product::model()->attachbehavior('ProductVariations', new ClientFooBehavior());

// This will be attached first so it will override the Product model's default "ProductVariations" behavior.



Thanks, not a bad idea actually. But the problem is the core application is not aware of any of the customisations, so lets say SiteController is implemented in the core application and initialise the Product model there, it won’t know any of the clients customisation and therefore unable to attach the behaviors

I’ve reworked the behaviors and put together some small files. After making the necessary changes to your model, you can switch the client specific code by altering the config file. I assume the config file will be unique to all clients.

3938

hooks.zip

The hooks manager is very simple and probably needs some rework but it should get you up and running. Basically, it’s a container, that is configured through the config file, for a specific client. Your model then calls this component and attaches the specified behavior to itself.




// Add this to your config's imports

'ext.hooks.behaviors.*'


// Add this to your config's components


'hookManager' => array(

                'class' => 'ext.hooks.HookManager',

                'hooks' => array(

                    'Product' => array(

                        'behaviors' => array(

                            'ProductVariation' => 'ClientFooBehavior' // Change this for each client

                        )

                    )

                )

            )


// Add this to the model's behavior method


'ProductVariation' => array(

                'class' => Yii::app()->hookManager->hooks[get_class($this)]['behaviors']['ProductVariation']

            ),



Now you should be good to go.





<?php echo Product::model()->getProductName(); // FOO-I am the base application


$product = Product::model()->findByPk(12);

echo $product->getProductName(); // FOO-I am the base application


?>



Thank you very much! That’s brilliant.

It’s also possible to use a name convention to check if the hook exists, but may have a performance hit.

When I come around to implementing this, I will try to create a generic hook extension and maybe release it to Yii community. Just wondering if anyone out there wants to have this kind of extension.

Think it could be useful, yes. If you post it, I imagine you’ll find that people use it :slight_smile: