John Miller
John Miller

Reputation: 727

How to parse TypoScript using the new parser in TYPO3 12+

There seem to be no information on how to use the new TypoScript parser. Announcement was made here without a single explanation or example on how to use the new parser in place of the old. I have this code that I've been using single early versions and works all the way up to version 12 (with deprecation notices. Code is in the ContentObjectPostInitHook.

$typoScriptParser=new TypoScriptParser();
$typoScriptParser->parse($configuration['TypoScript']);
$GLOBALS['TSFE']->tmpl->setup['lib.']['menux']=$typoScriptParser->setup;

$setup=typoScriptParser->getVal($configuration['TypoScriptObjPath'], $GLOBALS['TSFE']->tmpl->setup);

The TypoScriptParser class has now been marked for deprecation in version 13. TypoScriptFrontendController class' tmpl property has also been deprecated. We are advised to use the new parser. How do I refactor this code to the new standard? Thank you.

Upvotes: 1

Views: 124

Answers (1)

Elomidas
Elomidas

Reputation: 1

By the time the question was asked, I hope you don't need the answer anymore, but I had to do that, so it may help someone in the future:

Let's consider the following template that you get as a string named $template in your code somehow (directly from database or whatever other method you find):

plugin.tx_ext {
  current_value = 1
  additional_values {
    index1 = 19, 31
    index2 = 20
  }
}

Full class names for the imports

use TYPO3\CMS\Core\TypoScript\AST\AstBuilder;
use TYPO3\CMS\Core\TypoScript\AST\Node\ChildNodeInterface;
use TYPO3\CMS\Core\TypoScript\AST\Node\RootNode;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Line\LineStream;
use TYPO3\CMS\Core\TypoScript\Tokenizer\LosslessTokenizer;

First, you will use the Tokenizer to load your template string as a LineStream:

/** @var LosslessTokenizer $tokenizer */
$tokenizer = GeneralUtility::makeInstance(LosslessTokenizer::class);
/** @var LineStream $stream */
$stream = $tokenizer->tokenize($template);

Then create an instance of AstBuilder, if you are in a controller, you can rely on $this->eventDispatcher, else you will have to find it or create it by yourself.

/** @var AstBuilder $astBuilder */
$astBuilder = GeneralUtility::makeInstance(
    AstBuilder::class, $this->eventDispatcher);

Finally you can use the AstBuilder to parse the data:

$node = $astBuilder->build($stream, new RootNode());

Now that you have that, let's say you want to extract the values stored as 'additional_values' in our example, you can access them as follow:

# Get the node matching the searched path
$path = 'plugin.tx_ext.additional_values';
foreach (explode('.', $path) as $part) {
    $node = $node->getChildByName($part);
    if ($node == null)
        break;
}
$values = [];
if ($node != null) {
    /** @var ChildNodeInterface $child */
    foreach ($node->getNextChild() as $child) {
        $key = $child->getName();
        $value = $child->getValue();
        $list = [];
        # Value should always be a string at that point, 
        # but we never know what may change in the future
        if (is_string($value)) {
            if ($value == null || $value == '')
                $value = [];
            else $value = explode(',', $value);
        }
        foreach ($value as $val) {
            $val = intval($val);
            # Ignore duplicates
            if ($val < 0 || in_array($val, $list))
                continue;
            $list[] = $val;
        }
        $values[$key] = $list;
    }
}

At the end, your $values array should look like the following:

$values = [
    'index1' => [
        0 => 19,
        1 => 31
    ],
    'index2' => [
        0 => 20
    ]
]

Feel free to improve it if some of it is not perfect, so far it works so that's enough for me.

Upvotes: 0

Related Questions