mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-16 04:16:28 +00:00
feature #1286 Adding ignoreStrictCheck option for call_user_func_array, if throwing exception (fabpot)
This PR was merged into the master branch. Discussion ---------- Adding ignoreStrictCheck option for call_user_func_array, if throwing exception Same as #1236 with added unit tests and C extension support (to come). "I experienced the issue when using FuelPHP's ORM with EAV containers. When I tried to reference a property that was not defined I expected to get null, but instead the whole application stopped because an exception was thrown in the ORM, that no such function is present. I couldn't find other possible exception that could be thrown when this function is called, so I assumed it's safe to take the ignoreStrictCheck into consideration here." Commits -------1abf5d9[ext] Mirroring PHP change for call_user_func_array, see #12869ab290badded tests for exceptions thrown in __call()c711d37Adding ignoreStrictCheck option for call_user_func_array, if throwing exception
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
* 1.15.0 (2013-XX-XX)
|
||||
|
||||
* made ignoreStrictCheck in Template::getAttribute() works with __call() methods throwing BadMethodCallException
|
||||
* added min and max functions
|
||||
* added the round filter
|
||||
* fixed a bug that prevented the optimizers to be enabled/disabled selectively
|
||||
|
||||
+22
-1
@@ -18,8 +18,10 @@
|
||||
|
||||
#include "php.h"
|
||||
#include "php_twig.h"
|
||||
#include "ext/standard/php_var.h"
|
||||
#include "ext/standard/php_string.h"
|
||||
#include "ext/standard/php_smart_str.h"
|
||||
#include "ext/spl/spl_exceptions.h"
|
||||
|
||||
#include "Zend/zend_object_handlers.h"
|
||||
#include "Zend/zend_interfaces.h"
|
||||
@@ -945,6 +947,7 @@ PHP_FUNCTION(twig_template_get_attributes)
|
||||
self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
|
||||
}
|
||||
|
||||
$call = false;
|
||||
$lcItem = strtolower($item);
|
||||
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
||||
$method = (string) $item;
|
||||
@@ -954,8 +957,10 @@ PHP_FUNCTION(twig_template_get_attributes)
|
||||
$method = 'is'.$item;
|
||||
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
||||
$method = (string) $item;
|
||||
$call = true;
|
||||
*/
|
||||
{
|
||||
int call = 0;
|
||||
char *lcItem = TWIG_STRTOLOWER(item, item_len);
|
||||
int lcItem_length;
|
||||
char *method = NULL;
|
||||
@@ -981,6 +986,7 @@ PHP_FUNCTION(twig_template_get_attributes)
|
||||
method = tmp_method_name_is;
|
||||
} else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) {
|
||||
method = item;
|
||||
call = 1;
|
||||
/*
|
||||
} else {
|
||||
if ($isDefinedTest) {
|
||||
@@ -1037,9 +1043,24 @@ PHP_FUNCTION(twig_template_get_attributes)
|
||||
return;
|
||||
}
|
||||
/*
|
||||
$ret = call_user_func_array(array($object, $method), $arguments);
|
||||
// Some objects throw exceptions when they have __call, and the method we try
|
||||
// to call is not supported. If ignoreStrictCheck is true, we should return null.
|
||||
try {
|
||||
$ret = call_user_func_array(array($object, $method), $arguments);
|
||||
} catch (BadMethodCallException $e) {
|
||||
if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
|
||||
return null;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
*/
|
||||
ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
|
||||
if (EG(exception) && TWIG_INSTANCE_OF(EG(exception), spl_ce_BadMethodCallException TSRMLS_CC)) {
|
||||
if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
|
||||
zend_clear_exception(TSRMLS_C);
|
||||
return;
|
||||
}
|
||||
}
|
||||
free_ret = 1;
|
||||
efree(tmp_method_name_get);
|
||||
efree(tmp_method_name_is);
|
||||
|
||||
+12
-1
@@ -417,6 +417,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
|
||||
self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
|
||||
}
|
||||
|
||||
$call = false;
|
||||
$lcItem = strtolower($item);
|
||||
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
||||
$method = (string) $item;
|
||||
@@ -426,6 +427,7 @@ abstract class Twig_Template implements Twig_TemplateInterface
|
||||
$method = 'is'.$item;
|
||||
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
||||
$method = (string) $item;
|
||||
$call = true;
|
||||
} else {
|
||||
if ($isDefinedTest) {
|
||||
return false;
|
||||
@@ -446,7 +448,16 @@ abstract class Twig_Template implements Twig_TemplateInterface
|
||||
$this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
|
||||
}
|
||||
|
||||
$ret = call_user_func_array(array($object, $method), $arguments);
|
||||
// Some objects throw exceptions when they have __call, and the method we try
|
||||
// to call is not supported. If ignoreStrictCheck is true, we should return null.
|
||||
try {
|
||||
$ret = call_user_func_array(array($object, $method), $arguments);
|
||||
} catch (BadMethodCallException $e) {
|
||||
if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
|
||||
return null;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// useful when calling a template method from a template
|
||||
// this is not supported but unfortunately heavily used in the Symfony profiler
|
||||
|
||||
@@ -236,6 +236,18 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
|
||||
$this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getTestsDependingOnExtensionAvailability
|
||||
*/
|
||||
public function testGetAttributeCallExceptions($useExt = false)
|
||||
{
|
||||
$template = new Twig_TemplateTest(new Twig_Environment(), $useExt);
|
||||
|
||||
$object = new Twig_TemplateMagicMethodExceptionObject();
|
||||
|
||||
$this->assertEquals(null, $template->getAttribute($object, 'foo'));
|
||||
}
|
||||
|
||||
public function getGetAttributeTests()
|
||||
{
|
||||
$array = array(
|
||||
@@ -603,6 +615,14 @@ class Twig_TemplateMagicMethodObject
|
||||
}
|
||||
}
|
||||
|
||||
class Twig_TemplateMagicMethodExceptionObject
|
||||
{
|
||||
public function __call($method, $arguments)
|
||||
{
|
||||
throw new BadMethodCallException(sprintf('Unkown method %s', $method));
|
||||
}
|
||||
}
|
||||
|
||||
class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface
|
||||
{
|
||||
public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
|
||||
|
||||
Reference in New Issue
Block a user