Jeśli w taskach symfony spróbujemy użyć kontekstu poprzez wywołanie sfContext::getInstance(), otrzymamy wyjątek klasy sfException z komunikatem 'The "default" context does not exist'. Klasa sfContext reprezentuje kontekst aplikacji i dlatego nie jest on inicjowany w linii poleceń. Dobrą praktyką jest NIE używanie sfContext::getInstance(). Zdarza się niestety, że nie mamy innego wyboru (np. gdy korzystamy z obcego pluginu).
Inicjalizacja kontekstu
Aby pozbyć się wyjątku musimy zainicjalizować kontekst przy pomocy sfContext::createInstance(). Będziemy do tego potrzebować konfiguracji aplikacji, czyli obiektu klasy sfApplicationConfiguration. Symfony automatycznie go utworzy, jeśli przekażemy do taska opcję z nazwą aplikacji (na przykład --application=frontend).
class toolsDosomethingTask extends sfBaseTask
{
protected function configure()
{
$this->addOptions(array(
new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name'),
new sfCommandOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'The environment', 'dev'),
new sfCommandOption('connection', null, sfCommandOption::PARAMETER_REQUIRED, 'The connection name', 'propel')
));
$this->namespace = 'tools';
$this->name = 'do-something';
$this->briefDescription = '';
$this->detailedDescription = '';
}
protected function execute($arguments = array(), $options = array())
{
if ($this->configuration instanceof sfApplicationConfiguration)
{
sfContext::createInstance($this->configuration);
}
if (sfContext::hasInstance())
{
$context = sfContext::getInstance();
}
}
}
Jeśli nie podamy nazwy aplikacji, właśność $this->configuration będzie obiektem klasy ProjectConfiguration. Z tego powodu przed wywołaniem sfContext::createInstance() powinniśmy upewnić się, że pracujemy z konfiguracją aplikacji (na przykład przy pomocy instanceof). Z kolei przed odwołaniem się do kontekstu dobrze jest sprawdzić metodą sfContext::hasInstance(), czy został wcześniej utworzony.
Wartość domyślna
Gdy zależy nam, aby konfiguracja aplikacji zawsze była obecna, możemy ustalić domyślną nazwę aplikacji:
new sfCommandOption('application', null, sfCommandOption::PARAMETER_REQUIRED, 'The application name', 'frontend')
Dzięki temu nie będzie konieczne wpisywanie jej w linii poleceń.
sfContext::getInstance() to zło
Jak zaznaczyłem we wstępie dobrą praktyką jest unikanie bezpośredniego odwoływania się do kontekstu. Bywa to trudne, ale należy mieć na uwadze, że używając singletona wiążemy klasy problematyczną zależnością. Dobre argumenty popierające tą tezę przedstawiono w artykule "Why sfContext::getInstance() Is Bad" i prezentacji "30 Symfony Best Practices (slajd 58)".