PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/inc/lib/Twig/Node/Expression/Call.php

http://github.com/savetheinternet/Tinyboard
PHP | 178 lines | 143 code | 26 blank | 9 comment | 35 complexity | 0f048ba6fdc876ae24c79c0c69eb3db0 MD5 | raw file
Possible License(s): GPL-2.0, JSON
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) 2012 Fabien Potencier
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
  11. {
  12. protected function compileCallable(Twig_Compiler $compiler)
  13. {
  14. $callable = $this->getAttribute('callable');
  15. $closingParenthesis = false;
  16. if ($callable) {
  17. if (is_string($callable)) {
  18. $compiler->raw($callable);
  19. } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {
  20. $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1]));
  21. } else {
  22. $type = ucfirst($this->getAttribute('type'));
  23. $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name')));
  24. $closingParenthesis = true;
  25. }
  26. } else {
  27. $compiler->raw($this->getAttribute('thing')->compile());
  28. }
  29. $this->compileArguments($compiler);
  30. if ($closingParenthesis) {
  31. $compiler->raw(')');
  32. }
  33. }
  34. protected function compileArguments(Twig_Compiler $compiler)
  35. {
  36. $compiler->raw('(');
  37. $first = true;
  38. if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
  39. $compiler->raw('$this->env');
  40. $first = false;
  41. }
  42. if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
  43. if (!$first) {
  44. $compiler->raw(', ');
  45. }
  46. $compiler->raw('$context');
  47. $first = false;
  48. }
  49. if ($this->hasAttribute('arguments')) {
  50. foreach ($this->getAttribute('arguments') as $argument) {
  51. if (!$first) {
  52. $compiler->raw(', ');
  53. }
  54. $compiler->string($argument);
  55. $first = false;
  56. }
  57. }
  58. if ($this->hasNode('node')) {
  59. if (!$first) {
  60. $compiler->raw(', ');
  61. }
  62. $compiler->subcompile($this->getNode('node'));
  63. $first = false;
  64. }
  65. if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) {
  66. $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null;
  67. $arguments = $this->getArguments($callable, $this->getNode('arguments'));
  68. foreach ($arguments as $node) {
  69. if (!$first) {
  70. $compiler->raw(', ');
  71. }
  72. $compiler->subcompile($node);
  73. $first = false;
  74. }
  75. }
  76. $compiler->raw(')');
  77. }
  78. protected function getArguments($callable, $arguments)
  79. {
  80. $parameters = array();
  81. $named = false;
  82. foreach ($arguments as $name => $node) {
  83. if (!is_int($name)) {
  84. $named = true;
  85. $name = $this->normalizeName($name);
  86. } elseif ($named) {
  87. throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
  88. }
  89. $parameters[$name] = $node;
  90. }
  91. if (!$named) {
  92. return $parameters;
  93. }
  94. if (!$callable) {
  95. throw new LogicException(sprintf('Named arguments are not supported for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name')));
  96. }
  97. // manage named arguments
  98. if (is_array($callable)) {
  99. $r = new ReflectionMethod($callable[0], $callable[1]);
  100. } elseif (is_object($callable) && !$callable instanceof Closure) {
  101. $r = new ReflectionObject($callable);
  102. $r = $r->getMethod('__invoke');
  103. } else {
  104. $r = new ReflectionFunction($callable);
  105. }
  106. $definition = $r->getParameters();
  107. if ($this->hasNode('node')) {
  108. array_shift($definition);
  109. }
  110. if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
  111. array_shift($definition);
  112. }
  113. if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
  114. array_shift($definition);
  115. }
  116. if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
  117. foreach ($this->getAttribute('arguments') as $argument) {
  118. array_shift($definition);
  119. }
  120. }
  121. $arguments = array();
  122. $pos = 0;
  123. foreach ($definition as $param) {
  124. $name = $this->normalizeName($param->name);
  125. if (array_key_exists($name, $parameters)) {
  126. if (array_key_exists($pos, $parameters)) {
  127. throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
  128. }
  129. $arguments[] = $parameters[$name];
  130. unset($parameters[$name]);
  131. } elseif (array_key_exists($pos, $parameters)) {
  132. $arguments[] = $parameters[$pos];
  133. unset($parameters[$pos]);
  134. ++$pos;
  135. } elseif ($param->isDefaultValueAvailable()) {
  136. $arguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1);
  137. } elseif ($param->isOptional()) {
  138. break;
  139. } else {
  140. throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name')));
  141. }
  142. }
  143. if (!empty($parameters)) {
  144. throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '' , implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name')));
  145. }
  146. return $arguments;
  147. }
  148. protected function normalizeName($name)
  149. {
  150. return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name));
  151. }
  152. }