Phalcon\Mvc\View\Exception: Macro 'baseImagesURL' does not exist

437 Views Asked by At

I have defined a shared service baseImagesURL in my configuration Class but when I try to use it in volt it throws this error Phalcon\Mvc\View\Exception: Macro 'baseImagesURL' does not exist

/**
 * This service helps in the setting base images folder URL 
 */
$di->setShared('baseImagesURL', function() use ($di) {
    /** @var Config $config */
    $config = $di->get('config');
    $url = new Url();
    $url->setStaticBaseUri( $config->path("environment.baseImagesUri"));
    return $url;
});

Volt:

<img src="{{baseImagesURL('Sale-big.jpg')}}" >
1

There are 1 best solutions below

4
pagliuca On

Volt, by default, has already a function called url that can be used to handle what you want. I assume you are already familiar with the url function, so I imagine that you are using a different name (baseImagesURL) because you would like to have both functions simultaneously available inside the templating engine, with different base URI configurations.

To find out how to do what you whant, we can inspect the generated compiled code of a Volt template that uses the regular url function. We will see that the line {{url('foo.bar')}} gets translated to: <?= $this->url->get('foo.bar') ?> inside the generated PHP code (you can find this compiled file inside the cache/ dir of your Phalcon app).

Knowing that, we can do the same thing and create a new function called baseImagesURL to be used. First, we have to create a new service, like you already did in your question:

$di->setShared('baseImagesURLService', function () {                                                                                                                                                                                               
    $url = new UrlResolver();                                                                                            
    $url->setBaseUri('/tmp2/');                                                                                          
    $url->setStaticBaseUri('/tmp2/');                                                                                                                                                                                                                 
    return $url;                                                                                                         
});

The above is similar to what you had in your question, but I've simplified a little bit to have the base URIs hardcoded.

After creating this service, you can add a new Volt function:

$volt->getCompiler()->addFunction(
    'baseImagesURL',
    function ($url) {
        return '$this->baseImagesURLService->get(' . $url . ');';
    }
);

Now, we are ready to use the new function inside a Volt template:

{{ url('foo.bar') }}
<br/>
{{ baseImagesURL('foo.bar') }}

The above will result in:

/tmp/foo.bar
/tmp2/foo.bar

As you can see, I have used both url() and baseImagesURL() inside the same template, to show you that both are working as expected. For this demo, I've configured the url service almost identical to baseImagesURLService, except for the hardcoded path:

$di->setShared('url', function () {   
    $url = new UrlResolver();
    $url->setBaseUri('/tmp/');
    $url->setStaticBaseUri('/tmp/');
    return $url;
});

PS - I have only named the service baseImagesURLService (redundant name) to make a clear distinction between the service name, and the Volt function name (baseImagesURL). Of course, you could use the same name for both.

PS2 - Make sure that you have configured Volt to always recompile your template. If not, the function baseImagesURL will not be available and will trigger the same error you have already encountered (macro not found). Example:

$volt->setOptions([
    'compiledPath' => $config->application->cacheDir,
    'compiledSeparator' => '_',
    'compileAlways' => true
]);