TwigTokenParserSwitch.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /**
  3. * @package Grav.Common.Twig
  4. *
  5. * @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. * @origin https://gist.github.com/maxgalbu/9409182
  8. */
  9. namespace Grav\Common\Twig\TokenParser;
  10. use Grav\Common\Twig\Node\TwigNodeSwitch;
  11. /**
  12. * Adds ability use elegant switch instead of ungainly if statements
  13. *
  14. * {% switch type %}
  15. * {% case 'foo' %}
  16. * {{ my_data.foo }}
  17. * {% case 'bar' %}
  18. * {{ my_data.bar }}
  19. * {% default %}
  20. * {{ my_data.default }}
  21. * {% endswitch %}
  22. */
  23. class TwigTokenParserSwitch extends \Twig_TokenParser
  24. {
  25. /**
  26. * {@inheritdoc}
  27. */
  28. public function parse(\Twig_Token $token)
  29. {
  30. $lineno = $token->getLine();
  31. $stream = $this->parser->getStream();
  32. $name = $this->parser->getExpressionParser()->parseExpression();
  33. $stream->expect(\Twig_Token::BLOCK_END_TYPE);
  34. // There can be some whitespace between the {% switch %} and first {% case %} tag.
  35. while ($stream->getCurrent()->getType() === \Twig_Token::TEXT_TYPE && trim($stream->getCurrent()->getValue()) === '') {
  36. $stream->next();
  37. }
  38. $stream->expect(\Twig_Token::BLOCK_START_TYPE);
  39. $expressionParser = $this->parser->getExpressionParser();
  40. $default = null;
  41. $cases = [];
  42. $end = false;
  43. while (!$end) {
  44. $next = $stream->next();
  45. switch ($next->getValue()) {
  46. case 'case':
  47. $values = [];
  48. while (true) {
  49. $values[] = $expressionParser->parsePrimaryExpression();
  50. // Multiple allowed values?
  51. if ($stream->test(\Twig_Token::OPERATOR_TYPE, 'or')) {
  52. $stream->next();
  53. } else {
  54. break;
  55. }
  56. }
  57. $stream->expect(\Twig_Token::BLOCK_END_TYPE);
  58. $body = $this->parser->subparse(array($this, 'decideIfFork'));
  59. $cases[] = new \Twig_Node([
  60. 'values' => new \Twig_Node($values),
  61. 'body' => $body
  62. ]);
  63. break;
  64. case 'default':
  65. $stream->expect(\Twig_Token::BLOCK_END_TYPE);
  66. $default = $this->parser->subparse(array($this, 'decideIfEnd'));
  67. break;
  68. case 'endswitch':
  69. $end = true;
  70. break;
  71. default:
  72. throw new \Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "case", "default", or "endswitch" to close the "switch" block started at line %d)', $lineno), -1);
  73. }
  74. }
  75. $stream->expect(\Twig_Token::BLOCK_END_TYPE);
  76. return new TwigNodeSwitch($name, new \Twig_Node($cases), $default, $lineno, $this->getTag());
  77. }
  78. /**
  79. * Decide if current token marks switch logic.
  80. *
  81. * @param \Twig_Token $token
  82. * @return bool
  83. */
  84. public function decideIfFork(\Twig_Token $token)
  85. {
  86. return $token->test(array('case', 'default', 'endswitch'));
  87. }
  88. /**
  89. * Decide if current token marks end of swtich block.
  90. *
  91. * @param \Twig_Token $token
  92. * @return bool
  93. */
  94. public function decideIfEnd(\Twig_Token $token)
  95. {
  96. return $token->test(array('endswitch'));
  97. }
  98. /**
  99. * {@inheritdoc}
  100. */
  101. public function getTag()
  102. {
  103. return 'switch';
  104. }
  105. }