Wyjątek 'The "default" context does not exist.' w linii poleceń symfony

Ten wpis został napisany dawno temu i może być już nieaktualny.

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).

Default context does not exist

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)".

Jakub Zalas

Jakub Zalas

Architekt, Programista, Trener