Trouble is, this relies on a convention rather than a standard - so it’s not much better (or really any different) than asking users to give their components a specific name.
Here’s another take on a way to find components by class-name:
<?php
abstract class CModule extends CComponent
{
...
/**
* @var array registry for getComponentByClass, where $className => $componentId
*/
protected $_componentRegistry;
/**
* Obtain a component by it's class-name rather than it's component id.
*
* Note that this works only when there is a single instance of a given component
* in the same application or module.
*
* @param $name the class-name of the component you wish to find
* @return mixed the initialized component, or null if no component with the given class-name was found.
*/
public function getComponentByClass($name)
{
if (!isset($this->_componentRegistry))
$this->buildComponentRegistry();
if (isset($this->_componentRegistry[$name]))
return $this->getComponent($this->_componentRegistry[$name]);
else
return null;
}
/**
* Builds the internal component registry, mapping class-names to component ids.
*/
public function buildComponentRegistry()
{
$this->_componentRegistry = array();
foreach ($this->_componentConfig as $id=>$config)
if (array_key_exists($config['class'], $this->_componentRegistry))
$this->_componentRegistry[$config['class']] = null;
else
$this->_componentRegistry[$config['class']] = $id;
}
}
}
Two important differences from my first idea:
-
There is no runtime overhead, unless an application/component actually needs this functionality, since the classname => component-id registry is built the first time the function is called.
-
Only components with a single instance will be registered - if you have two instances of the same application component in the same application or module, it cannot be found this way.
This is untested code still, just meant to demonstrate the idea.
One limitation of this implementation, is that only components that were configured using CModule::setComponents() can be found in this way. This could actually be seen as a benefit - the class-name registry is really only intended to find a particular type of component that has been configured for the application or module. If a component was assigned explicitly using CModule::setComponent(), the function that performed this call would already know the id it’s using, and thus would be able to find the component via it’s name.
Alternatively, here’s another (and much simpler) approach:
Simply make it convention, that all registered components are automatically registered both with their configured component id, and their class-name.
Once configured or registered, you could access the same component using Yii::app()->myManager or Yii::app()->CMyManager as you please.
The only potential problem with that idea, is that (as you suggested) some people may already be registering their components with the component’s class-name as it’s id. Of course this is only a problem if it’s not taken into account in the implementation.
I do not have a code sample for this idea, but let me know if you’d like to see one?