Add a hook for adjusting the config
Defcon0 opened this issue · 10 comments
Hello,
we have the need for changing the RSCE elements based on a given YML configuration (contao 4.9). For this we need a hook in CustomElements::loadConfig()
(before the line $file = new \File($filePaths['path'], true);
).
Would that be possible?
Thanks in advance.
Bye Defcon0
What settings of the RSCE element do you want to change? Is it possible to make your changes in an onload_callback
?
We try to make the available rsce elements configurable through a yml file.
The starting point for us was to have a bundle which we can install to new projects and have some complex content elements in place then. Since we don't need all RSCE Elements in all projects, we built a way to configure which of them are selectable in the tl_content.type field.
The problem with onload_callback
is that the bundle also adds itself (loadConfig
) to onload_callback
and if we "clean" the $GLOBALS['TL_CTE']
array, the rsce bundle (which needs to be run after our bundle) adds the elements again.
We currently built a workaround in which we do our logic in the load_callback
of the type
field in tl_content, but a hook would be safer ;-)
How about adding one onload_callback
before and one after the custom elements extension?
If you are using service tags this should be possible easily by using priority 1
and -1
.
Service tags are only available in contao 4.9+, aren't they? Since we need the functionality also in v4.4 this won't be an option.
If you don't mind, I can create a PR for the hook, ok?
I’m not convinced that a hook at that point is a good solution. You would have to modify the $contents
and the $GLOBALS
array with the same values, otherwise the cached and non-cached behavior would be different. And if the data of your hook changes, how would you invalidate the cache?
Since we need the functionality also in v4.4 this won't be an option.
In Contao 4.4 you have to take care of the order yourself:
$GLOBALS['TL_DCA']['tl_content']['config']['onload_callback'][] = ['YourClass', 'onloadAfter'];
array_unshift($GLOBALS['TL_DCA']['tl_content']['config']['onload_callback'], ['YourClass', 'onloadBefore']);
Hi, I'm just read a little through the code. Best way to do the hook would be to only write $contents
and afterwards just read the cache again. Could be done in a new method like reloadConfigCache
.
public static function loadConfig($bypassCache = false)
{
// ...
$loadCachedConfig = false;
if (isset($GLOBALS['TL_HOOKS']['rsceLoadConfigBeforeSave']) && \is_array($GLOBALS['TL_HOOKS']['rsceLoadConfigBeforeSave'])) {
foreach ($GLOBALS['TL_HOOKS']['rsceLoadConfigBeforeSave'] as $callback) {
$hook = System::importStatic($callback[0]);
$contents = $hook->{$callback[1]}($contents, $elements, $templates);
}
$loadCachedConfig = true;
}
$file = new \File($filePaths['path'], true);
$file->write(implode("\n", $contents));
$file->close();
static::refreshOpcodeCache($filePaths['fullPath']);
if ($loadCachedConfig) {
static::reloadConfigCache();
}
}
Cache invalidation should be problem of the hook implementor. Could be done by a cache clearer/warmer calling CustomElements::reloadConfig()
refreshOpcodeCache()
does not work on all platforms for an already included file in the same PHP process. The only option would be to use eval()
. I don’t want to create a hook that evaluates strings as PHP code, this could go wrong in many ways.
Anyway, I still don’t understand the use case for the hook. If you want to modify the DCA config use the onload_callback
. You can use that callback before and after the custom elements extension to get control over what gets executed when.
Or is there anything you need to do that doesn’t work nicely in an onload_callback
?
For this use-case there is a another solution, so the hook is not necessary in this case. But hooks are never bad, to be honest, it is hard to extend/build on rsce. In combination with an hook in getConfigByType
we could get rid of html5 templates for example (we use twig).
refreshOpcodeCache() does not work on all platforms for an already included file in the same PHP process. The only option would be to use eval(). I don’t want to create a hook that evaluates strings as PHP code, this could go wrong in many ways.
I don't understand. This code part was taken from loadConfig
hook to just show where to put the hook code.
But hooks are never bad
They are hard to maintain backwards compatibility for.
In combination with an hook in
getConfigByType
we could get rid of html5 templates for example (we use twig).
That’s a totally different story to me. A hook (or rather an event) for getConfigByType
is more reasonable I think. But probably requires more work to ensure that this works for elements that have no Contao template and/or no _config.php file.
I don't understand. This code part was taken from
loadConfig
hook to just show where to put the hook code.
That was regarding your comment “Best way to do the hook would be to only write $contents and afterwards just read the cache again.”. This will not work in some environments.