Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Overwrite service for terminal script

Hi everybody, I have a service 'translation' like that

$di->setShared(
'translation',
function () use ($config, $di) {
$code = getLanguage();

/*
* Ahora es lo que va a funcionar
*/
$path = APP_DIR . "/lang/{$code}/{$code}.php";
if (!file_exists($path)) {
trigger_error("You must specify a language file for language '$code'");
$path = APP_DIR . '/lang/es/es.php';
}

$messages = [];
include $path;
//codump($messages);
if (!is_array($messages)) {
trigger_error("Translation data [{$path}] for language '$code' must be an array. Got: " . gettype($messages));
}

/*
* Utilizamos nuestra clase hipervitaminada Translate
*/
return new \Colindar\Translate\Translate(['content' => $messages]);
}
);

The problem is that getLanguage use cookies and:

$request = new Phalcon\Http\Request();
$code = $request->getBestLanguage();

to know what is te languajeĀ“s user.

Now in my aplication, the user can select your languaje and I save that in my bbdd.

how can i force this service to use the selection??

I have tried to overwrite the service in Mail.php (library to manage the shipments) like this:

    public function getTemplate($name, $params)
    {
        $parameters = array_merge(array(
            'publicUrl' => $this->config->application->publicUrl
        ), $params);

        $code = getLanguage();

        if (php_sapi_name() === 'cli' //se ejecuta por script
            and isset($params['lang']) //se le ha pasado un idioma de la bbd
            and $params['lang'] !== $code //y ese idioma es distionto al que ya hay cargado... sino para que tanto lio...
        ){
            $code = $params['lang'];
            $this->view->code = $code;

            //sobreescribimos el servicio
            $this->getDI()->remove('translation');

            $this->getDI()->setShared(
                'translation',
                function () use ($code) {
                    /*
                     * Ahora es lo que va a funcionar
                     */
                    $path = APP_DIR . "/lang/{$code}/{$code}.php";
                    if (!file_exists($path)) {
                        trigger_error("You must specify a language file for language '$code'");
                        $path = APP_DIR . '/lang/es/es.php';
                    }

                    $messages = [];
                    include $path;
                    if (!is_array($messages)) {
                        trigger_error("Translation data [{$path}] for language '$code' must be an array. Got: " . gettype($messages));
                    }

                    /*
                     * Utilizamos nuestra clase hipervitaminada Translate
                     */
                    return new \Colindar\Translate\Translate(['content' => $messages]);
                }
            );
        }

        //si ejecutamos por consola, cargamos de nuevo esto
        if (php_sapi_name() === 'cli') {
            $this->view->t    = $this->getDI()->getShared('translation');
            $this->view->code = $code;
        }

        return $this->view->getRender('emailTemplates', $name, $parameters, function ($view) {
            $view->setRenderLevel(View::LEVEL_LAYOUT);
        });

        return $view->getContent();
    }

this library is executed from console with a crontab every minute.

The email always is sent in english, the user want spanish.

Thanks people!!



57.7k
Accepted
answer
edited Oct '18

This is working for me:


$di = new \Phalcon\Di\FactoryDefault;

// Mock service class
class Translate {
    public $code;
    public function __construct($code)
    {
        $this->code = $code;
    }
}

// Mock component class, like a Controller
class Component extends \Phalcon\Mvc\User\Component
{
    public function action()
    {
        unset($this->translate); // components cache services independently of DI,
                                 // this would otherwise always return 'first'

        echo $this->translate->code, PHP_EOL;
    }
}

// define service
$di->set('translate', new Translate('first'));

// create mock component
$component = new Component;
$component->setDI($di);

echo 'Accessing from DI:', PHP_EOL;
echo $di->get('translate')->code, PHP_EOL;
echo 'Accessing from component:', PHP_EOL;
$component->action();

echo PHP_EOL, 'replacing service...', PHP_EOL, PHP_EOL;

$di->remove('translate');
$di->setShared('translate', new Translate('second'));

echo 'Accessing from DI:', PHP_EOL;
echo $di->get('translate')->code, PHP_EOL;
echo 'Accessing from component:', PHP_EOL;
$component->action();

Output:

Accessing from DI:
first
Accessing from component:
first

replacing service...

Accessing from DI:
second
Accessing from component:
second

EDIT: The gotcha that caused me sleepless nights is that if you already accessed a service from a component, it gets cached COMPONENT-WISE. You have to unset it inside the component for it to update properly

The output without the unset($this->translate); line looks like this:

Accessing from DI:
first
Accessing from component:
first

replacing service...

Accessing from DI:
second
Accessing from component:
first


3.3k

Fantastic!!! the headache was right where you said.

You had to do unset () so you would not take the CACHED!