From 75f59ebe01acc6f510b32b5ea8d3173d3d8e8458 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Mon, 16 Apr 2012 10:25:33 +0200 Subject: [PATCH 001/128] [Routing] add support for path-relative and scheme-relative URL generation --- .../Twig/Extension/RoutingExtension.php | 8 +- .../FrameworkBundle/Controller/Controller.php | 13 +- .../Controller/RedirectController.php | 5 +- .../Templating/Helper/RouterHelper.php | 10 +- .../Templating/Helper/LogoutUrlHelper.php | 28 ++-- .../Security/LocalizedFormFailureHandler.php | 5 +- .../Generator/Dumper/PhpGeneratorDumper.php | 4 +- .../Routing/Generator/UrlGenerator.php | 122 +++++++++++++++--- .../Generator/UrlGeneratorInterface.php | 22 +++- .../Component/Routing/RequestContext.php | 25 +++- src/Symfony/Component/Routing/Router.php | 4 +- .../Tests/Generator/UrlGeneratorTest.php | 117 ++++++++++++++++- .../Component/Security/Http/HttpUtils.php | 11 +- 13 files changed, 306 insertions(+), 68 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/RoutingExtension.php b/src/Symfony/Bridge/Twig/Extension/RoutingExtension.php index 65d7dd22e8..54befc2cf9 100644 --- a/src/Symfony/Bridge/Twig/Extension/RoutingExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/RoutingExtension.php @@ -40,14 +40,14 @@ class RoutingExtension extends \Twig_Extension ); } - public function getPath($name, $parameters = array()) + public function getPath($name, $parameters = array(), $relative = false) { - return $this->generator->generate($name, $parameters, false); + return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH); } - public function getUrl($name, $parameters = array()) + public function getUrl($name, $parameters = array(), $schemeRelative = false) { - return $this->generator->generate($name, $parameters, true); + return $this->generator->generate($name, $parameters, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php index 87900a1242..139b9ff403 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Controller; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\StreamedResponse; @@ -19,8 +20,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Doctrine\Bundle\DoctrineBundle\Registry; -use Symfony\Component\HttpFoundation\Request; /** * Controller is a simple implementation of a Controller. @@ -34,15 +35,15 @@ class Controller extends ContainerAware /** * Generates a URL from the given parameters. * - * @param string $route The name of the route - * @param mixed $parameters An array of parameters - * @param Boolean $absolute Whether to generate an absolute URL + * @param string $route The name of the route + * @param mixed $parameters An array of parameters + * @param string $referenceType The type of reference (see UrlGeneratorInterface) * * @return string The generated URL */ - public function generateUrl($route, $parameters = array(), $absolute = false) + public function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH) { - return $this->container->get('router')->generate($route, $parameters, $absolute); + return $this->container->get('router')->generate($route, $parameters, $referenceType); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php index 513d4de3f5..5d8b71906d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php @@ -12,8 +12,9 @@ namespace Symfony\Bundle\FrameworkBundle\Controller; use Symfony\Component\DependencyInjection\ContainerAware; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** * Redirects a request to another URL. @@ -45,7 +46,7 @@ class RedirectController extends ContainerAware $attributes = $this->container->get('request')->attributes->get('_route_params'); unset($attributes['route'], $attributes['permanent']); - return new RedirectResponse($this->container->get('router')->generate($route, $attributes, true), $permanent ? 301 : 302); + return new RedirectResponse($this->container->get('router')->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), $permanent ? 301 : 302); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php index 6ce78960df..f2429e25c1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php @@ -36,15 +36,15 @@ class RouterHelper extends Helper /** * Generates a URL from the given parameters. * - * @param string $name The name of the route - * @param mixed $parameters An array of parameters - * @param Boolean $absolute Whether to generate an absolute URL + * @param string $name The name of the route + * @param mixed $parameters An array of parameters + * @param string $referenceType The type of reference (see UrlGeneratorInterface) * * @return string The generated URL */ - public function generate($name, $parameters = array(), $absolute = false) + public function generate($name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH) { - return $this->generator->generate($name, $parameters, $absolute); + return $this->generator->generate($name, $parameters, $referenceType); } /** diff --git a/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php b/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php index 4b79957c3b..d5c6a0101e 100644 --- a/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php +++ b/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php @@ -55,36 +55,40 @@ class LogoutUrlHelper extends Helper } /** - * Generate the relative logout URL for the firewall. + * Generates the absolute logout path for the firewall. * * @param string $key The firewall key - * @return string The relative logout URL + * + * @return string The logout path */ public function getLogoutPath($key) { - return $this->generateLogoutUrl($key, false); + return $this->generateLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_PATH); } /** - * Generate the absolute logout URL for the firewall. + * Generates the absolute logout URL for the firewall. * * @param string $key The firewall key - * @return string The absolute logout URL + * + * @return string The logout URL */ public function getLogoutUrl($key) { - return $this->generateLogoutUrl($key, true); + return $this->generateLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_URL); } /** - * Generate the logout URL for the firewall. + * Generates the logout URL for the firewall. + * + * @param string $key The firewall key + * @param string $referenceType The type of reference (see UrlGeneratorInterface) * - * @param string $key The firewall key - * @param Boolean $absolute Whether to generate an absolute URL * @return string The logout URL + * * @throws \InvalidArgumentException if no LogoutListener is registered for the key */ - private function generateLogoutUrl($key, $absolute) + private function generateLogoutUrl($key, $referenceType) { if (!array_key_exists($key, $this->listeners)) { throw new \InvalidArgumentException(sprintf('No LogoutListener found for firewall key "%s".', $key)); @@ -97,13 +101,13 @@ class LogoutUrlHelper extends Helper if ('/' === $logoutPath[0]) { $request = $this->container->get('request'); - $url = ($absolute ? $request->getUriForPath($logoutPath) : $request->getBasePath() . $logoutPath); + $url = UrlGeneratorInterface::ABSOLUTE_URL === $referenceType ? $request->getUriForPath($logoutPath) : $request->getBasePath() . $logoutPath; if (!empty($parameters)) { $url .= '?' . http_build_query($parameters); } } else { - $url = $this->router->generate($logoutPath, $parameters, $absolute); + $url = $this->router->generate($logoutPath, $parameters, $referenceType); } return $url; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Security/LocalizedFormFailureHandler.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Security/LocalizedFormFailureHandler.php index fda394d8cc..7b97199065 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Security/LocalizedFormFailureHandler.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Security/LocalizedFormFailureHandler.php @@ -12,9 +12,10 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Security; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; class LocalizedFormFailureHandler implements AuthenticationFailureHandlerInterface @@ -28,6 +29,6 @@ class LocalizedFormFailureHandler implements AuthenticationFailureHandlerInterfa public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { - return new RedirectResponse($this->router->generate('localized_login_path', array(), true)); + return new RedirectResponse($this->router->generate('localized_login_path', array(), UrlGeneratorInterface::ABSOLUTE_URL)); } } diff --git a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php index c85f0201e4..abdf309d1b 100644 --- a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php +++ b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php @@ -108,7 +108,7 @@ EOF; private function generateGenerateMethod() { return <<doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$absolute, \$hostnameTokens); + return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostnameTokens); } EOF; } diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index aa0a3ee8f2..0dc38ddf89 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -127,7 +127,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt /** * {@inheritDoc} */ - public function generate($name, $parameters = array(), $absolute = false) + public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH) { if (null === $route = $this->routes->get($name)) { throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name)); @@ -136,15 +136,40 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt // the Route has a cache of its own and is not recompiled as long as it does not get modified $compiledRoute = $route->compile(); - return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $absolute, $compiledRoute->getHostnameTokens()); + return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostnameTokens()); + } + + /** + * This method converts the reference type to the new value introduced in Symfony 2.2. It can be used by + * other UrlGenerator implementations to be BC with Symfony 2.1. Reference type was a Boolean called + * $absolute in Symfony 2.1 and only supported two reference types. + * + * @param Boolean $absolute Whether to generate an absolute URL + * + * @return string The new reference type + * + * @deprecated Deprecated since version 2.2, to be removed in 2.3. + */ + public static function convertReferenceType($absolute) + { + if (false === $absolute) { + return self::ABSOLUTE_PATH; + } + if (true === $absolute) { + return self::ABSOLUTE_URL; + } + + return $absolute; } /** * @throws MissingMandatoryParametersException When route has some missing mandatory parameters * @throws InvalidParameterException When a parameter value is not correct */ - protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $absolute, $hostnameTokens) + protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostnameTokens) { + $referenceType = self::convertReferenceType($referenceType); + $variables = array_flip($variables); $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters); @@ -186,8 +211,8 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt $url = '/'; } - // do not encode the contexts base url as it is already encoded (see Symfony\Component\HttpFoundation\Request) - $url = $this->context->getBaseUrl().strtr(rawurlencode($url), $this->decodedChars); + // the contexts base url is already encoded (see Symfony\Component\HttpFoundation\Request) + $url = strtr(rawurlencode($url), $this->decodedChars); // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3 // so we need to encode them as they are not used for this purpose here @@ -199,16 +224,11 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt $url = substr($url, 0, -1) . '%2E'; } - // add a query string if needed - $extra = array_diff_key($parameters, $variables); - if ($extra && $query = http_build_query($extra, '', '&')) { - $url .= '?'.$query; - } - + $schemeAuthority = ''; if ($host = $this->context->getHost()) { $scheme = $this->context->getScheme(); - if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme != $req) { - $absolute = true; + if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme !== $req) { + $referenceType = self::ABSOLUTE_URL; $scheme = $req; } @@ -231,18 +251,20 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt } $routeHost = $token[1].$mergedParams[$token[3]].$routeHost; - } elseif ('text' === $token[0]) { + } else { $routeHost = $token[1].$routeHost; } } - if ($routeHost != $host) { + if ($routeHost !== $host) { $host = $routeHost; - $absolute = true; + if (self::ABSOLUTE_URL !== $referenceType) { + $referenceType = self::NETWORK_PATH; + } } } - if ($absolute) { + if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) { $port = ''; if ('http' === $scheme && 80 != $this->context->getHttpPort()) { $port = ':'.$this->context->getHttpPort(); @@ -250,10 +272,74 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt $port = ':'.$this->context->getHttpsPort(); } - $url = $scheme.'://'.$host.$port.$url; + $schemeAuthority = self::NETWORK_PATH === $referenceType ? '//' : "$scheme://"; + $schemeAuthority .= $host.$port; } } + if (self::RELATIVE_PATH === $referenceType) { + $url = self::getRelativePath($this->context->getPathInfo(), $url); + } else { + $url = $schemeAuthority.$this->context->getBaseUrl().$url; + } + + // add a query string if needed + $extra = array_diff_key($parameters, $variables); + if ($extra && $query = http_build_query($extra, '', '&')) { + $url .= '?'.$query; + } + return $url; } + + /** + * Returns the target path as relative reference from the base path. + * + * Only the URIs path component (no schema, hostname etc.) is relevant and must be given, starting with a slash. + * Both paths must be absolute and not contain relative parts. + * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives. + * Furthermore, they can be used to reduce the link size in documents. + * + * Example target paths, given a base path of "/a/b/c/d": + * - "/a/b/c/d" -> "" + * - "/a/b/c/" -> "./" + * - "/a/b/" -> "../" + * - "/a/b/c/other" -> "other" + * - "/a/x/y" -> "../../x/y" + * + * @param string $basePath The base path + * @param string $targetPath The target path + * + * @return string The relative target path + */ + public static function getRelativePath($basePath, $targetPath) + { + if ($basePath === $targetPath) { + return ''; + } + + $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath); + $targetDirs = explode('/', isset($targetPath[0]) && '/' === $targetPath[0] ? substr($targetPath, 1) : $targetPath); + array_pop($sourceDirs); + $targetFile = array_pop($targetDirs); + + foreach ($sourceDirs as $i => $dir) { + if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) { + unset($sourceDirs[$i], $targetDirs[$i]); + } else { + break; + } + } + + $targetDirs[] = $targetFile; + $path = str_repeat('../', count($sourceDirs)) . implode('/', $targetDirs); + + // A reference to the same base directory or an empty subdirectory must be prefixed with "./". + // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used + // as the first segment of a relative-path reference, as it would be mistaken for a scheme name + // (see http://tools.ietf.org/html/rfc3986#section-4.2). + return '' === $path || '/' === $path[0] + || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos) + ? "./$path" : $path; + } } diff --git a/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php b/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php index e28c79d2d6..e24030b32a 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php +++ b/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php @@ -18,20 +18,34 @@ use Symfony\Component\Routing\Exception\RouteNotFoundException; * UrlGeneratorInterface is the interface that all URL generator classes must implement. * * @author Fabien Potencier + * @author Tobias Schultze * * @api */ interface UrlGeneratorInterface extends RequestContextAwareInterface { + /** + * These constants define the different types of resource references that are declared + * in RFC 3986: http://tools.ietf.org/html/rfc3986 + * We are using the term "URL" instead of "URI" as this is more common in web applications + * and we do not need to distinguish them as the difference is mostly semantical and + * less technical. Generating URIs, i.e. representation-independent resource identifiers, + * is still possible. + */ + const ABSOLUTE_URL = 'url'; + const ABSOLUTE_PATH = 'path'; + const RELATIVE_PATH = 'relative'; + const NETWORK_PATH = 'network'; + /** * Generates a URL from the given parameters. * * If the generator is not able to generate the url, it must throw the RouteNotFoundException * as documented below. * - * @param string $name The name of the route - * @param mixed $parameters An array of parameters - * @param Boolean $absolute Whether to generate an absolute URL + * @param string $name The name of the route + * @param mixed $parameters An array of parameters + * @param string $referenceType The type of reference to be generated (see defined constants) * * @return string The generated URL * @@ -39,5 +53,5 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface * * @api */ - public function generate($name, $parameters = array(), $absolute = false); + public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH); } diff --git a/src/Symfony/Component/Routing/RequestContext.php b/src/Symfony/Component/Routing/RequestContext.php index 1f9cf3c02c..0286e842de 100644 --- a/src/Symfony/Component/Routing/RequestContext.php +++ b/src/Symfony/Component/Routing/RequestContext.php @@ -23,6 +23,7 @@ use Symfony\Component\HttpFoundation\Request; class RequestContext { private $baseUrl; + private $pathInfo; private $method; private $host; private $scheme; @@ -46,7 +47,7 @@ class RequestContext * * @api */ - public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443) + public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443, $path = '/') { $this->baseUrl = $baseUrl; $this->method = strtoupper($method); @@ -54,11 +55,13 @@ class RequestContext $this->scheme = strtolower($scheme); $this->httpPort = $httpPort; $this->httpsPort = $httpsPort; + $this->pathInfo = $path; } public function fromRequest(Request $request) { $this->setBaseUrl($request->getBaseUrl()); + $this->setPathInfo($request->getPathInfo()); $this->setMethod($request->getMethod()); $this->setHost($request->getHost()); $this->setScheme($request->getScheme()); @@ -88,6 +91,26 @@ class RequestContext $this->baseUrl = $baseUrl; } + /** + * Gets the path info. + * + * @return string The path info + */ + public function getPathInfo() + { + return $this->pathInfo; + } + + /** + * Sets the path info. + * + * @param string $pathInfo The path info + */ + public function setPathInfo($pathInfo) + { + $this->pathInfo = $pathInfo; + } + /** * Gets the HTTP method. * diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index 68d73ab24d..a85054a450 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -202,9 +202,9 @@ class Router implements RouterInterface /** * {@inheritdoc} */ - public function generate($name, $parameters = array(), $absolute = false) + public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH) { - return $this->getGenerator()->generate($name, $parameters, $absolute); + return $this->getGenerator()->generate($name, $parameters, $referenceType); } /** diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index a3f50b6aca..5c44307b84 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -379,7 +379,6 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase */ public function testDefaultRequirementOfVariableDisallowsNextSeparator() { - $routes = $this->getRoutes('test', new Route('/{page}.{_format}')); $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html')); } @@ -388,7 +387,7 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase { $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com')); - $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' =>'Fabien', 'locale' => 'fr'))); + $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' =>'Fabien', 'locale' => 'fr'))); } public function testWithHostnameSameAsContext() @@ -440,6 +439,120 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase $this->assertNull($generator->generate('test', array('foo' => 'baz'), false)); } + /** + * @dataProvider provideRelativePaths + */ + public function testGetRelativePath($sourcePath, $targetPath, $expectedPath) + { + $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath)); + } + + public function provideRelativePaths() + { + return array( + array( + '/same/dir/', + '/same/dir/', + '' + ), + array( + '/same/file', + '/same/file', + '' + ), + array( + '/', + '/file', + 'file' + ), + array( + '/', + '/dir/file', + 'dir/file' + ), + array( + '/dir/file.html', + '/dir/different-file.html', + 'different-file.html' + ), + array( + '/same/dir/extra-file', + '/same/dir/', + './' + ), + array( + '/parent/dir/', + '/parent/', + '../' + ), + array( + '/parent/dir/extra-file', + '/parent/', + '../' + ), + array( + '/a/b/', + '/x/y/z/', + '../../x/y/z/' + ), + array( + '/a/b/c/d/e', + '/a/c/d', + '../../../c/d' + ), + array( + '/a/b/c//', + '/a/b/c/', + '../' + ), + array( + '/a/b/c/', + '/a/b/c//', + './/' + ), + array( + '/root/a/b/c/', + '/root/x/b/c/', + '../../../x/b/c/' + ), + array( + '/a/b/c/d/', + '/a', + '../../../../a' + ), + array( + '/special-chars/sp%20ce/1€/mäh/e=mc²', + '/special-chars/sp%20ce/1€/<µ>/e=mc²', + '../<µ>/e=mc²' + ), + array( + 'not-rooted', + 'dir/file', + 'dir/file' + ), + array( + '//dir/', + '', + '../../' + ), + array( + '/dir/', + '/dir/file:with-colon', + './file:with-colon' + ), + array( + '/dir/', + '/dir/subdir/file:with-colon', + 'subdir/file:with-colon' + ), + array( + '/dir/', + '/dir/:subdir/', + './:subdir/' + ), + ); + } + protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null) { $context = new RequestContext('/app.php'); diff --git a/src/Symfony/Component/Security/Http/HttpUtils.php b/src/Symfony/Component/Security/Http/HttpUtils.php index 76cfc6af09..6a2da08bd4 100644 --- a/src/Symfony/Component/Security/Http/HttpUtils.php +++ b/src/Symfony/Component/Security/Http/HttpUtils.php @@ -67,8 +67,8 @@ class HttpUtils public function createRequest(Request $request, $path) { $newRequest = Request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all()); - if ($session = $request->getSession()) { - $newRequest->setSession($session); + if ($request->hasSession()) { + $newRequest->setSession($request->getSession()); } if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { @@ -127,15 +127,10 @@ class HttpUtils return $request->getUriForPath($path); } - return $this->generateUrl($path, true); - } - - private function generateUrl($route, $absolute = false) - { if (null === $this->urlGenerator) { throw new \LogicException('You must provide a UrlGeneratorInterface instance to be able to use routes.'); } - return $this->urlGenerator->generate($route, array(), $absolute); + return $this->urlGenerator->generate($path, array(), UrlGeneratorInterface::ABSOLUTE_URL); } } From 7db07d91aa2a06a31e7e75857ae2410c364f07bf Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 13 Dec 2012 15:42:18 +0100 Subject: [PATCH 002/128] [Routing] added tests for generating relative paths and network paths --- .../Tests/Generator/UrlGeneratorTest.php | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index 5c44307b84..899f139f9c 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Routing\Tests\Generator; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RequestContext; class UrlGeneratorTest extends \PHPUnit_Framework_TestCase @@ -439,6 +440,58 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase $this->assertNull($generator->generate('test', array('foo' => 'baz'), false)); } + public function testGenerateNetworkPath() + { + $routes = $this->getRoutes('test', new Route('/{name}', array(), array('_scheme' => 'http'), array(), '{locale}.example.com')); + + $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', + array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host' + ); + $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', + array('name' =>'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context' + ); + $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', + array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context' + ); + $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', + array('name' =>'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested' + ); + } + + public function testGenerateRelativePath() + { + $routes = new RouteCollection(); + $routes->add('article', new Route('/{author}/{article}/')); + $routes->add('comments', new Route('/{author}/{article}/comments')); + $routes->add('hostname', new Route('/{article}', array(), array(), array(), '{author}.example.com')); + $routes->add('scheme', new Route('/{author}', array(), array('_scheme' => 'https'))); + $routes->add('unrelated', new Route('/about')); + + $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/')); + + $this->assertSame('comments', $generator->generate('comments', + array('author' =>'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH) + ); + $this->assertSame('comments?page=2', $generator->generate('comments', + array('author' =>'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH) + ); + $this->assertSame('../twig-is-great/', $generator->generate('article', + array('author' =>'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH) + ); + $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article', + array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH) + ); + $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('hostname', + array('author' =>'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH) + ); + $this->assertSame('https://example.com/app.php/bernhard', $generator->generate('scheme', + array('author' =>'bernhard'), UrlGeneratorInterface::RELATIVE_PATH) + ); + $this->assertSame('../../about', $generator->generate('unrelated', + array(), UrlGeneratorInterface::RELATIVE_PATH) + ); + } + /** * @dataProvider provideRelativePaths */ From f0415ed3d1f7d3ec9b9092b4d61ef82a93d779f0 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 13 Dec 2012 19:02:15 +0100 Subject: [PATCH 003/128] [Routing] made reference type fully BC and improved phpdoc considerably --- .../FrameworkBundle/Controller/Controller.php | 8 +-- .../Templating/Helper/RouterHelper.php | 8 +-- .../Templating/Helper/LogoutUrlHelper.php | 4 +- .../Routing/Generator/UrlGenerator.php | 28 +--------- .../Generator/UrlGeneratorInterface.php | 53 ++++++++++++++----- 5 files changed, 53 insertions(+), 48 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php index 139b9ff403..a19030e11b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php @@ -35,11 +35,13 @@ class Controller extends ContainerAware /** * Generates a URL from the given parameters. * - * @param string $route The name of the route - * @param mixed $parameters An array of parameters - * @param string $referenceType The type of reference (see UrlGeneratorInterface) + * @param string $route The name of the route + * @param mixed $parameters An array of parameters + * @param Boolean|string $referenceType The type of reference (one of the constants in UrlGeneratorInterface) * * @return string The generated URL + * + * @see UrlGeneratorInterface */ public function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php index f2429e25c1..845b75d59a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/RouterHelper.php @@ -36,11 +36,13 @@ class RouterHelper extends Helper /** * Generates a URL from the given parameters. * - * @param string $name The name of the route - * @param mixed $parameters An array of parameters - * @param string $referenceType The type of reference (see UrlGeneratorInterface) + * @param string $name The name of the route + * @param mixed $parameters An array of parameters + * @param Boolean|string $referenceType The type of reference (one of the constants in UrlGeneratorInterface) * * @return string The generated URL + * + * @see UrlGeneratorInterface */ public function generate($name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH) { diff --git a/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php b/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php index d5c6a0101e..59f7182bc3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php +++ b/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php @@ -81,8 +81,8 @@ class LogoutUrlHelper extends Helper /** * Generates the logout URL for the firewall. * - * @param string $key The firewall key - * @param string $referenceType The type of reference (see UrlGeneratorInterface) + * @param string $key The firewall key + * @param Boolean|string $referenceType The type of reference (one of the constants in UrlGeneratorInterface) * * @return string The logout URL * diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 0dc38ddf89..9f605c918f 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -19,7 +19,8 @@ use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; use Symfony\Component\HttpKernel\Log\LoggerInterface; /** - * UrlGenerator generates a URL based on a set of routes. + * UrlGenerator can generate a URL or a path for any route in the RouteCollection + * based on the passed parameters. * * @author Fabien Potencier * @author Tobias Schultze @@ -139,37 +140,12 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostnameTokens()); } - /** - * This method converts the reference type to the new value introduced in Symfony 2.2. It can be used by - * other UrlGenerator implementations to be BC with Symfony 2.1. Reference type was a Boolean called - * $absolute in Symfony 2.1 and only supported two reference types. - * - * @param Boolean $absolute Whether to generate an absolute URL - * - * @return string The new reference type - * - * @deprecated Deprecated since version 2.2, to be removed in 2.3. - */ - public static function convertReferenceType($absolute) - { - if (false === $absolute) { - return self::ABSOLUTE_PATH; - } - if (true === $absolute) { - return self::ABSOLUTE_URL; - } - - return $absolute; - } - /** * @throws MissingMandatoryParametersException When route has some missing mandatory parameters * @throws InvalidParameterException When a parameter value is not correct */ protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostnameTokens) { - $referenceType = self::convertReferenceType($referenceType); - $variables = array_flip($variables); $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters); diff --git a/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php b/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php index e24030b32a..6c44849595 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php +++ b/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php @@ -17,6 +17,13 @@ use Symfony\Component\Routing\Exception\RouteNotFoundException; /** * UrlGeneratorInterface is the interface that all URL generator classes must implement. * + * The constants in this interface define the different types of resource references that + * are declared in RFC 3986: http://tools.ietf.org/html/rfc3986 + * We are using the term "URL" instead of "URI" as this is more common in web applications + * and we do not need to distinguish them as the difference is mostly semantical and + * less technical. Generating URIs, i.e. representation-independent resource identifiers, + * is also possible. + * * @author Fabien Potencier * @author Tobias Schultze * @@ -25,27 +32,45 @@ use Symfony\Component\Routing\Exception\RouteNotFoundException; interface UrlGeneratorInterface extends RequestContextAwareInterface { /** - * These constants define the different types of resource references that are declared - * in RFC 3986: http://tools.ietf.org/html/rfc3986 - * We are using the term "URL" instead of "URI" as this is more common in web applications - * and we do not need to distinguish them as the difference is mostly semantical and - * less technical. Generating URIs, i.e. representation-independent resource identifiers, - * is still possible. + * Generates an absolute URL, e.g. "http://example.com/dir/file". + */ + const ABSOLUTE_URL = true; + + /** + * Generates an absolute path, e.g. "/dir/file". + */ + const ABSOLUTE_PATH = false; + + /** + * Generates a relative path based on the current request path, e.g. "../parent-file". + * @see UrlGenerator::getRelativePath() */ - const ABSOLUTE_URL = 'url'; - const ABSOLUTE_PATH = 'path'; const RELATIVE_PATH = 'relative'; + + /** + * Generates a network path, e.g. "//example.com/dir/file". + * Such reference reuses the current scheme but specifies the hostname. + */ const NETWORK_PATH = 'network'; /** - * Generates a URL from the given parameters. + * Generates a URL or path for a specific route based on the given parameters. * - * If the generator is not able to generate the url, it must throw the RouteNotFoundException - * as documented below. + * Parameters that reference placeholders in the route pattern will substitute them in the + * path or hostname. Extra params are added as query string to the URL. * - * @param string $name The name of the route - * @param mixed $parameters An array of parameters - * @param string $referenceType The type of reference to be generated (see defined constants) + * When the passed reference type cannot be generated for the route because it requires a different + * hostname or scheme than the current one, the method will return a more comprehensive reference + * that includes the required params. For example, when you call this method with $referenceType = ABSOLUTE_PATH + * but the route requires the https scheme whereas the current scheme is http, it will instead return an + * ABSOLUTE_URL with the https scheme and the current hostname. This makes sure the generated URL matches + * the route in any case. + * + * If there is no route with the given name, the generator must throw the RouteNotFoundException. + * + * @param string $name The name of the route + * @param mixed $parameters An array of parameters + * @param Boolean|string $referenceType The type of reference to be generated (one of the constants) * * @return string The generated URL * From 1997e2e9789807db8ec0c1b837e3060cc4c0e2e8 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 13 Dec 2012 19:26:07 +0100 Subject: [PATCH 004/128] fix phpdoc of UrlGeneratorInterface that missed some exceptions and improve language of exception message --- .../Component/Routing/Generator/UrlGenerator.php | 11 ++++++----- .../Routing/Generator/UrlGeneratorInterface.php | 9 +++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 9f605c918f..337af75992 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -141,8 +141,9 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt } /** - * @throws MissingMandatoryParametersException When route has some missing mandatory parameters - * @throws InvalidParameterException When a parameter value is not correct + * @throws MissingMandatoryParametersException When some parameters are missing that mandatory for the route + * @throws InvalidParameterException When a parameter value for a placeholder is not correct because + * it does not match the requirement */ protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostnameTokens) { @@ -151,7 +152,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt // all params must be given if ($diff = array_diff_key($variables, $mergedParams)) { - throw new MissingMandatoryParametersException(sprintf('The "%s" route has some missing mandatory parameters ("%s").', $name, implode('", "', array_keys($diff)))); + throw new MissingMandatoryParametersException(sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', array_keys($diff)), $name)); } $url = ''; @@ -161,7 +162,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt if (!$optional || !array_key_exists($token[3], $defaults) || (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) { // check requirement if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) { - $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given).', $token[3], $name, $token[2], $mergedParams[$token[3]]); + $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]); if ($this->strictRequirements) { throw new InvalidParameterException($message); } @@ -213,7 +214,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt foreach ($hostnameTokens as $token) { if ('variable' === $token[0]) { if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) { - $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given).', $token[3], $name, $token[2], $mergedParams[$token[3]]); + $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]); if ($this->strictRequirements) { throw new InvalidParameterException($message); diff --git a/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php b/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php index 6c44849595..c38f310227 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php +++ b/src/Symfony/Component/Routing/Generator/UrlGeneratorInterface.php @@ -11,8 +11,10 @@ namespace Symfony\Component\Routing\Generator; -use Symfony\Component\Routing\RequestContextAwareInterface; +use Symfony\Component\Routing\Exception\InvalidParameterException; +use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; use Symfony\Component\Routing\Exception\RouteNotFoundException; +use Symfony\Component\Routing\RequestContextAwareInterface; /** * UrlGeneratorInterface is the interface that all URL generator classes must implement. @@ -74,7 +76,10 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface * * @return string The generated URL * - * @throws RouteNotFoundException if route doesn't exist + * @throws RouteNotFoundException If the named route doesn't exist + * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route + * @throws InvalidParameterException When a parameter value for a placeholder is not correct because + * it does not match the requirement * * @api */ From 85137778a65223b5b4acfa35c6e5429bc51b7a7c Mon Sep 17 00:00:00 2001 From: Drak Date: Wed, 19 Dec 2012 14:14:03 +0000 Subject: [PATCH 005/128] [HttpFoundation] Update docblock for non-working method --- .../Component/HttpFoundation/Session/Flash/FlashBag.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php index ce9308e154..f0a00d66a0 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php @@ -177,6 +177,11 @@ class FlashBag implements FlashBagInterface, \IteratorAggregate, \Countable /** * Returns the number of flashes. * + * This method does not work. + * + * @deprecated in 2.2, removed in 2.3 + * @see https://github.com/symfony/symfony/issues/6408 + * * @return int The number of flashes */ public function count() From 6703fb59d370a4fd365dc556d5ef4149ba7bace8 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Wed, 2 Jan 2013 22:49:54 +0100 Subject: [PATCH 006/128] added changelog entries --- src/Symfony/Bridge/Twig/CHANGELOG.md | 2 ++ src/Symfony/Component/Routing/CHANGELOG.md | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index d5a92ab7b3..41f6204cdd 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -5,6 +5,8 @@ CHANGELOG ----- * The `app` global variable is now injected even when using the twig service directly. + * Added an optional parameter to the `path` and `url` function which allows to generate + relative paths (e.g. "../parent-file") and scheme-relative URLs (e.g. "//example.com/dir/file"). 2.1.0 ----- diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index fba7d41a40..13042508b6 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -79,6 +79,12 @@ CHANGELOG pass the requirements (otherwise it would break your link anyway). * There is no restriction on the route name anymore. So non-alphanumeric characters are now also allowed. + * Added possibility to generate relative paths and network paths in the UrlGenerator, e.g. + "../parent-file" and "//example.com/dir/file". The third parameter in + `UrlGeneratorInterface::generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)` + now accepts more values and you should use the constants defined in `UrlGeneratorInterface` for + claritiy. The old method calls with a Boolean parameter will continue to work because they + equal the signature using the constants. 2.1.0 ----- From 33e9d002a708bf54e551c7e75de57841ee105535 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Sat, 5 Jan 2013 18:04:01 +0100 Subject: [PATCH 007/128] [Form] Deleted references in FormBuilder::getFormConfig() to improve performance --- src/Symfony/Component/Form/FormBuilder.php | 15 ++++++++++++ .../Component/Form/Tests/FormBuilderTest.php | 24 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index 9d23ff565f..8560e75806 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -202,6 +202,21 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB return count($this->children); } + /** + * {@inheritdoc} + */ + public function getFormConfig() + { + $config = parent::getFormConfig(); + + $config->factory = null; + $config->parent = null; + $config->children = array(); + $config->unresolvedChildren = array(); + + return $config; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php index 42d4317459..ff04006b54 100644 --- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php @@ -232,6 +232,30 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $this->builder->create('bar', 'text'); } + public function testGetFormConfigErasesReferences() + { + $builder = new FormBuilder('name', null, $this->dispatcher, $this->factory); + $builder->setParent(new FormBuilder('parent', null, $this->dispatcher, $this->factory)); + $builder->add(new FormBuilder('child', null, $this->dispatcher, $this->factory)); + + $config = $builder->getFormConfig(); + $reflClass = new \ReflectionClass($config); + $factory = $reflClass->getProperty('factory'); + $parent = $reflClass->getProperty('parent'); + $children = $reflClass->getProperty('children'); + $unresolvedChildren = $reflClass->getProperty('unresolvedChildren'); + + $factory->setAccessible(true); + $parent->setAccessible(true); + $children->setAccessible(true); + $unresolvedChildren->setAccessible(true); + + $this->assertNull($factory->getValue($config)); + $this->assertNull($parent->getValue($config)); + $this->assertEmpty($children->getValue($config)); + $this->assertEmpty($unresolvedChildren->getValue($config)); + } + private function getFormBuilder($name = 'name') { $mock = $this->getMockBuilder('Symfony\Component\Form\FormBuilder') From 1e2fb64817abd4f1e9aa4b8e1cb392a46f9a8688 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Jan 2013 08:52:07 +0100 Subject: [PATCH 008/128] [DependencyInjection] refactored code to avoid logic duplication --- .../DependencyInjection/Dumper/PhpDumper.php | 66 +++++++++---------- .../Fixtures/php/services9.php | 1 + 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 18251f064c..a2536d5847 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -227,24 +227,7 @@ class PhpDumper extends Dumper throw new ServiceCircularReferenceException($id, array($id)); } - $arguments = array(); - foreach ($sDefinition->getArguments() as $argument) { - $arguments[] = $this->dumpValue($argument); - } - - if (null !== $sDefinition->getFactoryMethod()) { - if (null !== $sDefinition->getFactoryClass()) { - $code .= sprintf(" \$%s = call_user_func(array(%s, '%s')%s);\n", $name, $this->dumpValue($sDefinition->getFactoryClass()), $sDefinition->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : ''); - } elseif (null !== $sDefinition->getFactoryService()) { - $code .= sprintf(" \$%s = %s->%s(%s);\n", $name, $this->getServiceCall($sDefinition->getFactoryService()), $sDefinition->getFactoryMethod(), implode(', ', $arguments)); - } else { - throw new \RuntimeException('Factory service or factory class must be defined in service definition for '.$id); - } - } elseif (false !== strpos($class, '$')) { - $code .= sprintf(" \$class = %s;\n \$%s = new \$class(%s);\n", $class, $name, implode(', ', $arguments)); - } else { - $code .= sprintf(" \$%s = new \\%s(%s);\n", $name, substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments)); - } + $code .= $this->addNewInstance($id, $sDefinition, '$'.$name, ' = '); if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) { $code .= $this->addServiceMethodCalls(null, $sDefinition, $name); @@ -295,11 +278,6 @@ class PhpDumper extends Dumper throw new \InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id)); } - $arguments = array(); - foreach ($definition->getArguments() as $value) { - $arguments[] = $this->dumpValue($value); - } - $simple = $this->isSimpleInstance($id, $definition); $instantiation = ''; @@ -318,19 +296,7 @@ class PhpDumper extends Dumper $instantiation .= ' = '; } - if (null !== $definition->getFactoryMethod()) { - if (null !== $definition->getFactoryClass()) { - $code = sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass()), $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : ''); - } elseif (null !== $definition->getFactoryService()) { - $code = sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments)); - } else { - throw new \RuntimeException('Factory method requires a factory service or factory class in service definition for '.$id); - } - } elseif (false !== strpos($class, '$')) { - $code = sprintf(" \$class = %s;\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments)); - } else { - $code = sprintf(" $return{$instantiation}new \\%s(%s);\n", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments)); - } + $code = $this->addNewInstance($id, $definition, $return, $instantiation); if (!$simple) { $code .= "\n"; @@ -609,6 +575,34 @@ EOF; return $publicServices.$aliasServices.$privateServices; } + private function addNewInstance($id, Definition $definition, $return, $instantiation) + { + $class = $this->dumpValue($definition->getClass()); + + $arguments = array(); + foreach ($definition->getArguments() as $value) { + $arguments[] = $this->dumpValue($value); + } + + if (null !== $definition->getFactoryMethod()) { + if (null !== $definition->getFactoryClass()) { + return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass()), $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : ''); + } + + if (null !== $definition->getFactoryService()) { + return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments)); + } + + throw new RuntimeException('Factory method requires a factory service or factory class in service definition for '.$id); + } + + if (false !== strpos($class, '$')) { + return sprintf(" \$class = %s;\n\n $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments)); + } + + return sprintf(" $return{$instantiation}new \\%s(%s);\n", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments)); + } + /** * Adds the class headers. * diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php index 0d4008583e..a5d2f74449 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php @@ -118,6 +118,7 @@ class ProjectServiceContainer extends Container protected function getFooBarService() { $class = $this->getParameter('foo_class'); + return new $class(); } From 666283cb76747fa5c0158101f321eb1afa1a272d Mon Sep 17 00:00:00 2001 From: Joseph Bielawski Date: Mon, 7 Jan 2013 11:42:04 +0100 Subject: [PATCH 009/128] [HttpFoundation] Docblock for Request::isXmlHttpRequest() now points to Wikipedia --- src/Symfony/Component/HttpFoundation/Request.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 546d0ffbd9..f973583125 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1132,7 +1132,8 @@ class Request * Returns true if the request is a XMLHttpRequest. * * It works if your JavaScript library set an X-Requested-With HTTP header. - * It is known to work with Prototype, Mootools, jQuery. + * It is known to work with common JavaScript frameworks: + * @link http://en.wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript * * @return Boolean true if the request is an XMLHttpRequest, false otherwise * From dbafc2c365b4e2ed12465041950ba48f4ad7e933 Mon Sep 17 00:00:00 2001 From: Simon Constans Date: Tue, 11 Dec 2012 19:25:03 +0100 Subject: [PATCH 010/128] [CssSelector] added css selector with empty string --- src/Symfony/Component/CssSelector/Tokenizer.php | 2 +- tests/Symfony/Tests/Component/CssSelector/TokenizerTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/CssSelector/Tokenizer.php b/src/Symfony/Component/CssSelector/Tokenizer.php index 67d5b67470..34e8ac580a 100644 --- a/src/Symfony/Component/CssSelector/Tokenizer.php +++ b/src/Symfony/Component/CssSelector/Tokenizer.php @@ -129,7 +129,7 @@ class Tokenizer } $result = substr($s, $start, $next - $start); - if ('\\' === $result[strlen($result) - 1]) { + if (strlen($result) > 0 && '\\' === $result[strlen($result) - 1]) { // next quote character is escaped $pos = $next + 1; continue; diff --git a/tests/Symfony/Tests/Component/CssSelector/TokenizerTest.php b/tests/Symfony/Tests/Component/CssSelector/TokenizerTest.php index 4e780831c2..70f471e197 100644 --- a/tests/Symfony/Tests/Component/CssSelector/TokenizerTest.php +++ b/tests/Symfony/Tests/Component/CssSelector/TokenizerTest.php @@ -34,6 +34,7 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase { $this->assertEquals('foo[class=foo bar ]', $this->tokensToString($this->tokenizer->tokenize('foo[class="foo bar"]')), '->tokenize() lexes an input string and returns an array of tokens'); $this->assertEquals("foo[class=foo Abar ]", $this->tokensToString($this->tokenizer->tokenize('foo[class="foo \\65 bar"]')), '->tokenize() lexes an input string and returns an array of tokens'); + $this->assertEquals("img[alt= ]", $this->tokensToString($this->tokenizer->tokenize('img[alt=""]')), '->tokenize() lexes an input string and returns an array of tokens'); } /** From 3195122905f96502290407f6a04c4ed6ea94c3bc Mon Sep 17 00:00:00 2001 From: srsbiz Date: Mon, 31 Dec 2012 10:36:11 +0100 Subject: [PATCH 011/128] [HttpFoundation] Check if required shell functions for `FileBinaryMimeTypeGuesser` are not disabled --- .../HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php index 115d95deef..bf30fe8124 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php @@ -28,8 +28,9 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface */ public static function isSupported() { - return !strstr(PHP_OS, 'WIN'); + return !defined('PHP_WINDOWS_VERSION_BUILD') && function_exists('passthru') && function_exists('escapeshellarg'); } + /** * Guesses the mime type of the file with the given path * From 694c47ce9626568efee496accf6ff5a564cbc83e Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:15:05 +0200 Subject: [PATCH 012/128] [Security] Change signature of `AuthenticationException` to match `\Exception` --- .../Security/Core/Exception/AuthenticationException.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index 074dad094b..fbe10ebaa8 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -15,18 +15,12 @@ namespace Symfony\Component\Security\Core\Exception; * AuthenticationException is the base class for all authentication exceptions. * * @author Fabien Potencier + * @author Alexander */ class AuthenticationException extends \RuntimeException implements \Serializable { private $extraInformation; - public function __construct($message, $extraInformation = null, $code = 0, \Exception $previous = null) - { - parent::__construct($message, $code, $previous); - - $this->extraInformation = $extraInformation; - } - public function getExtraInformation() { return $this->extraInformation; From ed6eed4c36cf5339c4661b2c4531dddacfa14f1b Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:16:07 +0200 Subject: [PATCH 013/128] [Security] Add `getMessageKey` and `getMessageData` to auth exceptions --- ...enticationCredentialsNotFoundException.php | 8 ++++++++ .../Exception/AuthenticationException.php | 20 +++++++++++++++++++ .../AuthenticationServiceException.php | 8 ++++++++ .../Exception/BadCredentialsException.php | 8 ++++++-- .../Core/Exception/CookieTheftException.php | 8 ++++++++ .../InsufficientAuthenticationException.php | 8 ++++++++ .../Exception/InvalidCsrfTokenException.php | 8 ++++++++ .../Core/Exception/NonceExpiredException.php | 8 ++++++++ .../Exception/ProviderNotFoundException.php | 8 ++++++++ .../Exception/SessionUnavailableException.php | 8 ++++++++ .../Core/Exception/TokenNotFoundException.php | 8 ++++++++ .../Exception/UsernameNotFoundException.php | 8 ++++++++ 12 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php index 16686ade10..1bd8ffdaff 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php @@ -16,7 +16,15 @@ namespace Symfony\Component\Security\Core\Exception; * because no Token is available. * * @author Fabien Potencier + * @author Alexander */ class AuthenticationCredentialsNotFoundException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.authentication_credentials_not_found_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index fbe10ebaa8..93e395bd99 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -52,4 +52,24 @@ class AuthenticationException extends \RuntimeException implements \Serializable $this->line ) = unserialize($str); } + + /** + * Message key to be used by the translation component. + * + * @return string + */ + public function getMessageKey() + { + return 'security.exception.authentication_exception'; + } + + /** + * Message data to be used by the translation component. + * + * @return array + */ + public function getMessageData() + { + return array(); + } } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php index 5b32d8110f..b002067c17 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php @@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * AuthenticationServiceException is thrown when an authentication request could not be processed due to a system problem. * * @author Fabien Potencier + * @author Alexander */ class AuthenticationServiceException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.authentication_service_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php b/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php index 2eae5b811d..3ac48006e0 100644 --- a/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php +++ b/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php @@ -15,11 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * BadCredentialsException is thrown when the user credentials are invalid. * * @author Fabien Potencier + * @author Alexander */ class BadCredentialsException extends AuthenticationException { - public function __construct($message, $code = 0, \Exception $previous = null) + /** + * {@inheritDoc} + */ + public function getMessageKey() { - parent::__construct($message, null, $code, $previous); + return 'security.exception.bad_credentials_exception'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php b/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php index 2ada78d73b..badd7b1018 100644 --- a/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php +++ b/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php @@ -16,7 +16,15 @@ namespace Symfony\Component\Security\Core\Exception; * detects that a presented cookie has already been used by someone else. * * @author Johannes M. Schmitt + * @author Alexander */ class CookieTheftException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.cookie_theft_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php index bbf5517dce..d99c03fa99 100644 --- a/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php @@ -17,7 +17,15 @@ namespace Symfony\Component\Security\Core\Exception; * This is the case when a user is anonymous and the resource to be displayed has an access role. * * @author Fabien Potencier + * @author Alexander */ class InsufficientAuthenticationException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.insufficient_authentication_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php b/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php index 4181bacc01..98a64d0b3a 100644 --- a/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php +++ b/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php @@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * This exception is thrown when the csrf token is invalid. * * @author Johannes M. Schmitt + * @author Alexander */ class InvalidCsrfTokenException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.invalid_csrf_token_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php b/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php index 6a6a7811e3..0e31713e91 100644 --- a/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php +++ b/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php @@ -18,7 +18,15 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException; * the digest nonce has expired. * * @author Fabien Potencier + * @author Alexander */ class NonceExpiredException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.nonce_expired_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php index e11c8aa161..aefe2ae109 100644 --- a/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php @@ -16,7 +16,15 @@ namespace Symfony\Component\Security\Core\Exception; * supports an authentication Token. * * @author Fabien Potencier + * @author Alexander */ class ProviderNotFoundException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.provider_not_found_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php b/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php index 519164a323..ff88c32bb1 100644 --- a/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php +++ b/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php @@ -21,7 +21,15 @@ namespace Symfony\Component\Security\Core\Exception; * request. * * @author Johannes M. Schmitt + * @author Alexander */ class SessionUnavailableException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.session_unavailable_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php index 593f3ad269..da06847b76 100644 --- a/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php @@ -14,7 +14,15 @@ namespace Symfony\Component\Security\Core\Exception; * TokenNotFoundException is thrown if a Token cannot be found. * * @author Johannes M. Schmitt + * @author Alexander */ class TokenNotFoundException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.token_not_found_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php index 38533e7ff3..2dc553403a 100644 --- a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php @@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * UsernameNotFoundException is thrown if a User cannot be found by its username. * * @author Fabien Potencier + * @author Alexander */ class UsernameNotFoundException extends AuthenticationException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.username_not_found_exception'; + } } From 963a1d7b81b4c083d031b629a8bfb933fdf6eea8 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:23:53 +0200 Subject: [PATCH 014/128] [Security] Add initial translations for the exceptions --- .../Resources/translations/exceptions.en.xlf | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf b/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf new file mode 100644 index 0000000000..a14ec4b314 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf @@ -0,0 +1,55 @@ + + + + + + security.exception.authentication_exception + An authentication exception occured. + + + security.exception.authentication_credentials_not_found_exception + Authentication credentials could not be found. + + + security.exception.authentication_service_exception + Authentication request could not be processed due to a system problem. + + + security.exception.bad_credentials_exception + Invalid credentials. + + + security.exception.cookie_theft_exception + Cookie has already been used by someone else. + + + security.exception.insufficient_authentication_exception + Not priviliged to request the resource. + + + security.exception.invalid_csrf_token_exception + Invalid CSRF token. + + + security.exception.nonce_expired_exception + Digest nonce has expired. + + + security.exception.provider_not_found_exception + No authentication provider found to support the authentication token. + + + security.exception.session_unavailable_exception + No session available. + + + security.exception.token_not_found_exception + No token could be found. + + + security.exception.username_not_found_exception + Username could not be found. + + + + From 42cced4c970fa9e08fc19f20ac2129b0cb1025ff Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:26:13 +0200 Subject: [PATCH 015/128] [Security] Fix AuthenticationException constructor calls --- .../Security/Http/RememberMe/TokenBasedRememberMeServices.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php index bd828f265c..5a66fe4539 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php @@ -43,7 +43,7 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices $user = $this->getUserProvider($class)->loadUserByUsername($username); } catch (\Exception $ex) { if (!$ex instanceof AuthenticationException) { - $ex = new AuthenticationException($ex->getMessage(), null, $ex->getCode(), $ex); + $ex = new AuthenticationException($ex->getMessage(), $ex->getCode(), $ex); } throw $ex; From 79430b8238af398c6f53263c267c7e5fc8401cf7 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:31:22 +0200 Subject: [PATCH 016/128] [Security] Fix AuthenticationServiceException constructor calls --- .../Authentication/Provider/DaoAuthenticationProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php index f22045f03d..cbfc39c86d 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php @@ -90,7 +90,9 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider } catch (UsernameNotFoundException $notFound) { throw $notFound; } catch (\Exception $repositoryProblem) { - throw new AuthenticationServiceException($repositoryProblem->getMessage(), $token, 0, $repositoryProblem); + $ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem); + $ex->setExtraInformation($token); + throw $ex; } } } From 1147977212c0b68612ed97569fae9faec6766d3d Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:37:14 +0200 Subject: [PATCH 017/128] [Security] Fix InsufficientAuthenticationException constructor calls --- .../Component/Security/Http/Firewall/ExceptionListener.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index f134f9c819..489e4c4f77 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -106,7 +106,9 @@ class ExceptionListener } try { - $response = $this->startAuthentication($request, new InsufficientAuthenticationException('Full authentication is required to access this resource.', $token, 0, $exception)); + $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception); + $insufficientAuthenticationException->setExtraInformation($token); + $response = $this->startAuthentication($request, $insufficientAuthenticationException); } catch (\Exception $e) { $event->setException($e); From 50e2cfc1f5a7c79bd5e9239eba2c52787cd0841f Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:41:08 +0200 Subject: [PATCH 018/128] [Security] Add custom `getMessageKey` AccountStatusException childs --- .../Security/Core/Exception/AccountExpiredException.php | 8 ++++++++ .../Core/Exception/CredentialsExpiredException.php | 8 ++++++++ .../Security/Core/Exception/DisabledException.php | 8 ++++++++ .../Component/Security/Core/Exception/LockedException.php | 8 ++++++++ 4 files changed, 32 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php b/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php index f899b1b76b..5a3bd50f52 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php @@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * AccountExpiredException is thrown when the user account has expired. * * @author Fabien Potencier + * @author Alexander */ class AccountExpiredException extends AccountStatusException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.account_expired_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php b/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php index a4d42c842f..03f96c3bf4 100644 --- a/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php +++ b/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php @@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * CredentialsExpiredException is thrown when the user account credentials have expired. * * @author Fabien Potencier + * @author Alexander */ class CredentialsExpiredException extends AccountStatusException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.credentials_expired_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/DisabledException.php b/src/Symfony/Component/Security/Core/Exception/DisabledException.php index fd26221502..feb0609701 100644 --- a/src/Symfony/Component/Security/Core/Exception/DisabledException.php +++ b/src/Symfony/Component/Security/Core/Exception/DisabledException.php @@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * DisabledException is thrown when the user account is disabled. * * @author Fabien Potencier + * @author Alexander */ class DisabledException extends AccountStatusException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.disabled_exception'; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/LockedException.php b/src/Symfony/Component/Security/Core/Exception/LockedException.php index 6fa0b778f7..f185a02791 100644 --- a/src/Symfony/Component/Security/Core/Exception/LockedException.php +++ b/src/Symfony/Component/Security/Core/Exception/LockedException.php @@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception; * LockedException is thrown if the user account is locked. * * @author Fabien Potencier + * @author Alexander */ class LockedException extends AccountStatusException { + /** + * {@inheritDoc} + */ + public function getMessageKey() + { + return 'security.exception.locked_exception'; + } } From 0038fbb8b6a649abce98e47085eca7de631952ff Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:44:07 +0200 Subject: [PATCH 019/128] [Security] Add initial translations for AccountStatusException childs --- .../Resources/translations/exceptions.en.xlf | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf b/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf index a14ec4b314..7a3fac6313 100644 --- a/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf +++ b/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf @@ -50,6 +50,22 @@ security.exception.username_not_found_exception Username could not be found. + + security.exception.account_expired_exception + Account has expired. + + + security.exception.credentials_expired_exception + Credentials have expired. + + + security.exception.credentials_expired_exception + Account is disabled. + + + security.exception.credentials_expired_exception + Account is locked. + From d7129b9a7e8b85b22e2559afe3bc5c6550494605 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:47:39 +0200 Subject: [PATCH 020/128] [Security] Fix exception constructors called in `UserChecker` --- .../Component/Security/Core/User/UserChecker.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Security/Core/User/UserChecker.php b/src/Symfony/Component/Security/Core/User/UserChecker.php index 93897a1010..955cb19bbd 100644 --- a/src/Symfony/Component/Security/Core/User/UserChecker.php +++ b/src/Symfony/Component/Security/Core/User/UserChecker.php @@ -33,7 +33,9 @@ class UserChecker implements UserCheckerInterface } if (!$user->isCredentialsNonExpired()) { - throw new CredentialsExpiredException('User credentials have expired.', $user); + $ex = new CredentialsExpiredException('User credentials have expired.'); + $ex->setExtraInformation($user); + throw $ex; } } @@ -47,15 +49,21 @@ class UserChecker implements UserCheckerInterface } if (!$user->isAccountNonLocked()) { - throw new LockedException('User account is locked.', $user); + $ex = new LockedException('User account is locked.'); + $ex->setExtraInformation($user); + throw $ex; } if (!$user->isEnabled()) { - throw new DisabledException('User account is disabled.', $user); + throw new DisabledException('User account is disabled.'); + $ex->setExtraInformation($user); + throw $ex; } if (!$user->isAccountNonExpired()) { - throw new AccountExpiredException('User account has expired.', $user); + $ex = new AccountExpiredException('User account has expired.'); + $ex->setExtraInformation($user); + throw $ex; } } } From d6c57cff6f1a1acc679eab8ba7ec8c5be3df2c47 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 15:56:45 +0200 Subject: [PATCH 021/128] [FrameworkBundle] Register security exception translations --- .../DependencyInjection/FrameworkExtension.php | 5 +++++ .../Tests/DependencyInjection/FrameworkExtensionTest.php | 5 +++++ src/Symfony/Bundle/FrameworkBundle/composer.json | 3 ++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 1ec5e9e2ae..92cc1cef08 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -527,6 +527,11 @@ class FrameworkExtension extends Extension $dirs[] = dirname($r->getFilename()).'/Resources/translations'; } + if (class_exists('Symfony\Component\Security\Core\Exception\AuthenticationException')) { + $r = new \ReflectionClass('Symfony\Component\Security\Core\Exception\AuthenticationException'); + + $dirs[] = dirname($r->getFilename()).'/../../Resources/translations'; + } $overridePath = $container->getParameter('kernel.root_dir').'/Resources/%s/translations'; foreach ($container->getParameter('kernel.bundles') as $bundle => $class) { $reflection = new \ReflectionClass($class); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 3203f37bca..d60406f871 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -205,6 +205,11 @@ abstract class FrameworkExtensionTest extends TestCase $files, '->registerTranslatorConfiguration() finds Form translation resources' ); + $this->assertContains( + 'Symfony/Component/Security/Resources/translations/exceptions.en.xlf', + $files, + '->registerTranslatorConfiguration() finds Security translation resources' + ); $calls = $container->getDefinition('translator.default')->getMethodCalls(); $this->assertEquals('fr', $calls[0][1][0]); diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 3f2ad2f0c1..12bc33d882 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -29,7 +29,8 @@ "doctrine/common": ">=2.2,<2.4-dev" }, "require-dev": { - "symfony/finder": "2.2.*" + "symfony/finder": "2.2.*", + "symfony/security": "2.2.*" }, "suggest": { "symfony/console": "2.2.*", From 837ae151029322cf50b840ab0a878f81850f7fbd Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 16:00:04 +0200 Subject: [PATCH 022/128] [Security] Add note about changed constructor to changelog --- src/Symfony/Component/Security/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 1305b28335..9fb4c1d579 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -34,3 +34,6 @@ CHANGELOG `AbstractAuthenticationListener` has changed. * [BC BREAK] moved the default logout success handling to a separate class. The order of arguments in the constructor of `LogoutListener` has changed. + * [BC BREAK] The constructor of `AuthenticationException` and all child + classes now matches the constructor of `\Exception`. Extra information + should be passed via the `setExtraInformation` setter. From 39da27a06d02e44ed02d91830e0ed9b75b507e01 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 17:26:18 +0200 Subject: [PATCH 023/128] [Security] Removed `get/setExtraInformation`, added `get/set(Token|User)` --- src/Symfony/Component/Security/CHANGELOG.md | 5 ++-- .../AuthenticationProviderManager.php | 4 ++-- .../Provider/DaoAuthenticationProvider.php | 2 +- .../Core/Exception/AccountStatusException.php | 24 +++++++++++++++++++ .../Exception/AuthenticationException.php | 22 +++++++++++++---- .../Security/Core/User/UserChecker.php | 8 +++---- .../Http/Firewall/ExceptionListener.php | 2 +- .../AuthenticationProviderManagerTest.php | 6 ++--- 8 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 9fb4c1d579..d897fc3a52 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -35,5 +35,6 @@ CHANGELOG * [BC BREAK] moved the default logout success handling to a separate class. The order of arguments in the constructor of `LogoutListener` has changed. * [BC BREAK] The constructor of `AuthenticationException` and all child - classes now matches the constructor of `\Exception`. Extra information - should be passed via the `setExtraInformation` setter. + classes now matches the constructor of `\Exception`. The extra information + getters and setters are removed. There are now dedicated getters/setters for + token (`AuthenticationException') and user (`AccountStatusException`). diff --git a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php index b0414f0fff..8b7474bec4 100644 --- a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php +++ b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php @@ -77,7 +77,7 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface break; } } catch (AccountStatusException $e) { - $e->setExtraInformation($token); + $e->setToken($token); throw $e; } catch (AuthenticationException $e) { @@ -105,7 +105,7 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface $this->eventDispatcher->dispatch(AuthenticationEvents::AUTHENTICATION_FAILURE, new AuthenticationFailureEvent($token, $lastException)); } - $lastException->setExtraInformation($token); + $lastException->setToken($token); throw $lastException; } diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php index cbfc39c86d..8647382d6a 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php @@ -91,7 +91,7 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider throw $notFound; } catch (\Exception $repositoryProblem) { $ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem); - $ex->setExtraInformation($token); + $ex->setToken($token); throw $ex; } } diff --git a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php index 958f584f4e..5a166731d2 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php @@ -11,12 +11,36 @@ namespace Symfony\Component\Security\Core\Exception; +use Symfony\Component\Security\Core\User\UserInterface; + /** * AccountStatusException is the base class for authentication exceptions * caused by the user account status. * * @author Fabien Potencier + * @author Alexander */ abstract class AccountStatusException extends AuthenticationException { + private $user; + + /** + * Get the user. + * + * @return UserInterface + */ + public function getUser() + { + return $this->user; + } + + /** + * Set the user. + * + * @param UserInterface $user + */ + public function setUser(UserInterface $user) + { + $this->user = $user; + } } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index 93e395bd99..d67d41e95e 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Core\Exception; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + /** * AuthenticationException is the base class for all authentication exceptions. * @@ -19,16 +21,26 @@ namespace Symfony\Component\Security\Core\Exception; */ class AuthenticationException extends \RuntimeException implements \Serializable { - private $extraInformation; + private $token; - public function getExtraInformation() + /** + * Get the token. + * + * @return TokenInterface + */ + public function getToken() { - return $this->extraInformation; + return $this->token; } - public function setExtraInformation($extraInformation) + /** + * Set the token. + * + * @param TokenInterface $token + */ + public function setToken(TokenInterface $token) { - $this->extraInformation = $extraInformation; + $this->token = $token; } public function serialize() diff --git a/src/Symfony/Component/Security/Core/User/UserChecker.php b/src/Symfony/Component/Security/Core/User/UserChecker.php index 955cb19bbd..414bc315eb 100644 --- a/src/Symfony/Component/Security/Core/User/UserChecker.php +++ b/src/Symfony/Component/Security/Core/User/UserChecker.php @@ -34,7 +34,7 @@ class UserChecker implements UserCheckerInterface if (!$user->isCredentialsNonExpired()) { $ex = new CredentialsExpiredException('User credentials have expired.'); - $ex->setExtraInformation($user); + $ex->setUser($user); throw $ex; } } @@ -50,19 +50,19 @@ class UserChecker implements UserCheckerInterface if (!$user->isAccountNonLocked()) { $ex = new LockedException('User account is locked.'); - $ex->setExtraInformation($user); + $ex->setUser($user); throw $ex; } if (!$user->isEnabled()) { throw new DisabledException('User account is disabled.'); - $ex->setExtraInformation($user); + $ex->setUser($user); throw $ex; } if (!$user->isAccountNonExpired()) { $ex = new AccountExpiredException('User account has expired.'); - $ex->setExtraInformation($user); + $ex->setUser($user); throw $ex; } } diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 489e4c4f77..99389ef5a5 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -107,7 +107,7 @@ class ExceptionListener try { $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception); - $insufficientAuthenticationException->setExtraInformation($token); + $insufficientAuthenticationException->setToken($token); $response = $this->startAuthentication($request, $insufficientAuthenticationException); } catch (\Exception $e) { $event->setException($e); diff --git a/src/Symfony/Component/Security/Tests/Core/Authentication/AuthenticationProviderManagerTest.php b/src/Symfony/Component/Security/Tests/Core/Authentication/AuthenticationProviderManagerTest.php index c57967bfa4..12eb568a29 100644 --- a/src/Symfony/Component/Security/Tests/Core/Authentication/AuthenticationProviderManagerTest.php +++ b/src/Symfony/Component/Security/Tests/Core/Authentication/AuthenticationProviderManagerTest.php @@ -37,7 +37,7 @@ class AuthenticationProviderManagerTest extends \PHPUnit_Framework_TestCase $manager->authenticate($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')); $this->fail(); } catch (ProviderNotFoundException $e) { - $this->assertSame($token, $e->getExtraInformation()); + $this->assertSame($token, $e->getToken()); } } @@ -51,7 +51,7 @@ class AuthenticationProviderManagerTest extends \PHPUnit_Framework_TestCase $manager->authenticate($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')); $this->fail(); } catch (AccountStatusException $e) { - $this->assertSame($token, $e->getExtraInformation()); + $this->assertSame($token, $e->getToken()); } } @@ -65,7 +65,7 @@ class AuthenticationProviderManagerTest extends \PHPUnit_Framework_TestCase $manager->authenticate($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')); $this->fail(); } catch (AuthenticationException $e) { - $this->assertSame($token, $e->getExtraInformation()); + $this->assertSame($token, $e->getToken()); } } From 50d5724c238bd08e3a43ce0a076c4288e25e6a3b Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 17:38:53 +0200 Subject: [PATCH 024/128] [Security] Introduced `UsernameNotFoundException#get/setUsername` --- src/Symfony/Component/Security/CHANGELOG.md | 3 ++- .../Provider/DaoAuthenticationProvider.php | 1 + .../Provider/UserAuthenticationProvider.php | 1 + .../Exception/UsernameNotFoundException.php | 22 +++++++++++++++++++ .../Security/Core/User/ChainUserProvider.php | 8 +++++-- .../Core/User/InMemoryUserProvider.php | 5 ++++- 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index d897fc3a52..83914b16bc 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -37,4 +37,5 @@ CHANGELOG * [BC BREAK] The constructor of `AuthenticationException` and all child classes now matches the constructor of `\Exception`. The extra information getters and setters are removed. There are now dedicated getters/setters for - token (`AuthenticationException') and user (`AccountStatusException`). + token (`AuthenticationException'), user (`AccountStatusException`) and + username (`UsernameNotFoundException`). diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php index 8647382d6a..a9a22056d6 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php @@ -88,6 +88,7 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider return $user; } catch (UsernameNotFoundException $notFound) { + $notFound->setUsername($username); throw $notFound; } catch (\Exception $repositoryProblem) { $ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem); diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php index ed8f4995e1..626f50b8b5 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php @@ -71,6 +71,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter if ($this->hideUserNotFoundExceptions) { throw new BadCredentialsException('Bad credentials', 0, $notFound); } + $notFound->setUsername($username); throw $notFound; } diff --git a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php index 2dc553403a..421fada497 100644 --- a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php @@ -19,6 +19,8 @@ namespace Symfony\Component\Security\Core\Exception; */ class UsernameNotFoundException extends AuthenticationException { + private $username; + /** * {@inheritDoc} */ @@ -26,4 +28,24 @@ class UsernameNotFoundException extends AuthenticationException { return 'security.exception.username_not_found_exception'; } + + /** + * Get the username. + * + * @return string + */ + public function getUsername() + { + return $this->username; + } + + /** + * Set the username. + * + * @param string $username + */ + public function setUsername($username) + { + $this->username = $username; + } } diff --git a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php index 376ba1c724..3ff1ea9372 100644 --- a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php @@ -44,7 +44,9 @@ class ChainUserProvider implements UserProviderInterface } } - throw new UsernameNotFoundException(sprintf('There is no user with name "%s".', $username)); + $ex = new UsernameNotFoundException(sprintf('There is no user with name "%s".', $username)); + $ex->setUsername($username); + throw $ex; } /** @@ -66,7 +68,9 @@ class ChainUserProvider implements UserProviderInterface } if ($supportedUserFound) { - throw new UsernameNotFoundException(sprintf('There is no user with name "%s".', $user->getUsername())); + $ex = new UsernameNotFoundException(sprintf('There is no user with name "%s".', $user->getUsername())); + $ex->setUsername($user->getUsername()); + throw $ex; } else { throw new UnsupportedUserException(sprintf('The account "%s" is not supported.', get_class($user))); } diff --git a/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php b/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php index bd74804487..e87f80c10a 100644 --- a/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/InMemoryUserProvider.php @@ -68,7 +68,10 @@ class InMemoryUserProvider implements UserProviderInterface public function loadUserByUsername($username) { if (!isset($this->users[strtolower($username)])) { - throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username)); + $ex = new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username)); + $ex->setUsername($username); + + throw $ex; } $user = $this->users[strtolower($username)]; From 2d7a7ba139a8a758dadb019f6f2f27eb59589041 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sun, 15 Jul 2012 17:46:50 +0200 Subject: [PATCH 025/128] [Security] Fix `AuthenticationException` serialization --- .../Core/Exception/AccountStatusException.php | 23 +++++++++++++++++++ .../Exception/AuthenticationException.php | 4 ++-- .../Exception/UsernameNotFoundException.php | 23 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php index 5a166731d2..d89d553a53 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php @@ -43,4 +43,27 @@ abstract class AccountStatusException extends AuthenticationException { $this->user = $user; } + + /** + * {@inheritDoc} + */ + public function serialize() + { + return serialize(array( + $this->user, + parent::serialize(), + )); + } + + /** + * {@inheritDoc} + */ + public function unserialize($str) + { + list( + $this->user, + $parentData + ) = unserialize($str); + parent::unserialize($parentData); + } } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index d67d41e95e..7958ff78c1 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -46,7 +46,7 @@ class AuthenticationException extends \RuntimeException implements \Serializable public function serialize() { return serialize(array( - $this->extraInformation, + $this->token, $this->code, $this->message, $this->file, @@ -57,7 +57,7 @@ class AuthenticationException extends \RuntimeException implements \Serializable public function unserialize($str) { list( - $this->extraInformation, + $this->token, $this->code, $this->message, $this->file, diff --git a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php index 421fada497..9a9989f096 100644 --- a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php @@ -48,4 +48,27 @@ class UsernameNotFoundException extends AuthenticationException { $this->username = $username; } + + /** + * {@inheritDoc} + */ + public function serialize() + { + return serialize(array( + $this->username, + parent::serialize(), + )); + } + + /** + * {@inheritDoc} + */ + public function unserialize($str) + { + list( + $this->username, + $parentData + ) = unserialize($str); + parent::unserialize($parentData); + } } From aa7476967a99903be91ece62cdba383ebef26011 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 7 Jan 2013 20:34:14 +0100 Subject: [PATCH 026/128] [Security] Fix CS + unreachable code --- .../Security/Core/Exception/AccountStatusException.php | 6 ++---- .../Security/Core/Exception/UsernameNotFoundException.php | 6 ++---- src/Symfony/Component/Security/Core/User/UserChecker.php | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php index d89d553a53..7819e4dd09 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php @@ -60,10 +60,8 @@ abstract class AccountStatusException extends AuthenticationException */ public function unserialize($str) { - list( - $this->user, - $parentData - ) = unserialize($str); + list($this->user, $parentData) = unserialize($str); + parent::unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php index 9a9989f096..0299f839ac 100644 --- a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php @@ -65,10 +65,8 @@ class UsernameNotFoundException extends AuthenticationException */ public function unserialize($str) { - list( - $this->username, - $parentData - ) = unserialize($str); + list($this->username, $parentData) = unserialize($str); + parent::unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/User/UserChecker.php b/src/Symfony/Component/Security/Core/User/UserChecker.php index 414bc315eb..8dde3a6670 100644 --- a/src/Symfony/Component/Security/Core/User/UserChecker.php +++ b/src/Symfony/Component/Security/Core/User/UserChecker.php @@ -55,7 +55,7 @@ class UserChecker implements UserCheckerInterface } if (!$user->isEnabled()) { - throw new DisabledException('User account is disabled.'); + $ex = new DisabledException('User account is disabled.'); $ex->setUser($user); throw $ex; } From 324703a9ff6c54e8bde784e0c54410ad957e61bc Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 7 Jan 2013 20:55:10 +0100 Subject: [PATCH 027/128] [Security] Switch to English messages as message keys --- .../Security/Core/Exception/AccountExpiredException.php | 2 +- .../Exception/AuthenticationCredentialsNotFoundException.php | 2 +- .../Security/Core/Exception/AuthenticationException.php | 2 +- .../Core/Exception/AuthenticationServiceException.php | 2 +- .../Security/Core/Exception/BadCredentialsException.php | 2 +- .../Security/Core/Exception/CookieTheftException.php | 2 +- .../Security/Core/Exception/CredentialsExpiredException.php | 2 +- .../Component/Security/Core/Exception/DisabledException.php | 2 +- .../Core/Exception/InsufficientAuthenticationException.php | 2 +- .../Security/Core/Exception/InvalidCsrfTokenException.php | 2 +- .../Component/Security/Core/Exception/LockedException.php | 2 +- .../Security/Core/Exception/NonceExpiredException.php | 2 +- .../Security/Core/Exception/ProviderNotFoundException.php | 2 +- .../Security/Core/Exception/SessionUnavailableException.php | 2 +- .../Security/Core/Exception/TokenNotFoundException.php | 5 +++-- .../Security/Core/Exception/UsernameNotFoundException.php | 2 +- 16 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php b/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php index 5a3bd50f52..a5618ce621 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountExpiredException.php @@ -24,6 +24,6 @@ class AccountExpiredException extends AccountStatusException */ public function getMessageKey() { - return 'security.exception.account_expired_exception'; + return 'Account has expired.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php index 1bd8ffdaff..633b2bee92 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationCredentialsNotFoundException.php @@ -25,6 +25,6 @@ class AuthenticationCredentialsNotFoundException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.authentication_credentials_not_found_exception'; + return 'Authentication credentials could not be found.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index 7958ff78c1..2b897c2513 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -72,7 +72,7 @@ class AuthenticationException extends \RuntimeException implements \Serializable */ public function getMessageKey() { - return 'security.exception.authentication_exception'; + return 'An authentication exception occurred.'; } /** diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php index b002067c17..758a4f0245 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationServiceException.php @@ -24,6 +24,6 @@ class AuthenticationServiceException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.authentication_service_exception'; + return 'Authentication request could not be processed due to a system problem.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php b/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php index 3ac48006e0..5deecca9b3 100644 --- a/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php +++ b/src/Symfony/Component/Security/Core/Exception/BadCredentialsException.php @@ -24,6 +24,6 @@ class BadCredentialsException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.bad_credentials_exception'; + return 'Invalid credentials.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php b/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php index badd7b1018..8d9e154944 100644 --- a/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php +++ b/src/Symfony/Component/Security/Core/Exception/CookieTheftException.php @@ -25,6 +25,6 @@ class CookieTheftException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.cookie_theft_exception'; + return 'Cookie has already been used by someone else.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php b/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php index 03f96c3bf4..b9bf2d158a 100644 --- a/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php +++ b/src/Symfony/Component/Security/Core/Exception/CredentialsExpiredException.php @@ -24,6 +24,6 @@ class CredentialsExpiredException extends AccountStatusException */ public function getMessageKey() { - return 'security.exception.credentials_expired_exception'; + return 'Credentials have expired.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/DisabledException.php b/src/Symfony/Component/Security/Core/Exception/DisabledException.php index feb0609701..5571ab14a9 100644 --- a/src/Symfony/Component/Security/Core/Exception/DisabledException.php +++ b/src/Symfony/Component/Security/Core/Exception/DisabledException.php @@ -24,6 +24,6 @@ class DisabledException extends AccountStatusException */ public function getMessageKey() { - return 'security.exception.disabled_exception'; + return 'Account is disabled.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php index d99c03fa99..74fc2b9b64 100644 --- a/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/InsufficientAuthenticationException.php @@ -26,6 +26,6 @@ class InsufficientAuthenticationException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.insufficient_authentication_exception'; + return 'Not privileged to request the resource.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php b/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php index 98a64d0b3a..ce0e1f410e 100644 --- a/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php +++ b/src/Symfony/Component/Security/Core/Exception/InvalidCsrfTokenException.php @@ -24,6 +24,6 @@ class InvalidCsrfTokenException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.invalid_csrf_token_exception'; + return 'Invalid CSRF token.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/LockedException.php b/src/Symfony/Component/Security/Core/Exception/LockedException.php index f185a02791..6532f70a53 100644 --- a/src/Symfony/Component/Security/Core/Exception/LockedException.php +++ b/src/Symfony/Component/Security/Core/Exception/LockedException.php @@ -24,6 +24,6 @@ class LockedException extends AccountStatusException */ public function getMessageKey() { - return 'security.exception.locked_exception'; + return 'Account is locked.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php b/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php index 0e31713e91..da6fba82b7 100644 --- a/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php +++ b/src/Symfony/Component/Security/Core/Exception/NonceExpiredException.php @@ -27,6 +27,6 @@ class NonceExpiredException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.nonce_expired_exception'; + return 'Digest nonce has expired.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php index aefe2ae109..ea2b1fdf1f 100644 --- a/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/ProviderNotFoundException.php @@ -25,6 +25,6 @@ class ProviderNotFoundException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.provider_not_found_exception'; + return 'No authentication provider found to support the authentication token.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php b/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php index ff88c32bb1..4b47b189ef 100644 --- a/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php +++ b/src/Symfony/Component/Security/Core/Exception/SessionUnavailableException.php @@ -30,6 +30,6 @@ class SessionUnavailableException extends AuthenticationException */ public function getMessageKey() { - return 'security.exception.session_unavailable_exception'; + return 'No session available, it either timed out or cookies are not enabled.'; } } diff --git a/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php index da06847b76..fb85abf0cf 100644 --- a/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/TokenNotFoundException.php @@ -1,5 +1,4 @@ Date: Mon, 7 Jan 2013 20:57:06 +0100 Subject: [PATCH 028/128] [Security] Move translations file to 'security' domain --- .../FrameworkExtensionTest.php | 2 +- .../{exceptions.en.xlf => security.en.xlf} | 38 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) rename src/Symfony/Component/Security/Resources/translations/{exceptions.en.xlf => security.en.xlf} (57%) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index d60406f871..129ae0aa4d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -206,7 +206,7 @@ abstract class FrameworkExtensionTest extends TestCase '->registerTranslatorConfiguration() finds Form translation resources' ); $this->assertContains( - 'Symfony/Component/Security/Resources/translations/exceptions.en.xlf', + 'Symfony/Component/Security/Resources/translations/security.en.xlf', $files, '->registerTranslatorConfiguration() finds Security translation resources' ); diff --git a/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf b/src/Symfony/Component/Security/Resources/translations/security.en.xlf similarity index 57% rename from src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf rename to src/Symfony/Component/Security/Resources/translations/security.en.xlf index 7a3fac6313..3640698ce9 100644 --- a/src/Symfony/Component/Security/Resources/translations/exceptions.en.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.en.xlf @@ -3,67 +3,67 @@ - security.exception.authentication_exception - An authentication exception occured. + An authentication exception occurred. + An authentication exception occurred. - security.exception.authentication_credentials_not_found_exception + Authentication credentials could not be found. Authentication credentials could not be found. - security.exception.authentication_service_exception + Authentication request could not be processed due to a system problem. Authentication request could not be processed due to a system problem. - security.exception.bad_credentials_exception + Invalid credentials. Invalid credentials. - security.exception.cookie_theft_exception + Cookie has already been used by someone else. Cookie has already been used by someone else. - security.exception.insufficient_authentication_exception - Not priviliged to request the resource. + Not privileged to request the resource. + Not privileged to request the resource. - security.exception.invalid_csrf_token_exception + Invalid CSRF token. Invalid CSRF token. - security.exception.nonce_expired_exception + Digest nonce has expired. Digest nonce has expired. - security.exception.provider_not_found_exception + No authentication provider found to support the authentication token. No authentication provider found to support the authentication token. - security.exception.session_unavailable_exception - No session available. + No session available, it either timed out or cookies are not enabled. + No session available, it either timed out or cookies are not enabled. - security.exception.token_not_found_exception + No token could be found. No token could be found. - security.exception.username_not_found_exception + Username could not be found. Username could not be found. - security.exception.account_expired_exception + Account has expired. Account has expired. - security.exception.credentials_expired_exception + Credentials have expired. Credentials have expired. - security.exception.credentials_expired_exception + Account is disabled. Account is disabled. - security.exception.credentials_expired_exception + Account is locked. Account is locked. From 1d362b884937a6efac6c3ab3f39160e4080e7cf5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 7 Jan 2013 22:32:53 +0100 Subject: [PATCH 029/128] [DependencyInjection] fixed a bug where the strict flag on references were lost (closes #6607) --- .../Compiler/ResolveInvalidReferencesPass.php | 2 +- .../Compiler/ResolveInvalidReferencesPassTest.php | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php index 66e217146b..4327fdacf1 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php @@ -88,7 +88,7 @@ class ResolveInvalidReferencesPass implements CompilerPassInterface // resolve invalid behavior if ($exists && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) { - $arguments[$k] = new Reference($id); + $arguments[$k] = new Reference($id, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $argument->isStrict()); } elseif (!$exists && ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) { $arguments[$k] = null; } elseif (!$exists && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) { diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPassTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPassTest.php index 6c8f312495..be5cdb0313 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPassTest.php +++ b/tests/Symfony/Tests/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPassTest.php @@ -61,6 +61,20 @@ class ResolveInvalidReferencesPassTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array(), $def->getProperties()); } + public function testStrictFlagIsPreserved() + { + $container = new ContainerBuilder(); + $container->register('bar'); + $def = $container + ->register('foo') + ->addArgument(new Reference('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE, false)) + ; + + $this->process($container); + + $this->assertFalse($def->getArgument(0)->isStrict()); + } + protected function process(ContainerBuilder $container) { $pass = new ResolveInvalidReferencesPass(); From ae3d4541a942118413bc89b19a802b560a924a6d Mon Sep 17 00:00:00 2001 From: Douglas Greenshields Date: Mon, 7 Jan 2013 22:34:59 +0000 Subject: [PATCH 030/128] [Form] corrected source node for a Danish translation --- .../Component/Form/Resources/translations/validators.da.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf index 9663cb6f17..c2dd4601f9 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.da.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.da.xlf @@ -11,7 +11,7 @@ Den oploadede fil var for stor. Opload venligst en mindre fil. - The CSRF token is invalid. + The CSRF token is invalid. Please try to resubmit the form. CSRF nøglen er ugyldig. From 8da2b412b4380f7ef439d17eb9daf0c912539403 Mon Sep 17 00:00:00 2001 From: Igor Wiedler Date: Tue, 8 Jan 2013 02:14:26 +0100 Subject: [PATCH 031/128] [TwigBundle] There is no CSS visibility of display, should be visible instead --- .../TwigBundle/Resources/views/Exception/trace.html.twig | 4 ++-- .../TwigBundle/Resources/views/Exception/traces.html.twig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/trace.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/trace.html.twig index cc2e0ddf22..5df02f1b80 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/trace.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/trace.html.twig @@ -12,8 +12,8 @@ in {{ trace.file|format_file(trace.line) }}  {% spaceless %} - - - + + - + + {% endspaceless %}
diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/traces.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/traces.html.twig index da0b5b8dd1..5ee11ee836 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/traces.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/Exception/traces.html.twig @@ -5,8 +5,8 @@ {{ exception.class|abbr_class }}: {{ exception.message|e|replace({"\n": '
'})|format_file_from_text }}  {% spaceless %} - - - + + - + + {% endspaceless %} From 55aa0120cf2193355b74eec509e216123e74d73d Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 8 Jan 2013 11:08:32 +0100 Subject: [PATCH 032/128] [Form] Fixed EntityChoiceList when loading objects with negative integer IDs --- .../Form/ChoiceList/EntityChoiceList.php | 19 +++++++- .../Form/ChoiceList/EntityChoiceListTest.php | 43 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php index 2e385a343f..e34c3e5bf4 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php @@ -329,7 +329,7 @@ class EntityChoiceList extends ObjectChoiceList protected function createIndex($entity) { if ($this->idAsIndex) { - return current($this->getIdentifierValues($entity)); + return $this->fixIndex(current($this->getIdentifierValues($entity))); } return parent::createIndex($entity); @@ -355,6 +355,23 @@ class EntityChoiceList extends ObjectChoiceList return parent::createValue($entity); } + /** + * {@inheritdoc} + */ + protected function fixIndex($index) + { + $index = parent::fixIndex($index); + + // If the ID is a single-field integer identifier, it is used as + // index. Replace any leading minus by underscore to make it a valid + // form name. + if ($this->idAsIndex && $index < 0) { + $index = strtr($index, '-', '_'); + } + + return $index; + } + /** * Loads the list with entities. */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/EntityChoiceListTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/EntityChoiceListTest.php index 3a2e9bba9f..e93ab1078d 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/EntityChoiceListTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/EntityChoiceListTest.php @@ -312,4 +312,47 @@ class EntityChoiceListTest extends DoctrineOrmTestCase $this->assertSame(array(0 => $entity1, 1 => $entity2), $choiceList->getChoices()); } + + public function testMinusReplacedByUnderscoreInNegativeIntIds() + { + $entity1 = new SingleIdentEntity(-1, 'Foo'); + $entity2 = new SingleIdentEntity(1, 'Bar'); + + // Persist for managed state + $this->em->persist($entity1); + $this->em->persist($entity2); + $this->em->flush(); + + $choiceList = new EntityChoiceList( + $this->em, + self::SINGLE_IDENT_CLASS, + 'name' + ); + + $this->assertSame(array('_1' => $entity1, 1 => $entity2), $choiceList->getChoices()); + $this->assertSame(array('_1', 1), $choiceList->getIndicesForChoices(array($entity1, $entity2))); + $this->assertSame(array('_1', 1), $choiceList->getIndicesForValues(array('-1', '1'))); + } + + public function testMinusReplacedByUnderscoreIfNotLoaded() + { + $entity1 = new SingleIdentEntity(-1, 'Foo'); + $entity2 = new SingleIdentEntity(1, 'Bar'); + + // Persist for managed state + $this->em->persist($entity1); + $this->em->persist($entity2); + $this->em->flush(); + + $choiceList = new EntityChoiceList( + $this->em, + self::SINGLE_IDENT_CLASS, + 'name' + ); + + // no getChoices()! + + $this->assertSame(array('_1', 1), $choiceList->getIndicesForChoices(array($entity1, $entity2))); + $this->assertSame(array('_1', 1), $choiceList->getIndicesForValues(array('-1', '1'))); + } } From 46f751ccf258a6c4a4271c71b27c1fadf01668c4 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 27 Nov 2012 22:42:05 +0100 Subject: [PATCH 033/128] [Validator] Extracted message interpolation logic of ConstraintViolation and used the Translation component for that --- src/Symfony/Component/Validator/CHANGELOG.md | 2 + .../Validator/ConstraintViolation.php | 19 ++-- .../Component/Validator/DefaultTranslator.php | 57 ++++++++++ .../Component/Validator/ExecutionContext.php | 37 ++++++- .../Component/Validator/GraphWalker.php | 19 +++- .../Tests/ConstraintViolationListTest.php | 2 +- .../Tests/ConstraintViolationTest.php | 1 + .../Validator/Tests/ExecutionContextTest.php | 103 +++++++++++++++--- .../Validator/Tests/GraphWalkerTest.php | 11 +- .../Validator/Tests/ValidationVisitorTest.php | 16 ++- .../Validator/Tests/ValidatorBuilderTest.php | 16 ++- .../Validator/Tests/ValidatorContextTest.php | 3 +- .../Validator/Tests/ValidatorFactoryTest.php | 3 +- .../Validator/Tests/ValidatorTest.php | 14 ++- .../Component/Validator/ValidationVisitor.php | 21 +++- src/Symfony/Component/Validator/Validator.php | 26 ++++- .../Component/Validator/ValidatorBuilder.php | 34 +++++- .../Validator/ValidatorBuilderInterface.php | 23 ++++ .../Component/Validator/ValidatorContext.php | 3 +- src/Symfony/Component/Validator/composer.json | 3 +- 20 files changed, 364 insertions(+), 49 deletions(-) create mode 100644 src/Symfony/Component/Validator/DefaultTranslator.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 20d499f855..b037079365 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -28,6 +28,8 @@ CHANGELOG As of Symfony 2.3, this method will be typed against `MetadataFactoryInterface` instead. * [BC BREAK] the switches `traverse` and `deep` in the `Valid` constraint and in `GraphWalker::walkReference` are ignored for arrays now. Arrays are always traversed recursively. + * added dependency to Translation component + * violation messages are now translated with a TranslatorInterface implementation 2.1.0 ----- diff --git a/src/Symfony/Component/Validator/ConstraintViolation.php b/src/Symfony/Component/Validator/ConstraintViolation.php index 7b6f1e1928..8f73d50c85 100644 --- a/src/Symfony/Component/Validator/ConstraintViolation.php +++ b/src/Symfony/Component/Validator/ConstraintViolation.php @@ -18,6 +18,11 @@ namespace Symfony\Component\Validator; */ class ConstraintViolation implements ConstraintViolationInterface { + /** + * @var string + */ + private $message; + /** * @var string */ @@ -56,6 +61,7 @@ class ConstraintViolation implements ConstraintViolationInterface /** * Creates a new constraint violation. * + * @param string $message The violation message. * @param string $messageTemplate The raw violation message. * @param array $messageParameters The parameters to substitute * in the raw message. @@ -70,8 +76,9 @@ class ConstraintViolation implements ConstraintViolationInterface * @param mixed $code The error code of the * violation, if any. */ - public function __construct($messageTemplate, array $messageParameters, $root, $propertyPath, $invalidValue, $messagePluralization = null, $code = null) + public function __construct($message, $messageTemplate, array $messageParameters, $root, $propertyPath, $invalidValue, $messagePluralization = null, $code = null) { + $this->message = $message; $this->messageTemplate = $messageTemplate; $this->messageParameters = $messageParameters; $this->messagePluralization = $messagePluralization; @@ -132,15 +139,7 @@ class ConstraintViolation implements ConstraintViolationInterface */ public function getMessage() { - $parameters = $this->messageParameters; - - foreach ($parameters as $i => $parameter) { - if (is_array($parameter)) { - $parameters[$i] = 'Array'; - } - } - - return strtr($this->messageTemplate, $parameters); + return $this->message; } /** diff --git a/src/Symfony/Component/Validator/DefaultTranslator.php b/src/Symfony/Component/Validator/DefaultTranslator.php new file mode 100644 index 0000000000..850e0f1e16 --- /dev/null +++ b/src/Symfony/Component/Validator/DefaultTranslator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator; + +use Symfony\Component\Translation\TranslatorInterface; + +/** + * Simple translator implementation that simply replaces the parameters in + * the message IDs. + * + * Does not support translation domains or locales. + * + * @author Bernhard Schussek + */ +class DefaultTranslator implements TranslatorInterface +{ + /** + * {@inheritdoc} + */ + public function trans($id, array $parameters = array(), $domain = null, $locale = null) + { + return strtr($id, $parameters); + } + + /** + * {@inheritdoc} + */ + public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) + { + return strtr($id, $parameters); + } + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + throw new \BadMethodCallException('Unsupported method.'); + } + + /** + * {@inheritdoc} + */ + public function getLocale() + { + throw new \BadMethodCallException('Unsupported method.'); + } +} diff --git a/src/Symfony/Component/Validator/ExecutionContext.php b/src/Symfony/Component/Validator/ExecutionContext.php index bfcaba891f..864f749da8 100644 --- a/src/Symfony/Component/Validator/ExecutionContext.php +++ b/src/Symfony/Component/Validator/ExecutionContext.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Validator; +use Symfony\Component\Translation\TranslatorInterface; + /** * Default implementation of {@link ExecutionContextInterface}. * @@ -26,6 +28,16 @@ class ExecutionContext implements ExecutionContextInterface */ private $globalContext; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var MetadataInterface */ @@ -49,19 +61,23 @@ class ExecutionContext implements ExecutionContextInterface /** * Creates a new execution context. * - * @param GlobalExecutionContextInterface $globalContext The global context storing node-independent state. - * @param MetadataInterface $metadata The metadata of the validated node. - * @param mixed $value The value of the validated node. - * @param string $group The current validation group. - * @param string $propertyPath The property path to the current node. + * @param GlobalExecutionContextInterface $globalContext The global context storing node-independent state. + * @param TranslatorInterface $translator The translator for translating violation messages. + * @param null|string $translationDomain The domain of the validation messages. + * @param MetadataInterface $metadata The metadata of the validated node. + * @param mixed $value The value of the validated node. + * @param string $group The current validation group. + * @param string $propertyPath The property path to the current node. */ - public function __construct(GlobalExecutionContextInterface $globalContext, MetadataInterface $metadata = null, $value = null, $group = null, $propertyPath = '') + public function __construct(GlobalExecutionContextInterface $globalContext, TranslatorInterface $translator, $translationDomain = null, MetadataInterface $metadata = null, $value = null, $group = null, $propertyPath = '') { if (null === $group) { $group = Constraint::DEFAULT_GROUP; } $this->globalContext = $globalContext; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->metadata = $metadata; $this->value = $value; $this->propertyPath = $propertyPath; @@ -74,6 +90,9 @@ class ExecutionContext implements ExecutionContextInterface public function addViolation($message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null) { $this->globalContext->getViolations()->add(new ConstraintViolation( + null === $pluralization + ? $this->translator->trans($message, $params, $this->translationDomain) + : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain), $message, $params, $this->globalContext->getRoot(), @@ -103,6 +122,9 @@ class ExecutionContext implements ExecutionContextInterface trigger_error('addViolationAtPath() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED); $this->globalContext->getViolations()->add(new ConstraintViolation( + null === $pluralization + ? $this->translator->trans($message, $params, $this->translationDomain) + : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain), $message, $params, $this->globalContext->getRoot(), @@ -146,6 +168,9 @@ class ExecutionContext implements ExecutionContextInterface public function addViolationAt($subPath, $message, array $params = array(), $invalidValue = null, $pluralization = null, $code = null) { $this->globalContext->getViolations()->add(new ConstraintViolation( + null === $pluralization + ? $this->translator->trans($message, $params, $this->translationDomain) + : $this->translator->transChoice($message, $pluralization, $params, $this->translationDomain), $message, $params, $this->globalContext->getRoot(), diff --git a/src/Symfony/Component/Validator/GraphWalker.php b/src/Symfony/Component/Validator/GraphWalker.php index 8af1a56153..ca212489a6 100644 --- a/src/Symfony/Component/Validator/GraphWalker.php +++ b/src/Symfony/Component/Validator/GraphWalker.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Mapping\MemberMetadata; @@ -39,6 +40,16 @@ class GraphWalker */ private $metadataFactory; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var array */ @@ -49,16 +60,20 @@ class GraphWalker * * @param ValidationVisitor $visitor * @param MetadataFactoryInterface $metadataFactory + * @param TranslatorInterface $translator + * @param null|string $translationDomain * @param array $validatedObjects * * @deprecated Deprecated since version 2.2, to be removed in 2.3. */ - public function __construct(ValidationVisitor $visitor, MetadataFactoryInterface $metadataFactory, array &$validatedObjects = array()) + public function __construct(ValidationVisitor $visitor, MetadataFactoryInterface $metadataFactory, TranslatorInterface $translator, $translationDomain = null, array &$validatedObjects = array()) { trigger_error('GraphWalker is deprecated since version 2.2 and will be removed in 2.3. This class has been replaced by ValidationVisitorInterface and MetadataInterface.', E_USER_DEPRECATED); $this->visitor = $visitor; $this->metadataFactory = $metadataFactory; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->validatedObjects = &$validatedObjects; } @@ -208,6 +223,8 @@ class GraphWalker $context = new ExecutionContext( $this->visitor, + $this->translator, + $this->translationDomain, $metadata, $value, $group, diff --git a/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php b/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php index f0d3e225a3..30d7ff0f64 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintViolationListTest.php @@ -129,6 +129,6 @@ EOF; protected function getViolation($message, $root = null, $propertyPath = null) { - return new ConstraintViolation($message, array(), $root, $propertyPath, null); + return new ConstraintViolation($message, $message, array(), $root, $propertyPath, null); } } diff --git a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php index f4b3652468..e1f06c2428 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintViolationTest.php @@ -18,6 +18,7 @@ class ConstraintViolationTest extends \PHPUnit_Framework_TestCase public function testToStringHandlesArrays() { $violation = new ConstraintViolation( + 'Array', '{{ value }}', array('{{ value }}' => array(1, 2, 3)), 'Root', diff --git a/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php b/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php index 40b5996646..467bdaaed7 100644 --- a/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php +++ b/src/Symfony/Component/Validator/Tests/ExecutionContextTest.php @@ -19,11 +19,14 @@ use Symfony\Component\Validator\ExecutionContext; class ExecutionContextTest extends \PHPUnit_Framework_TestCase { + const TRANS_DOMAIN = 'trans_domain'; + private $visitor; private $violations; private $metadata; private $metadataFactory; private $globalContext; + private $translator; /** * @var ExecutionContext @@ -51,7 +54,8 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase $this->globalContext->expects($this->any()) ->method('getMetadataFactory') ->will($this->returnValue($this->metadataFactory)); - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', 'foo.bar'); + $this->translator = $this->getMock('Symfony\Component\Translation\TranslatorInterface'); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', 'foo.bar'); } protected function tearDown() @@ -82,7 +86,7 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase { // BC $this->metadata = new ClassMetadata(__NAMESPACE__ . '\ExecutionContextTest_TestClass'); - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', 'foo.bar'); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', 'foo.bar'); $this->assertSame(__NAMESPACE__ . '\ExecutionContextTest_TestClass', $this->context->getCurrentClass()); $this->assertNull($this->context->getCurrentProperty()); @@ -92,7 +96,7 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase { // BC $this->metadata = new PropertyMetadata(__NAMESPACE__ . '\ExecutionContextTest_TestClass', 'myProperty'); - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', 'foo.bar'); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', 'foo.bar'); $this->assertSame(__NAMESPACE__ . '\ExecutionContextTest_TestClass', $this->context->getCurrentClass()); $this->assertSame('myProperty', $this->context->getCurrentProperty()); @@ -111,10 +115,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolation() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + $this->context->addViolation('Error', array('foo' => 'bar'), 'invalid'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -126,10 +136,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationUsesPreconfiguredValueIfNotPassed() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array()) + ->will($this->returnValue('Translated error')); + $this->context->addViolation('Error'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array(), 'Root', @@ -141,21 +157,32 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationUsesPassedNullValue() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo1' => 'bar1')) + ->will($this->returnValue('Translated error')); + $this->translator->expects($this->once()) + ->method('transChoice') + ->with('Choice error', 1, array('foo2' => 'bar2')) + ->will($this->returnValue('Translated choice error')); + // passed null value should override preconfigured value "invalid" - $this->context->addViolation('Error', array('foo' => 'bar'), null); - $this->context->addViolation('Error', array('foo' => 'bar'), null, 1); + $this->context->addViolation('Error', array('foo1' => 'bar1'), null); + $this->context->addViolation('Choice error', array('foo2' => 'bar2'), null, 1); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', - array('foo' => 'bar'), + array('foo1' => 'bar1'), 'Root', 'foo.bar', null ), new ConstraintViolation( - 'Error', - array('foo' => 'bar'), + 'Translated choice error', + 'Choice error', + array('foo2' => 'bar2'), 'Root', 'foo.bar', null, @@ -166,11 +193,17 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtPath() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + // override preconfigured property path $this->context->addViolationAtPath('bar.baz', 'Error', array('foo' => 'bar'), 'invalid'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -182,10 +215,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtPathUsesPreconfiguredValueIfNotPassed() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array()) + ->will($this->returnValue('Translated error')); + $this->context->addViolationAtPath('bar.baz', 'Error'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array(), 'Root', @@ -197,12 +236,22 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtPathUsesPassedNullValue() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + $this->translator->expects($this->once()) + ->method('transChoice') + ->with('Choice error', 3, array('foo' => 'bar')) + ->will($this->returnValue('Translated choice error')); + // passed null value should override preconfigured value "invalid" $this->context->addViolationAtPath('bar.baz', 'Error', array('foo' => 'bar'), null); - $this->context->addViolationAtPath('bar.baz', 'Error', array('foo' => 'bar'), null, 1); + $this->context->addViolationAtPath('bar.baz', 'Choice error', array('foo' => 'bar'), null, 3); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -210,23 +259,30 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase null ), new ConstraintViolation( - 'Error', + 'Translated choice error', + 'Choice error', array('foo' => 'bar'), 'Root', 'bar.baz', null, - 1 + 3 ), )), $this->context->getViolations()); } public function testAddViolationAt() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + // override preconfigured property path $this->context->addViolationAt('bam.baz', 'Error', array('foo' => 'bar'), 'invalid'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -238,10 +294,16 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtUsesPreconfiguredValueIfNotPassed() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array()) + ->will($this->returnValue('Translated error')); + $this->context->addViolationAt('bam.baz', 'Error'); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array(), 'Root', @@ -253,12 +315,22 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testAddViolationAtUsesPassedNullValue() { + $this->translator->expects($this->once()) + ->method('trans') + ->with('Error', array('foo' => 'bar')) + ->will($this->returnValue('Translated error')); + $this->translator->expects($this->once()) + ->method('transChoice') + ->with('Choice error', 2, array('foo' => 'bar')) + ->will($this->returnValue('Translated choice error')); + // passed null value should override preconfigured value "invalid" $this->context->addViolationAt('bam.baz', 'Error', array('foo' => 'bar'), null); - $this->context->addViolationAt('bam.baz', 'Error', array('foo' => 'bar'), null, 1); + $this->context->addViolationAt('bam.baz', 'Choice error', array('foo' => 'bar'), null, 2); $this->assertEquals(new ConstraintViolationList(array( new ConstraintViolation( + 'Translated error', 'Error', array('foo' => 'bar'), 'Root', @@ -266,12 +338,13 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase null ), new ConstraintViolation( - 'Error', + 'Translated choice error', + 'Choice error', array('foo' => 'bar'), 'Root', 'foo.bar.bam.baz', null, - 1 + 2 ), )), $this->context->getViolations()); } @@ -293,7 +366,7 @@ class ExecutionContextTest extends \PHPUnit_Framework_TestCase public function testGetPropertyPathWithEmptyCurrentPropertyPath() { - $this->context = new ExecutionContext($this->globalContext, $this->metadata, 'currentValue', 'Group', ''); + $this->context = new ExecutionContext($this->globalContext, $this->translator, self::TRANS_DOMAIN, $this->metadata, 'currentValue', 'Group', ''); $this->assertEquals('bam.baz', $this->context->getPropertyPath('bam.baz')); } diff --git a/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php b/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php index 83a67db3cd..1f8d6213c0 100644 --- a/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php +++ b/src/Symfony/Component/Validator/Tests/GraphWalkerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Tests; use Symfony\Component\Validator\Tests\Fixtures\ConstraintAValidator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ValidationVisitor; use Symfony\Component\Validator\Tests\Fixtures\Entity; use Symfony\Component\Validator\Tests\Fixtures\Reference; @@ -53,7 +54,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->metadataFactory = new FakeMetadataFactory(); - $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory()); + $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->walker = $this->visitor->getGraphWalker(); $this->metadata = new ClassMetadata(self::CLASSNAME); $this->metadataFactory->addMetadata($this->metadata); @@ -172,6 +173,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase // validated $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -204,6 +206,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase // "Default" was launched $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -231,6 +234,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase // Only group "Second" was validated $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -285,6 +289,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -317,6 +322,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -350,6 +356,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -449,6 +456,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -515,6 +523,7 @@ class GraphWalkerTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'message', 'message', array('param' => 'value'), 'Root', diff --git a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php b/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php index 86fdbd5e95..1bbb33e26f 100644 --- a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Tests; use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\Tests\Fixtures\Reference; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; @@ -49,7 +50,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->metadataFactory = new FakeMetadataFactory(); - $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory()); + $this->visitor = new ValidationVisitor('Root', $this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->metadata = new ClassMetadata(self::CLASS_NAME); $this->metadataFactory->addMetadata($this->metadata); } @@ -154,6 +155,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase // validated $violations = new ConstraintViolationList(array( new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -187,6 +189,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase // "Default" was launched $violations = new ConstraintViolationList(array( new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -215,6 +218,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase // Only group "Second" was validated $violations = new ConstraintViolationList(array( new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -243,6 +247,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -251,6 +256,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // generated by the reference new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -278,6 +284,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -286,6 +293,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // generated by the reference new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -313,6 +321,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -321,6 +330,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // generated by the reference new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -352,6 +362,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -414,6 +425,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -489,6 +501,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -497,6 +510,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // nothing generated by the reference! new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', diff --git a/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php b/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php index d963e4a848..d77d920704 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorBuilderTest.php @@ -96,8 +96,8 @@ class ValidatorBuilderTest extends \PHPUnit_Framework_TestCase public function testSetMetadataCache() { - $this->assertSame($this->builder, $this->builder->setMetadataCache($this->getMock( - 'Symfony\Component\Validator\Mapping\Cache\CacheInterface')) + $this->assertSame($this->builder, $this->builder->setMetadataCache( + $this->getMock('Symfony\Component\Validator\Mapping\Cache\CacheInterface')) ); } @@ -107,4 +107,16 @@ class ValidatorBuilderTest extends \PHPUnit_Framework_TestCase $this->getMock('Symfony\Component\Validator\ConstraintValidatorFactoryInterface')) ); } + + public function testSetTranslator() + { + $this->assertSame($this->builder, $this->builder->setTranslator( + $this->getMock('Symfony\Component\Translation\TranslatorInterface')) + ); + } + + public function testSetTranslationDomain() + { + $this->assertSame($this->builder, $this->builder->setTranslationDomain('TRANS_DOMAIN')); + } } diff --git a/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php b/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php index e10c2dad96..212a12cb47 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorContextTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Tests; use Symfony\Component\Validator\Validator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\Mapping\ClassMetadataFactoryAdapter; use Symfony\Component\Validator\ValidatorContext; @@ -57,6 +58,6 @@ class ValidatorContextTest extends \PHPUnit_Framework_TestCase ->setConstraintValidatorFactory($validatorFactory) ->getValidator(); - $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory), $validator); + $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory, new DefaultTranslator()), $validator); } } diff --git a/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php b/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php index 029678a8d4..8ab61cd581 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorFactoryTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Tests; use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\Validator\Mapping\ClassMetadataFactoryAdapter; use Symfony\Component\Validator\Validator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ValidatorContext; use Symfony\Component\Validator\ValidatorFactory; use Symfony\Component\Validator\ConstraintValidatorFactory; @@ -78,7 +79,7 @@ class ValidatorFactoryTest extends \PHPUnit_Framework_TestCase $validator = $this->factory->getValidator(); - $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory), $validator); + $this->assertEquals(new Validator(new ClassMetadataFactoryAdapter($metadataFactory), $validatorFactory, new DefaultTranslator()), $validator); } public function testBuildDefaultFromAnnotationsWithCustomNamespaces() diff --git a/src/Symfony/Component/Validator/Tests/ValidatorTest.php b/src/Symfony/Component/Validator/Tests/ValidatorTest.php index a2fccc684a..4d184aee3f 100644 --- a/src/Symfony/Component/Validator/Tests/ValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidatorTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity; use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; use Symfony\Component\Validator\Tests\Fixtures\FailingConstraint; use Symfony\Component\Validator\Validator; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; use Symfony\Component\Validator\ConstraintValidatorFactory; @@ -37,7 +38,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->metadataFactory = new FakeMetadataFactory(); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory()); + $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); } protected function tearDown() @@ -59,6 +60,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase // Only the constraint of group "Default" failed $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -82,6 +84,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase // Only the constraint of group "Custom" failed $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -107,6 +110,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase // The constraints of both groups failed $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -114,6 +118,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase '' )); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -141,6 +146,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -154,6 +160,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), $entity, @@ -198,6 +205,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase { $violations = new ConstraintViolationList(); $violations->add(new ConstraintViolation( + 'Failed', 'Failed', array(), '', @@ -232,7 +240,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase ->method('getMetadataFor') ->with('VALUE') ->will($this->returnValue($metadata)); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory()); + $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->validator->validateProperty('VALUE', 'someProperty'); } @@ -249,7 +257,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase ->method('getMetadataFor') ->with('VALUE') ->will($this->returnValue($metadata)); - $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory()); + $this->validator = new Validator($this->metadataFactory, new ConstraintValidatorFactory(), new DefaultTranslator()); $this->validator->validatePropertyValue('VALUE', 'someProperty', 'propertyValue'); } diff --git a/src/Symfony/Component/Validator/ValidationVisitor.php b/src/Symfony/Component/Validator/ValidationVisitor.php index 1ef231ed1c..ad21eff74a 100644 --- a/src/Symfony/Component/Validator/ValidationVisitor.php +++ b/src/Symfony/Component/Validator/ValidationVisitor.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Exception\NoSuchMetadataException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Translation\TranslatorInterface; /** * Default implementation of {@link ValidationVisitorInterface} and @@ -37,6 +38,16 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo */ private $validatorFactory; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var array */ @@ -65,11 +76,13 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo * @param mixed $root The value passed to the validator. * @param MetadataFactoryInterface $metadataFactory The factory for obtaining metadata instances. * @param ConstraintValidatorFactoryInterface $validatorFactory The factory for creating constraint validators. + * @param TranslatorInterface $translator The translator for translating violation messages. + * @param string|null $translationDomain The domain of the translation messages. * @param ObjectInitializerInterface[] $objectInitializers The initializers for preparing objects before validation. * * @throws UnexpectedTypeException If any of the object initializers is not an instance of ObjectInitializerInterface */ - public function __construct($root, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, array $objectInitializers = array()) + public function __construct($root, MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, TranslatorInterface $translator, $translationDomain = null, array $objectInitializers = array()) { foreach ($objectInitializers as $initializer) { if (!$initializer instanceof ObjectInitializerInterface) { @@ -80,6 +93,8 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo $this->root = $root; $this->metadataFactory = $metadataFactory; $this->validatorFactory = $validatorFactory; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->objectInitializers = $objectInitializers; $this->violations = new ConstraintViolationList(); } @@ -91,6 +106,8 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo { $context = new ExecutionContext( $this, + $this->translator, + $this->translationDomain, $metadata, $value, $group, @@ -161,7 +178,7 @@ class ValidationVisitor implements ValidationVisitorInterface, GlobalExecutionCo trigger_error('getGraphWalker() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED); if (null === $this->graphWalker) { - $this->graphWalker = new GraphWalker($this, $this->metadataFactory, $this->validatedObjects); + $this->graphWalker = new GraphWalker($this, $this->metadataFactory, $this->translator, $this->translationDomain, $this->validatedObjects); } return $this->graphWalker; diff --git a/src/Symfony/Component/Validator/Validator.php b/src/Symfony/Component/Validator/Validator.php index 848dc4e2ed..a700692d8d 100644 --- a/src/Symfony/Component/Validator/Validator.php +++ b/src/Symfony/Component/Validator/Validator.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\Exception\ValidatorException; +use Symfony\Component\Translation\TranslatorInterface; /** * Default implementation of {@link ValidatorInterface}. @@ -32,6 +33,16 @@ class Validator implements ValidatorInterface */ private $validatorFactory; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * @var array */ @@ -40,11 +51,15 @@ class Validator implements ValidatorInterface public function __construct( MetadataFactoryInterface $metadataFactory, ConstraintValidatorFactoryInterface $validatorFactory, + TranslatorInterface $translator, + $translationDomain = null, array $objectInitializers = array() ) { $this->metadataFactory = $metadataFactory; $this->validatorFactory = $validatorFactory; + $this->translator = $translator; + $this->translationDomain = $translationDomain; $this->objectInitializers = $objectInitializers; } @@ -137,7 +152,7 @@ class Validator implements ValidatorInterface */ public function validateValue($value, $constraints, $groups = null) { - $context = new ExecutionContext($this->createVisitor(null)); + $context = new ExecutionContext($this->createVisitor(null), $this->translator, $this->translationDomain); $constraints = is_array($constraints) ? $constraints : array($constraints); @@ -176,7 +191,14 @@ class Validator implements ValidatorInterface */ private function createVisitor($root) { - return new ValidationVisitor($root, $this->metadataFactory, $this->validatorFactory, $this->objectInitializers); + return new ValidationVisitor( + $root, + $this->metadataFactory, + $this->validatorFactory, + $this->translator, + $this->translationDomain, + $this->objectInitializers + ); } /** diff --git a/src/Symfony/Component/Validator/ValidatorBuilder.php b/src/Symfony/Component/Validator/ValidatorBuilder.php index 8f39d4ae4d..8937042d44 100644 --- a/src/Symfony/Component/Validator/ValidatorBuilder.php +++ b/src/Symfony/Component/Validator/ValidatorBuilder.php @@ -23,6 +23,7 @@ use Symfony\Component\Validator\Mapping\Loader\AnnotationLoader; use Symfony\Component\Validator\Mapping\Loader\YamlFilesLoader; use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader; use Symfony\Component\Validator\Mapping\Loader\XmlFilesLoader; +use Symfony\Component\Translation\TranslatorInterface; use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\CachedReader; @@ -75,6 +76,16 @@ class ValidatorBuilder implements ValidatorBuilderInterface */ private $metadataCache; + /** + * @var TranslatorInterface + */ + private $translator; + + /** + * @var null|string + */ + private $translationDomain; + /** * {@inheritdoc} */ @@ -254,6 +265,26 @@ class ValidatorBuilder implements ValidatorBuilderInterface return $this; } + /** + * {@inheritdoc} + */ + public function setTranslator(TranslatorInterface $translator) + { + $this->translator = $translator; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setTranslationDomain($translationDomain) + { + $this->translationDomain = $translationDomain; + + return $this; + } + /** * {@inheritdoc} */ @@ -296,7 +327,8 @@ class ValidatorBuilder implements ValidatorBuilderInterface } $validatorFactory = $this->validatorFactory ?: new ConstraintValidatorFactory(); + $translator = $this->translator ?: new DefaultTranslator(); - return new Validator($metadataFactory, $validatorFactory, $this->initializers); + return new Validator($metadataFactory, $validatorFactory, $translator, $this->translationDomain, $this->initializers); } } diff --git a/src/Symfony/Component/Validator/ValidatorBuilderInterface.php b/src/Symfony/Component/Validator/ValidatorBuilderInterface.php index 914d4f96d7..18b96eac36 100644 --- a/src/Symfony/Component/Validator/ValidatorBuilderInterface.php +++ b/src/Symfony/Component/Validator/ValidatorBuilderInterface.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator; use Symfony\Component\Validator\Mapping\Cache\CacheInterface; +use Symfony\Component\Translation\TranslatorInterface; use Doctrine\Common\Annotations\Reader; /** @@ -139,6 +140,28 @@ interface ValidatorBuilderInterface */ public function setConstraintValidatorFactory(ConstraintValidatorFactoryInterface $validatorFactory); + /** + * Sets the translator used for translating violation messages. + * + * @param TranslatorInterface $translator The translator instance. + * + * @return ValidatorBuilderInterface The builder object. + */ + public function setTranslator(TranslatorInterface $translator); + + /** + * Sets the default translation domain of violation messages. + * + * The same message can have different translations in different domains. + * Pass the domain that is used for violation messages by default to this + * method. + * + * @param string $translationDomain The translation domain of the violation messages. + * + * @return ValidatorBuilderInterface The builder object. + */ + public function setTranslationDomain($translationDomain); + /** * Builds and returns a new validator object. * diff --git a/src/Symfony/Component/Validator/ValidatorContext.php b/src/Symfony/Component/Validator/ValidatorContext.php index 9c8ec3d043..c5e9f34e0d 100644 --- a/src/Symfony/Component/Validator/ValidatorContext.php +++ b/src/Symfony/Component/Validator/ValidatorContext.php @@ -89,7 +89,8 @@ class ValidatorContext implements ValidatorContextInterface return new Validator( $this->metadataFactory, - $this->constraintValidatorFactory + $this->constraintValidatorFactory, + new DefaultTranslator() ); } diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index e3cb106914..9c65253c8e 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "symfony/translation": "2.2.*" }, "require-dev": { "symfony/http-foundation": "2.2.*", From e7eb5b0d7dd57f6a9cddf92b05c697d849376cbd Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 27 Nov 2012 23:17:30 +0100 Subject: [PATCH 034/128] [Form] Adapted Form component to translator integration in the validator --- .../ViolationMapper/ViolationMapper.php | 1 + src/Symfony/Component/Form/FormError.php | 18 +++++++++++++----- .../Form/Tests/AbstractDivLayoutTest.php | 6 +++--- .../Form/Tests/AbstractLayoutTest.php | 8 ++++---- .../Form/Tests/AbstractTableLayoutTest.php | 6 +++--- .../EventListener/ValidationListenerTest.php | 10 ++++------ .../ViolationMapper/ViolationMapperTest.php | 10 ++++++++-- 7 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php index 9ac6bb69b3..cece98804e 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php @@ -123,6 +123,7 @@ class ViolationMapper implements ViolationMapperInterface // Only add the error if the form is synchronized if ($this->acceptsErrors($scope)) { $scope->addError(new FormError( + $violation->getMessage(), $violation->getMessageTemplate(), $violation->getMessageParameters(), $violation->getMessagePluralization() diff --git a/src/Symfony/Component/Form/FormError.php b/src/Symfony/Component/Form/FormError.php index b336a40388..343165ca46 100644 --- a/src/Symfony/Component/Form/FormError.php +++ b/src/Symfony/Component/Form/FormError.php @@ -18,6 +18,11 @@ namespace Symfony\Component\Form; */ class FormError { + /** + * @var string + */ + private $message; + /** * The template for the error message * @var string @@ -41,16 +46,19 @@ class FormError * * Any array key in $messageParameters will be used as a placeholder in * $messageTemplate. - * @see \Symfony\Component\Translation\Translator * - * @param string $messageTemplate The template for the error message + * @param string $message The translated error message + * @param string|null $messageTemplate The template for the error message * @param array $messageParameters The parameters that should be * substituted in the message template. * @param integer|null $messagePluralization The value for error message pluralization + * + * @see \Symfony\Component\Translation\Translator */ - public function __construct($messageTemplate, array $messageParameters = array(), $messagePluralization = null) + public function __construct($message, $messageTemplate = null, array $messageParameters = array(), $messagePluralization = null) { - $this->messageTemplate = $messageTemplate; + $this->message = $message; + $this->messageTemplate = $messageTemplate ?: $message; $this->messageParameters = $messageParameters; $this->messagePluralization = $messagePluralization; } @@ -62,7 +70,7 @@ class FormError */ public function getMessage() { - return strtr($this->messageTemplate, $this->messageParameters); + return $this->message; } /** diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php index ac9b18b065..7fd743006e 100644 --- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php @@ -19,7 +19,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest public function testRow() { $form = $this->factory->createNamed('name', 'text'); - $form->addError(new FormError('Error!')); + $form->addError(new FormError('[trans]Error![/trans]')); $view = $form->createView(); $html = $this->renderRow($view); @@ -58,7 +58,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest public function testRepeatedRow() { $form = $this->factory->createNamed('name', 'repeated'); - $form->addError(new FormError('Error!')); + $form->addError(new FormError('[trans]Error![/trans]')); $view = $form->createView(); $html = $this->renderRow($view); @@ -398,7 +398,7 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest ) ->getForm(); - $form->get('child')->addError(new FormError('Error!')); + $form->get('child')->addError(new FormError('[trans]Error![/trans]')); $this->assertWidgetMatchesXpath($form->createView(), array(), '/div diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index a7ff80e9de..e2801c2d8e 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -283,8 +283,8 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase public function testErrors() { $form = $this->factory->createNamed('name', 'text'); - $form->addError(new FormError('Error 1')); - $form->addError(new FormError('Error 2')); + $form->addError(new FormError('[trans]Error 1[/trans]')); + $form->addError(new FormError('[trans]Error 2[/trans]')); $view = $form->createView(); $html = $this->renderErrors($view); @@ -1151,7 +1151,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase { $child = $this->factory->createNamed('date', 'date'); $form = $this->factory->createNamed('form', 'form')->add($child); - $child->addError(new FormError('Error!')); + $child->addError(new FormError('[trans]Error![/trans]')); $view = $form->createView(); $this->assertEmpty($this->renderErrors($view)); @@ -1676,7 +1676,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase { $child = $this->factory->createNamed('time', 'time'); $form = $this->factory->createNamed('form', 'form')->add($child); - $child->addError(new FormError('Error!')); + $child->addError(new FormError('[trans]Error![/trans]')); $view = $form->createView(); $this->assertEmpty($this->renderErrors($view)); diff --git a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php index efa957fb0b..e0f62c4ab1 100644 --- a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php @@ -18,7 +18,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest public function testRow() { $form = $this->factory->createNamed('name', 'text'); - $form->addError(new FormError('Error!')); + $form->addError(new FormError('[trans]Error![/trans]')); $view = $form->createView(); $html = $this->renderRow($view); @@ -91,7 +91,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest public function testRepeatedRowWithErrors() { $form = $this->factory->createNamed('name', 'repeated'); - $form->addError(new FormError('Error!')); + $form->addError(new FormError('[trans]Error![/trans]')); $view = $form->createView(); $html = $this->renderRow($view); @@ -250,7 +250,7 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest ) ->getForm(); - $form->get('child')->addError(new FormError('Error!')); + $form->get('child')->addError(new FormError('[trans]Error![/trans]')); $this->assertWidgetMatchesXpath($form->createView(), array(), '/table diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php index 7e358910e2..d9555e13e1 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php @@ -49,6 +49,8 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase private $message; + private $messageTemplate; + private $params; protected function setUp() @@ -63,17 +65,13 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase $this->violationMapper = $this->getMock('Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface'); $this->listener = new ValidationListener($this->validator, $this->violationMapper); $this->message = 'Message'; + $this->messageTemplate = 'Message template'; $this->params = array('foo' => 'bar'); } private function getConstraintViolation($code = null) { - return new ConstraintViolation($this->message, $this->params, null, 'prop.path', null, null, $code); - } - - private function getFormError() - { - return new FormError($this->message, $this->params); + return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code); } private function getBuilder($name = 'name', $propertyPath = null, $dataClass = null) diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php index e192f07108..2f41a99101 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php @@ -48,6 +48,11 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase */ private $message; + /** + * @var string + */ + private $messageTemplate; + /** * @var array */ @@ -62,6 +67,7 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $this->mapper = new ViolationMapper(); $this->message = 'Message'; + $this->messageTemplate = 'Message template'; $this->params = array('foo' => 'bar'); } @@ -101,7 +107,7 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase */ protected function getConstraintViolation($propertyPath) { - return new ConstraintViolation($this->message, $this->params, null, $propertyPath, null); + return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, $propertyPath, null); } /** @@ -109,7 +115,7 @@ class ViolationMapperTest extends \PHPUnit_Framework_TestCase */ protected function getFormError() { - return new FormError($this->message, $this->params); + return new FormError($this->message, $this->messageTemplate, $this->params); } public function testMapToVirtualFormIfDataDoesNotMatch() From 92a3b27a70cca04d6f834a518ce5f0cba2ea1bca Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 27 Nov 2012 23:17:49 +0100 Subject: [PATCH 035/128] [TwigBridge] Adapted TwigBridge to translator integration in the validator --- .../Twig/Resources/views/Form/form_div_layout.html.twig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index d7be0986a9..870cdd99dd 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -275,11 +275,7 @@ {% if errors|length > 0 %}
    {% for error in errors %} -
  • {{ - error.messagePluralization is null - ? error.messageTemplate|trans(error.messageParameters, 'validators') - : error.messageTemplate|transchoice(error.messagePluralization, error.messageParameters, 'validators') - }}
  • +
  • {{ error.message }}
  • {% endfor %}
{% endif %} From c96a0511f221669e809e4d7d22902b1828ab5c06 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 27 Nov 2012 23:18:12 +0100 Subject: [PATCH 036/128] [FrameworkBundle] Adapted FrameworkBundle to translator integration in the validator --- .../Compiler/AddValidatorInitializersPass.php | 2 +- .../DependencyInjection/Configuration.php | 1 + .../FrameworkExtension.php | 1 + .../Resources/config/validator.xml | 2 ++ .../Resources/views/Form/form_errors.html.php | 16 +------------- .../views/FormTable/form_errors.html.php | 21 ------------------- 6 files changed, 6 insertions(+), 37 deletions(-) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddValidatorInitializersPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddValidatorInitializersPass.php index 6f3be9b2a5..bf9f338111 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddValidatorInitializersPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddValidatorInitializersPass.php @@ -28,6 +28,6 @@ class AddValidatorInitializersPass implements CompilerPassInterface $initializers[] = new Reference($id); } - $container->getDefinition('validator')->replaceArgument(2, $initializers); + $container->getDefinition('validator')->replaceArgument(4, $initializers); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 60caf1d00c..70017d727b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -370,6 +370,7 @@ class Configuration implements ConfigurationInterface ->children() ->scalarNode('cache')->end() ->booleanNode('enable_annotations')->defaultFalse()->end() + ->scalarNode('translation_domain')->defaultValue('validators')->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 1ec5e9e2ae..baeb0abba8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -574,6 +574,7 @@ class FrameworkExtension extends Extension { $loader->load('validator.xml'); + $container->setParameter('validator.translation_domain', $config['translation_domain']); $container->setParameter('validator.mapping.loader.xml_files_loader.mapping_files', $this->getValidatorXmlMappingFiles($container)); $container->setParameter('validator.mapping.loader.yaml_files_loader.mapping_files', $this->getValidatorYamlMappingFiles($container)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml index 2dad8ca211..0bc70040a2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml @@ -23,6 +23,8 @@ + + %validator.translation_domain% diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_errors.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_errors.html.php index 339e3d0009..da9bec42ec 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_errors.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_errors.html.php @@ -1,21 +1,7 @@
    -
  • getMessagePluralization()) { - echo $view['translator']->trans( - $error->getMessageTemplate(), - $error->getMessageParameters(), - 'validators' - ); - } else { - echo $view['translator']->transChoice( - $error->getMessageTemplate(), - $error->getMessagePluralization(), - $error->getMessageParameters(), - 'validators' - ); - }?>
  • +
  • getMessage() ?>
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php deleted file mode 100644 index 339e3d0009..0000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/FormTable/form_errors.html.php +++ /dev/null @@ -1,21 +0,0 @@ - -
    - -
  • getMessagePluralization()) { - echo $view['translator']->trans( - $error->getMessageTemplate(), - $error->getMessageParameters(), - 'validators' - ); - } else { - echo $view['translator']->transChoice( - $error->getMessageTemplate(), - $error->getMessagePluralization(), - $error->getMessageParameters(), - 'validators' - ); - }?>
  • - -
- From b94a256cc75a116566f70cbfde8eb760f225fbeb Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 27 Nov 2012 23:23:26 +0100 Subject: [PATCH 037/128] [DoctrineBridge] Adapted DoctrineBridge to translator integration in the validator --- .../Tests/Validator/Constraints/UniqueValidatorTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php index efa077a63c..db80925111 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueValidatorTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Validator\Constraints; use Symfony\Bridge\Doctrine\Tests\DoctrineOrmTestCase; +use Symfony\Component\Validator\DefaultTranslator; use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIdentEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleIdentEntity; @@ -132,7 +133,7 @@ class UniqueValidatorTest extends DoctrineOrmTestCase $metadataFactory->addMetadata($metadata); $validatorFactory = $this->createValidatorFactory($uniqueValidator); - return new Validator($metadataFactory, $validatorFactory); + return new Validator($metadataFactory, $validatorFactory, new DefaultTranslator()); } private function createSchema($em) From 1e34e91909d6c8de9543011b4f0416d9449fb4d5 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 27 Nov 2012 23:24:28 +0100 Subject: [PATCH 038/128] [Form] Added upgrade instructions to the UPGRADE file --- UPGRADE-2.2.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md index a14fdda35b..f8ff48cdd0 100644 --- a/UPGRADE-2.2.md +++ b/UPGRADE-2.2.md @@ -64,6 +64,26 @@ Symfony\Component\Form\Exception namespace or to create custom exception classes for your purpose. + * Translating validation errors is now optional. You can still do so + manually if you like, or you can simplify your templates to simply output + the already translated message. + + Before: + + ``` + {{ + error.messagePluralization is null + ? error.messageTemplate|trans(error.messageParameters, 'validators') + : error.messageTemplate|transchoice(error.messagePluralization, error.messageParameters, 'validators') + }} + ``` + + After: + + ``` + {{ error.message }} + ``` + #### Deprecations * The methods `getParent()`, `setParent()` and `hasParent()` in From 56d61eb6da5ee9859129fee756ecc046c95d636a Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Wed, 28 Nov 2012 14:07:07 +0100 Subject: [PATCH 039/128] [Form][Validator] Added BC breaks in unstable code to the CHANGELOG --- src/Symfony/Component/Form/CHANGELOG.md | 1 + src/Symfony/Component/Validator/CHANGELOG.md | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index c229302a5e..d8e309637f 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -12,6 +12,7 @@ CHANGELOG * deprecated FormException and introduced ExceptionInterface instead * [BC BREAK] FormException is now an interface * protected FormBuilder methods from being called when it is turned into a FormConfigInterface with getFormConfig() + * [BC BREAK] inserted argument `$message` in the constructor of `FormError` 2.1.0 ----- diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index b037079365..79416e59e6 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -30,6 +30,12 @@ CHANGELOG are ignored for arrays now. Arrays are always traversed recursively. * added dependency to Translation component * violation messages are now translated with a TranslatorInterface implementation + * [BC BREAK] inserted argument `$message` in the constructor of `ConstraintViolation` + * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ExecutionContext` + * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `GraphWalker` + * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ValidationVisitor` + * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `Validator` + * [BC BREAK] added `setTranslator()` and `setTranslationDomain()` to `ValidatorBuilderInterface` 2.1.0 ----- From cc0df0a5aff1f5362373db951fd9d8b5fddc7de8 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Mon, 3 Dec 2012 16:49:07 +0100 Subject: [PATCH 040/128] [Validator] Changed validator to support pluralized messages by default This was implemented in order to satisfy Drupal's requirements for a singular and a plural message whenever a message is passed to their implementation of transChoice(). --- UPGRADE-2.2.md | 21 ++++++++++ src/Symfony/Component/Validator/CHANGELOG.md | 2 + .../Validator/Constraints/Choice.php | 4 +- .../Component/Validator/Constraints/Count.php | 6 +-- .../Validator/Constraints/Length.php | 6 +-- .../Validator/Constraints/MaxLength.php | 2 +- .../Validator/Constraints/MinLength.php | 2 +- .../Component/Validator/DefaultTranslator.php | 12 +++++- .../Resources/translations/validators.af.xlf | 16 +++---- .../Resources/translations/validators.bg.xlf | 18 ++++---- .../Resources/translations/validators.ca.xlf | 16 +++---- .../Resources/translations/validators.cs.xlf | 16 +++---- .../Resources/translations/validators.cy.xlf | 42 +++++++++---------- .../Resources/translations/validators.da.xlf | 10 ++--- .../Resources/translations/validators.de.xlf | 16 +++---- .../Resources/translations/validators.en.xlf | 16 +++---- .../Resources/translations/validators.es.xlf | 16 +++---- .../Resources/translations/validators.et.xlf | 8 ++-- .../Resources/translations/validators.eu.xlf | 16 +++---- .../Resources/translations/validators.fa.xlf | 16 +++---- .../Resources/translations/validators.fi.xlf | 16 +++---- .../Resources/translations/validators.fr.xlf | 16 +++---- .../Resources/translations/validators.gl.xlf | 16 +++---- .../Resources/translations/validators.he.xlf | 16 +++---- .../Resources/translations/validators.hr.xlf | 10 ++--- .../Resources/translations/validators.hu.xlf | 16 +++---- .../Resources/translations/validators.hy.xlf | 12 +++--- .../Resources/translations/validators.id.xlf | 16 +++---- .../Resources/translations/validators.it.xlf | 16 +++---- .../Resources/translations/validators.ja.xlf | 8 ++-- .../Resources/translations/validators.lb.xlf | 16 +++---- .../Resources/translations/validators.lt.xlf | 16 +++---- .../Resources/translations/validators.mn.xlf | 8 ++-- .../Resources/translations/validators.nb.xlf | 8 ++-- .../Resources/translations/validators.nl.xlf | 16 +++---- .../Resources/translations/validators.no.xlf | 18 ++++---- .../Resources/translations/validators.pl.xlf | 16 +++---- .../Resources/translations/validators.pt.xlf | 16 +++---- .../translations/validators.pt_BR.xlf | 16 +++---- .../Resources/translations/validators.ro.xlf | 16 +++---- .../Resources/translations/validators.ru.xlf | 16 +++---- .../Resources/translations/validators.sk.xlf | 16 +++---- .../Resources/translations/validators.sl.xlf | 16 +++---- .../Resources/translations/validators.sq.xlf | 16 +++---- .../translations/validators.sr_Cyrl.xlf | 16 +++---- .../translations/validators.sr_Latn.xlf | 16 +++---- .../Resources/translations/validators.sv.xlf | 18 ++++---- .../Resources/translations/validators.tr.xlf | 16 +++---- .../Resources/translations/validators.uk.xlf | 18 ++++---- .../translations/validators.zh_CN.xlf | 16 +++---- 50 files changed, 373 insertions(+), 340 deletions(-) diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md index f8ff48cdd0..c485bf6112 100644 --- a/UPGRADE-2.2.md +++ b/UPGRADE-2.2.md @@ -206,6 +206,27 @@ } ``` + * The sources of the pluralized messages in translation files have changed + from the singular to the pluralized version. If you created custom + translation files for validator errors, you should adapt them. + + Before: + + + You must select at least {{ limit }} choices. + Sie müssen mindestens {{ limit }} Möglichkeit wählen.|Sie müssen mindestens {{ limit }} Möglichkeiten wählen. + + + After: + + + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. + Sie müssen mindestens {{ limit }} Möglichkeit wählen.|Sie müssen mindestens {{ limit }} Möglichkeiten wählen. + + + Check the file src/Symfony/Component/Validator/Resources/translations/validators.en.xlf + for the new message sources. + #### Deprecations * The interface `ClassMetadataFactoryInterface` was deprecated and will be diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 79416e59e6..b0f47b233b 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -36,6 +36,8 @@ CHANGELOG * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `ValidationVisitor` * [BC BREAK] inserted arguments `$translator` and `$translationDomain` in the constructor of `Validator` * [BC BREAK] added `setTranslator()` and `setTranslationDomain()` to `ValidatorBuilderInterface` + * improved the Validator to support pluralized messages by default + * [BC BREAK] changed the source of all pluralized messages in the translation files to the pluralized version 2.1.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Choice.php b/src/Symfony/Component/Validator/Constraints/Choice.php index b73bd77ca3..70d6fd4da9 100644 --- a/src/Symfony/Component/Validator/Constraints/Choice.php +++ b/src/Symfony/Component/Validator/Constraints/Choice.php @@ -28,8 +28,8 @@ class Choice extends Constraint public $max = null; public $message = 'The value you selected is not a valid choice.'; public $multipleMessage = 'One or more of the given values is invalid.'; - public $minMessage = 'You must select at least {{ limit }} choices.'; - public $maxMessage = 'You must select at most {{ limit }} choices.'; + public $minMessage = 'You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.'; + public $maxMessage = 'You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.'; /** * {@inheritDoc} diff --git a/src/Symfony/Component/Validator/Constraints/Count.php b/src/Symfony/Component/Validator/Constraints/Count.php index db0661d0d1..afb0089282 100644 --- a/src/Symfony/Component/Validator/Constraints/Count.php +++ b/src/Symfony/Component/Validator/Constraints/Count.php @@ -21,9 +21,9 @@ use Symfony\Component\Validator\Exception\MissingOptionsException; */ class Count extends Constraint { - public $minMessage = 'This collection should contain {{ limit }} elements or more.'; - public $maxMessage = 'This collection should contain {{ limit }} elements or less.'; - public $exactMessage = 'This collection should contain exactly {{ limit }} elements.'; + public $minMessage = 'This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.'; + public $maxMessage = 'This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.'; + public $exactMessage = 'This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.'; public $min; public $max; diff --git a/src/Symfony/Component/Validator/Constraints/Length.php b/src/Symfony/Component/Validator/Constraints/Length.php index 70554c0686..cc355574ef 100644 --- a/src/Symfony/Component/Validator/Constraints/Length.php +++ b/src/Symfony/Component/Validator/Constraints/Length.php @@ -21,9 +21,9 @@ use Symfony\Component\Validator\Exception\MissingOptionsException; */ class Length extends Constraint { - public $maxMessage = 'This value is too long. It should have {{ limit }} characters or less.'; - public $minMessage = 'This value is too short. It should have {{ limit }} characters or more.'; - public $exactMessage = 'This value should have exactly {{ limit }} characters.'; + public $maxMessage = 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.'; + public $minMessage = 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.'; + public $exactMessage = 'This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.'; public $max; public $min; public $charset = 'UTF-8'; diff --git a/src/Symfony/Component/Validator/Constraints/MaxLength.php b/src/Symfony/Component/Validator/Constraints/MaxLength.php index 57b9bff7db..a737e38c46 100644 --- a/src/Symfony/Component/Validator/Constraints/MaxLength.php +++ b/src/Symfony/Component/Validator/Constraints/MaxLength.php @@ -22,7 +22,7 @@ use Symfony\Component\Validator\Constraint; */ class MaxLength extends Constraint { - public $message = 'This value is too long. It should have {{ limit }} characters or less.'; + public $message = 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.'; public $limit; public $charset = 'UTF-8'; diff --git a/src/Symfony/Component/Validator/Constraints/MinLength.php b/src/Symfony/Component/Validator/Constraints/MinLength.php index 78c5d2c99b..9827ac330e 100644 --- a/src/Symfony/Component/Validator/Constraints/MinLength.php +++ b/src/Symfony/Component/Validator/Constraints/MinLength.php @@ -22,7 +22,7 @@ use Symfony\Component\Validator\Constraint; */ class MinLength extends Constraint { - public $message = 'This value is too short. It should have {{ limit }} characters or more.'; + public $message = 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.'; public $limit; public $charset = 'UTF-8'; diff --git a/src/Symfony/Component/Validator/DefaultTranslator.php b/src/Symfony/Component/Validator/DefaultTranslator.php index 850e0f1e16..c46856752d 100644 --- a/src/Symfony/Component/Validator/DefaultTranslator.php +++ b/src/Symfony/Component/Validator/DefaultTranslator.php @@ -36,7 +36,17 @@ class DefaultTranslator implements TranslatorInterface */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { - return strtr($id, $parameters); + $ids = explode('|', $id); + + if (1 == $number) { + return strtr($ids[0], $parameters); + } + + if (!isset($ids[1])) { + throw new \InvalidArgumentException(sprintf('The message "%s" cannot be pluralized, because it is missing a plural (e.g. "There is one apple|There are %%count%% apples").', $id)); + } + + return strtr($ids[1], $parameters); } /** diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf index e6a29653b1..6100400159 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf @@ -23,11 +23,11 @@ Die waarde wat jy gekies het is nie 'n geldige keuse nie. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Jy moet ten minste {{ limit }} kies.|Jy moet ten minste {{ limit }} keuses kies. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Jy moet by die meeste {{ limit }} keuse kies.|Jy moet by die meeste {{ limit }} keuses kies. @@ -75,7 +75,7 @@ Hierdie waarde moet {{ limit }} of minder wees. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Hierdie waarde is te lank. Dit moet {{ limit }} karakter of minder wees.|Hierdie waarde is te lank. Dit moet {{ limit }} karakters of minder wees. @@ -83,7 +83,7 @@ Hierdie waarde moet {{ limit }} of meer wees. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Hierdie waarde is te kort. Dit moet {{ limit }} karakter of meer wees.|Hierdie waarde is te kort. Dit moet {{ limit }} karakters of meer wees. @@ -179,7 +179,7 @@ Hierdie waarde moet die huidige wagwoord van die gebruiker wees. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Hierdie waarde moet presies {{ limit }} karakter wees.|Hierdie waarde moet presies {{ limit }} karakters wees. @@ -203,15 +203,15 @@ 'n PHP-uitbreiding veroorsaak die oplaai van die lêer om te misluk. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Hierdie versameling moet {{ limit }} element of meer bevat.|Hierdie versameling moet {{ limit }} elemente of meer bevat. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Hierdie versameling moet {{ limit }} element of minder bevat.|Hierdie versameling moet {{ limit }} elemente of meer bevat. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Hierdie versameling moet presies {{ limit }} element bevat.|Hierdie versameling moet presies {{ limit }} elemente bevat. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf index 9d5754c3cd..f6a67e7257 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf @@ -23,11 +23,11 @@ Избраната стойност е невалидна. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Трябва да изберете поне {{ limit }} опция.|Трябва да изберете поне {{ limit }} опции. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Трябва да изберете най-много {{ limit }} опция.|Трябва да изберете най-много {{ limit }} опции. @@ -75,7 +75,7 @@ Стойността трябва да бъде {{ limit }} или по-малко. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Стойността е твърде дълга. Трябва да съдържа най-много {{ limit }} символ.|Стойността е твърде дълга. Трябва да съдържа най-много {{ limit }} символа. @@ -83,7 +83,7 @@ Стойността трябва да бъде {{ limit }} или повече. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Стойността е твърде кратка. Трябва да съдържа поне {{ limit }} символ.|Стойността е твърде кратка. Трябва да съдържа поне {{ limit }} символа. @@ -179,7 +179,7 @@ Стойността трябва да бъде текущата потребителска парола. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Стойността трябва да бъде точно {{ limit }} символ.|Стойността трябва да бъде точно {{ limit }} символа. @@ -203,17 +203,17 @@ PHP разширение предизвика прекъсване на качването. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Колекцията трябва да съдържа поне {{ limit }} елемент.|Колекцията трябва да съдържа поне {{ limit }} елемента. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Колекцията трябва да съдържа най-много {{ limit }} елемент.|Колекцията трябва да съдържа най-много {{ limit }} елемента. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Колекцията трябва да съдържа точно {{ limit }} елемент.|Колекцията трябва да съдържа точно {{ limit }} елемента. - \ No newline at end of file + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index 687598d825..49ac9b72bb 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -23,11 +23,11 @@ El valor seleccionat no és una opció vàlida. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Ha de seleccionar almenys {{ limit }} opció.|Ha de seleccionar almenys {{ limit }} opcions. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Ha de seleccionar com a màxim {{ limit }} opció.|Ha de seleccionar com a màxim {{ limit }} opcions. @@ -75,7 +75,7 @@ Aquest valor hauria de ser {{ limit }} o menys. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Aquest valor és massa llarg. Hauria de tenir {{ limit }} caràcter o menys.|Aquest valor és massa llarg. Hauria de tenir {{ limit }} caràcters o menys. @@ -83,7 +83,7 @@ Aquest valor hauria de ser {{ limit }} o més. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Aquest valor és massa curt. Hauria de tenir {{ limit }} caràcters o més. @@ -179,7 +179,7 @@ Aquest valor hauria de ser la contrasenya actual de l'usuari. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Aquest valor hauria de tenir exactament {{ limit }} caràcter.|Aquest valor hauria de tenir exactament {{ limit }} caràcters. @@ -203,15 +203,15 @@ Una extensió de PHP va fer que la pujada fallara. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Aquesta col·lecció ha de contenir {{ limit }} element o més.|Aquesta col·lecció ha de contenir {{ limit }} elements o més. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Aquesta col·lecció ha de contenir {{ limit }} element o menys.|Aquesta col·lecció ha de contenir {{ limit }} elements o menys. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Aquesta col·lecció ha de contenir exactament {{ limit }} element.|Aquesta col·lecció ha de contenir exactament {{ limit }} elements. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index 60d5835442..e386b8e07f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -23,11 +23,11 @@ Vybraná hodnota není platnou možností. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Musí být vybrána nejméně {{ limit }} možnost.|Musí být vybrány nejméně {{ limit }} možnosti.|Musí být vybráno nejméně {{ limit }} možností. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Musí být vybrána maximálně {{ limit }} možnost.|Musí být vybrány maximálně {{ limit }} možnosti.|Musí být vybráno maximálně {{ limit }} možností. @@ -75,7 +75,7 @@ Tato hodnota musí být {{ limit }} nebo méně. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Tato hodnota je příliš dlouhá. Musí obsahovat maximálně {{ limit }} znak.|Tato hodnota je příliš dlouhá. Musí obsahovat maximálně {{ limit }} znaky.|Tato hodnota je příliš dlouhá. Musí obsahovat maximálně {{ limit }} znaků. @@ -83,7 +83,7 @@ Tato hodnota musí být {{ limit }} nebo více. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Tato hodnota je příliš krátká. Musí obsahovat minimálně {{ limit }} znak.|Tato hodnota je příliš krátká. Musí obsahovat minimálně {{ limit }} znaky.|Tato hodnota je příliš krátká. Musí obsahovat minimálně {{ limit }} znaků. @@ -179,7 +179,7 @@ Tato hodnota musí být aktuální heslo uživatele. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Tato hodnota musí mít přesně {{ limit }} znak.|Tato hodnota musí mít přesně {{ limit }} znaky.|Tato hodnota musí mít přesně {{limit}} znaků. @@ -203,15 +203,15 @@ Rozšíření PHP zabránilo nahrání souboru. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Tato kolekce musí obsahovat minimálně {{ limit }} prvek.|Tato kolekce musí obsahovat minimálně {{ limit }} prvky.|Tato kolekce musí obsahovat minimálně {{ limit }} prvků. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Tato kolekce musí obsahovat maximálně {{ limit }} prvek.|Tato kolekce musí obsahovat maximálně {{ limit }} prvky.|Tato kolekce musí obsahovat maximálně {{ limit }} prvků. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Tato kolekce musí obsahovat přesně {{ limit }} prvek.|Tato kolekce musí obsahovat přesně {{ limit }} prvky.|Tato kolekce musí obsahovat přesně {{ limit }} prvků. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf index e5cdf46d02..e6e7a86266 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf @@ -20,14 +20,14 @@ The value you selected is not a valid choice. - Nid yw'r gwerth ddewiswyd yn ddilys. + Nid yw'r gwerth � ddewiswyd yn ddilys. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Rhaid dewis o leiaf {{ limit }} opsiwn. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Rhaid dewis dim mwy na {{ limit }} opsiwn. @@ -64,18 +64,18 @@ The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - Mae'r ffeil yn rhy fawr ({{ size }} {{ suffix }}). Yr uchafswm ganiateir yw {{ limit }} {{ suffix }}. + Mae'r ffeil yn rhy fawr ({{ size }} {{ suffix }}). Yr uchafswm � ganiateir yw {{ limit }} {{ suffix }}. The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Nid yw math mime y ffeil yn ddilys ({{ type }}). Dyma'r mathau ganiateir {{ types }}. + Nid yw math mime y ffeil yn ddilys ({{ type }}). Dyma'r mathau � ganiateir {{ types }}. This value should be {{ limit }} or less. Dylai'r gwerth hwn fod yn {{ limit }} neu lai. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Mae'r gwerth hwn rhy hir. Dylai gynnwys {{ limit }} nodyn cyfrifiadurol neu lai. @@ -83,7 +83,7 @@ Dylai'r gwerth hwn fod yn {{ limit }} neu fwy. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Mae'r gwerth hwn yn rhy fyr. Dylai gynnwys {{ limit }} nodyn cyfrifiadurol neu fwy. @@ -116,7 +116,7 @@ The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - Mae'r ffeil yn rhy fawr. Yr uchafswm ganiateir yw {{ limit }} {{ suffix }}. + Mae'r ffeil yn rhy fawr. Yr uchafswm � ganiateir yw {{ limit }} {{ suffix }}. The file is too large. @@ -124,7 +124,7 @@ The file could not be uploaded. - Methwyd uwchlwytho'r ffeil. + Methwyd � uwchlwytho'r ffeil. This value should be a valid number. @@ -156,35 +156,35 @@ The size of the image could not be detected. - Methwyd darganfod maint y ddelwedd. + Methwyd � darganfod maint y ddelwedd. The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - Mae lled y ddelwedd yn rhy fawr ({{ width }}px). Y lled mwyaf ganiateir yw {{ max_width }}px. + Mae lled y ddelwedd yn rhy fawr ({{ width }}px). Y lled mwyaf � ganiateir yw {{ max_width }}px. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - Mae lled y ddelwedd yn rhy fach ({{ width }}px). Y lled lleiaf ganiateir yw {{ min_width }}px. + Mae lled y ddelwedd yn rhy fach ({{ width }}px). Y lled lleiaf � ganiateir yw {{ min_width }}px. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - Mae uchder y ddelwedd yn rhy fawr ({{ width }}px). Yr uchder mwyaf ganiateir yw {{ max_height }}px. + Mae uchder y ddelwedd yn rhy fawr ({{ width }}px). Yr uchder mwyaf � ganiateir yw {{ max_height }}px. The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Mae uchder y ddelwedd yn rhy fach ({{ width }}px). Yr uchder lleiaf ganiateir yw {{ min_height }}px. + Mae uchder y ddelwedd yn rhy fach ({{ width }}px). Yr uchder lleiaf � ganiateir yw {{ min_height }}px. This value should be the user current password. Dylaid bod y gwerth hwn yn gyfrinair presenol y defnyddiwr. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Dylai'r gwerth hwn fod yn union {{ limit }} nodyn cyfrifiadurol o hyd. The file was only partially uploaded. - Dim ond rhan o'r ffeil uwchlwythwyd. + Dim ond rhan o'r ffeil � uwchlwythwyd. No file was uploaded. @@ -196,22 +196,22 @@ Cannot write temporary file to disk. - Methwyd ysgrifennu'r ffeil dros-dro ar ddisg. + Methwyd � ysgrifennu'r ffeil dros-dro ar ddisg. A PHP extension caused the upload to fail. - Methwyd uwchlwytho oherwydd ategyn PHP. + Methwyd � uwchlwytho oherwydd ategyn PHP. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Dylai'r casgliad hwn gynnwys {{ limit }} elfen neu fwy. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Dylai'r casgliad hwn gynnwys {{ limit }} elfen neu lai. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Dylai'r casgliad hwn gynnwys union {{ limit }} elfen. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf index 8d3e6531c2..70fee3b4ce 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf @@ -23,11 +23,11 @@ Værdien skal være en af de givne muligheder. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Du skal vælge mindst {{ limit }} muligheder. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Du kan højest vælge {{ limit }} muligheder. @@ -75,7 +75,7 @@ Værdien skal være {{ limit }} eller mindre. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Værdien er for lang. Den skal have {{ limit }} bogstaver eller mindre. @@ -83,7 +83,7 @@ Værdien skal være {{ limit }} eller mere. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Værdien er for kort. Den skal have {{ limit }} tegn eller flere. @@ -179,7 +179,7 @@ Værdien skal være brugerens nuværende password. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Værdien skal have præcis {{ limit }} tegn. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index ad4153adfa..2cc17204b2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -23,11 +23,11 @@ Sie haben einen ungültigen Wert ausgewählt. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Sie müssen mindestens {{ limit }} Möglichkeit wählen.|Sie müssen mindestens {{ limit }} Möglichkeiten wählen. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Sie dürfen höchstens {{ limit }} Möglichkeit wählen.|Sie dürfen höchstens {{ limit }} Möglichkeiten wählen. @@ -75,7 +75,7 @@ Dieser Wert sollte kleiner oder gleich {{ limit }} sein. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Diese Zeichenkette ist zu lang. Sie sollte höchstens {{ limit }} Zeichen haben.|Diese Zeichenkette ist zu lang. Sie sollte höchstens {{ limit }} Zeichen haben. @@ -83,7 +83,7 @@ Dieser Wert sollte größer oder gleich {{ limit }} sein. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Diese Zeichenkette ist zu kurz. Sie sollte mindestens {{ limit }} Zeichen haben.|Diese Zeichenkette ist zu kurz. Sie sollte mindestens {{ limit }} Zeichen haben. @@ -179,7 +179,7 @@ Dieser Wert sollte dem aktuellen Benutzerpasswort entsprechen. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Dieser Wert sollte genau {{ limit }} Zeichen lang sein.|Dieser Wert sollte genau {{ limit }} Zeichen lang sein. @@ -203,15 +203,15 @@ Eine PHP-Erweiterung verhinderte den Upload. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Diese Sammlung sollte {{ limit }} oder mehr Elemente beinhalten.|Diese Sammlung sollte {{ limit }} oder mehr Elemente beinhalten. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Diese Sammlung sollte {{ limit }} oder weniger Elemente beinhalten.|Diese Sammlung sollte {{ limit }} oder weniger Elemente beinhalten. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Diese Sammlung sollte genau {{ limit }} Element beinhalten.|Diese Sammlung sollte genau {{ limit }} Elemente beinhalten. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index 346614f066..5c910b451d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -23,11 +23,11 @@ The value you selected is not a valid choice. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. @@ -75,7 +75,7 @@ This value should be {{ limit }} or less. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. @@ -83,7 +83,7 @@ This value should be {{ limit }} or more. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. @@ -179,7 +179,7 @@ This value should be the user current password. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. @@ -203,15 +203,15 @@ A PHP extension caused the upload to fail. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index b1a31a4bdf..980767bd27 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -23,11 +23,11 @@ El valor seleccionado no es una opción válida. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Debe seleccionar al menos {{ limit }} opción.|Debe seleccionar al menos {{ limit }} opciones. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Debe seleccionar como máximo {{ limit }} opción.|Debe seleccionar como máximo {{ limit }} opciones. @@ -75,7 +75,7 @@ Este valor debería ser {{ limit }} o menos. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Este valor es demasiado largo. Debería tener {{ limit }} carácter o menos.|Este valor es demasiado largo. Debería tener {{ limit }} caracteres o menos. @@ -83,7 +83,7 @@ Este valor debería ser {{ limit }} o más. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Este valor es demasiado corto. Debería tener {{ limit }} carácter o más.|Este valor es demasiado corto. Debería tener {{ limit }} caracteres o más. @@ -179,7 +179,7 @@ Este valor debería ser la contraseña actual del usuario. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Este valor debería tener exactamente {{ limit }} carácter.|Este valor debería tener exactamente {{ limit }} caracteres. @@ -203,15 +203,15 @@ Una extensión de PHP hizo que la subida fallara. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Esta colección debe contener {{ limit }} elemento o más.|Esta colección debe contener {{ limit }} elementos o más. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Esta colección debe contener {{ limit }} elemento o menos.|Esta colección debe contener {{ limit }} elementos o menos. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Esta colección debe contener exactamente {{ limit }} elemento.|Esta colección debe contener exactamente {{ limit }} elementos. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf index 3f9c9a8f75..b77d59f308 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf @@ -23,11 +23,11 @@ Väärtus peaks olema üks etteantud valikutest. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Valima peaks vähemalt {{ limit }} valikut. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Valima peaks mitte rohkem kui {{ limit }} valikut. @@ -75,7 +75,7 @@ Väärtus peaks olema {{ limit }} või vähem. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Väärtus on liiga pikk. Pikkus peaks olema {{ limit }} tähemärki või vähem. @@ -83,7 +83,7 @@ Väärtus peaks olema {{ limit }} või rohkem. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Väärtus on liiga lühike. Pikkus peaks olema {{ limit }} tähemärki või rohkem. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf index b1864bd60f..f008091845 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf @@ -23,11 +23,11 @@ Hautatu duzun balioa ez da aukera egoki bat. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Gutxienez {{ limit }} aukera hautatu behar dituzu. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Gehienez {{ limit }} aukera hautatu behar dituzu. @@ -75,7 +75,7 @@ Balio honek {{ limit }} edo gutxiago izan beharko luke. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Balio hau luzeegia da. {{ limit }} karaktere edo gutxiago eduki beharko lituzke. @@ -83,7 +83,7 @@ Balio honek {{ limit }} edo handiago izan beharko luke. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Balio hau motzegia da. {{ limit }} karaktere edo gehiago eduki beharko lituzke. @@ -179,7 +179,7 @@ Balio honek uneko erabiltzailearen pasahitza izan beharko luke. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Balio honek zehazki {{ limit }} karaktere izan beharko lituzke. @@ -203,15 +203,15 @@ PHP luzapen batek igoeraren hutsa eragin du. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Bilduma honek {{ limit }} elementu edo gehiago eduki beharko lituzke. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Bilduma honek {{ limit }} elementu edo gutxiago eduki beharko lituzke. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Bilduma honek zehazki {{ limit }} elementu eduki beharko lituzke. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index 9ea4b83221..e44ac029bd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -23,11 +23,11 @@ گزینه انتخابی معتبر نیست. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. باید حداقل {{ limit }} گزینه انتخاب کنید. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. حداکثر {{ limit }} گزینه می توانید انتخاب کنید. @@ -75,7 +75,7 @@ این مقدار باید کوچکتر یا مساوی {{ limit }} باشد. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. بسیار طولانی است.حداکثر تعداد حروف مجاز برابر {{ limit }} است. @@ -83,7 +83,7 @@ این مقدار باید برابر و یا بیشتر از {{ limit }} باشد. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. بسیار کوتاه است.تعداد حروف باید حداقل {{ limit }} باشد. @@ -179,7 +179,7 @@ این مقدار می بایست کلمه عبور کنونی کاربر باشد. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. این مقدار می بایست دقیفا {{ limit }} کاراکتر داشته باشد.|این مقدرا می بایشت دقیقا {{ limit }} کاراکتر داشته باشد. @@ -203,15 +203,15 @@ اکستنشن PHP موجب شد که بارگذاری فایل با شکست مواجه شود. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. این مجموعه می بایست دارای {{ limit }} عنصر یا بیشتر باشد.|این مجموعه می بایست دارای {{ limit }} عنصر یا بیشتر باشد. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. این مجموعه می بایست دارای حداقل {{ limit }} عنصر یا کمتر باشد.|این مجموعه می بایست دارای {{ limit }} عنصر یا کمتر باشد. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. این مجموعه می بایست به طور دقیق دارا {{ limit }} عنصر باشد.|این مجموعه می بایست به طور دقیق دارای {{ limit }} قلم باشد. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf index 1dd7a00927..99f90b09f1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf @@ -23,11 +23,11 @@ Arvon tulee olla yksi annetuista vaihtoehdoista. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Sinun tulee valita vähintään {{ limit }} vaihtoehtoa. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Sinun tulee valitan enintään {{ limit }} vaihtoehtoa. @@ -75,7 +75,7 @@ Arvon tulee olla {{ limit }} tai vähemmän. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Liian pitkä syöte. Syöte saa olla enintään {{ limit }} merkkiä. @@ -83,7 +83,7 @@ Arvon tulee olla {{ limit }} tai enemmän. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Liian lyhyt syöte. Syötteen tulee olla vähintään {{ limit }} merkkiä. @@ -179,7 +179,7 @@ Tämän arvon tulisi olla käyttäjän tämänhetkinen salasana. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Tämän arvon tulisi olla tasan yhden merkin pituinen.|Tämän arvon tulisi olla tasan {{ limit }} merkkiä pitkä. @@ -203,15 +203,15 @@ PHP-laajennoksen vuoksi tiedoston lataus epäonnistui. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Tässä ryhmässä tulisi olla yksi tai useampi elementti.|Tässä ryhmässä tulisi olla vähintään {{ limit }} elementtiä. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Tässä ryhmässä tulisi olla enintään yksi elementti.|Tässä ryhmässä tulisi olla enintään {{ limit }} elementtiä. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Tässä ryhmässä tulisi olla tasan yksi elementti.|Tässä ryhmässä tulisi olla enintään {{ limit }} elementtiä. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index e6ca4a7f8a..0210fac557 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -23,11 +23,11 @@ Cette valeur doit être l'un des choix proposés. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Vous devez sélectionner au moins {{ limit }} choix.|Vous devez sélectionner au moins {{ limit }} choix. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Vous devez sélectionner au maximum {{ limit }} choix.|Vous devez sélectionner au maximum {{ limit }} choix. @@ -75,7 +75,7 @@ Cette valeur doit être inférieure ou égale à {{ limit }}. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Cette chaine est trop longue. Elle doit avoir au maximum {{ limit }} caractère.|Cette chaine est trop longue. Elle doit avoir au maximum {{ limit }} caractères. @@ -83,7 +83,7 @@ Cette valeur doit être supérieure ou égale à {{ limit }}. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Cette chaine est trop courte. Elle doit avoir au minimum {{ limit }} caractère.|Cette chaine est trop courte. Elle doit avoir au minimum {{ limit }} caractères. @@ -179,7 +179,7 @@ Cette valeur doit être le mot de passe actuel de l'utilisateur. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Cette chaine doit avoir exactement {{ limit }} caractère.|Cette chaine doit avoir exactement {{ limit }} caractères. @@ -203,15 +203,15 @@ Une extension PHP a empêché le transfert du fichier. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Cette collection doit contenir {{ limit }} élément ou plus.|Cette collection doit contenir {{ limit }} éléments ou plus. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Cette collection doit contenir {{ limit }} élément ou moins.|Cette collection doit contenir {{ limit }} éléments ou moins. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Cette collection doit contenir exactement {{ limit }} élément.|Cette collection doit contenir exactement {{ limit }} éléments. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf index 2994dba4ce..5f61f97337 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf @@ -23,11 +23,11 @@ O valor seleccionado non é unha opción válida. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Debe seleccionar polo menos {{ limit }} opción.|Debe seleccionar polo menos {{ limit }} opcions. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Debe seleccionar como máximo {{ limit }} opción.|Debe seleccionar como máximo {{ limit }} opcions. @@ -75,7 +75,7 @@ Este valor debería ser {{ limit }} ou menos. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Este valor é demasiado longo. Debería ter {{ limit }} carácter ou menos.|Este valor é demasiado longo. Debería ter {{ limit }} caracteres ou menos. @@ -83,7 +83,7 @@ Este valor debería ser {{ limit }} ou máis. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Este valor é demasiado curto. Debería ter {{ limit }} carácter ou máis.|Este valor é demasiado corto. Debería ter {{ limit }} caracteres ou máis. @@ -179,7 +179,7 @@ Este valor debería ser a contrasinal actual do usuario. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Este valor debería ter exactamente {{ limit }} carácter.|Este valor debería ter exactamente {{ limit }} caracteres. @@ -203,15 +203,15 @@ Unha extensión de PHP provocou que a subida fallara. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Esta colección debe conter {{ limit }} elemento ou máis.|Esta colección debe conter {{ limit }} elementos ou máis. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Esta colección debe conter {{ limit }} elemento ou menos.|Esta colección debe conter {{ limit }} elementos ou menos. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Esta colección debe conter exactamente {{ limit }} elemento.|Esta colección debe conter exactamente {{ limit }} elementos. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf index 9be564e60b..520e5bae72 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf @@ -23,11 +23,11 @@ הערך שבחרת אינו חוקי. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. אתה צריך לבחור לפחות {{ limit }} אפשרויות.|אתה צריך לבחור לפחות {{ limit }} אפשרויות. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. אתה צריך לבחור לכל היותר {{ limit }} אפשרויות.|אתה צריך לבחור לכל היותר {{ limit }} אפשרויות. @@ -75,7 +75,7 @@ הערך צריל להכיל {{ limit }} תווים לכל היותר. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. הערך ארוך מידי. הוא צריך להכיל {{ limit }} תווים לכל היותר.|הערך ארוך מידי. הוא צריך להכיל {{ limit }} תווים לכל היותר. @@ -83,7 +83,7 @@ הערך צריך להכיל {{ limit }} תווים לפחות. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. הערך קצר מידיץ הוא צריך להכיל {{ limit }} תווים לפחות.|הערך קצר מידיץ הוא צריך להכיל {{ limit }} תווים לפחות. @@ -179,7 +179,7 @@ הערך צריך להיות סיסמת המשתמש הנוכחי. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. הערך צריך להיות בדיוק {{ limit }} תווים.|הערך צריך להיות בדיוק {{ limit }} תווים. @@ -203,15 +203,15 @@ סיומת PHP גרם להעלאה להיכשל. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. האוסף אמור להכיל {{ limit }} אלמנטים או יותר.|האוסף אמור להכיל {{ limit }} אלמנטים או יותר. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. האוסף אמור להכיל {{ limit }} אלמנטים או פחות.|האוסף אמור להכיל {{ limit }} אלמנטים או פחות. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. האוסף צריך להכיל בדיוק {{ limit }} אלמנטים.|האוסף צריך להכיל בדיוק {{ limit }} אלמנטים. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index f6bb1c95d5..5873d5f842 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -23,11 +23,11 @@ Ova vrijednost treba biti jedna od ponuđenih. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Izaberite barem {{ limit }} mogućnosti. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Izaberite najviše {{ limit }} mogućnosti. @@ -75,7 +75,7 @@ Ova vrijednost treba biti {{ limit }} ili manje. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Ova vrijednost je predugačka. Treba imati {{ limit }} znakova ili manje. @@ -83,7 +83,7 @@ Ova vrijednost treba biti {{ limit }} ili više. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Ova vrijednost je prekratka. Treba imati {{ limit }} znakova ili više. @@ -179,7 +179,7 @@ Ova vrijednost treba biti trenutna korisnička lozinka. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Ova vrijednost treba imati točno {{ limit }} znakova. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf index 004d304c3b..ab10c5a738 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf @@ -23,11 +23,11 @@ Ez az érték a megadottak egyike legyen. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Legalább {{ limit }} értéket kell kiválasztani. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Legfeljebb {{ limit }} értéket lehet kiválasztani. @@ -75,7 +75,7 @@ Ez az érték {{ limit }} vagy kevesebb legyen. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Ez az érték túl hosszú. {{ limit }} karaktert vagy kevesebbet tartalmazzon. @@ -83,7 +83,7 @@ Ez az érték {{ limit }} vagy több legyen. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Ez az érték túl rövid. {{ limit }} karaktert vagy többet tartalmazzon. @@ -179,7 +179,7 @@ Ez az érték a felhasználó jelenlegi jelszava legyen. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Ez az érték pontosan {{ limit }} karaktert tartalmazzon. @@ -203,15 +203,15 @@ Egy PHP bővítmény miatt a feltöltés nem sikerült. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Ez a gyűjtemény {{ limit }} elemet vagy többet tartalmazzon. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Ez a gyűjtemény {{ limit }} elemet vagy kevesebbet tartalmazzon. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Ez a gyűjetemény pontosan {{ limit }} elemet tartalmazzon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf index 7b161c99f8..262b93b8bc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf @@ -23,11 +23,11 @@ Ձեր ընտրած արժեքը անթույլատրելի է. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Դուք պետք է ընտրեք ամենաքիչը {{ limit }} տարբերակներ. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Դուք պետք է ընտրեք ոչ ավելի քան {{ limit }} տարբերակներ. @@ -75,7 +75,7 @@ Արժեքը պետք է լինի {{ limit }} կամ փոքր. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Արժեքը չափազանց երկար է: Պետք է լինի {{ limit }} կամ ավել սիմվոլներ. @@ -83,7 +83,7 @@ Արժեքը պետ է լինի {{ limit }} կամ շատ. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Արժեքը չափազանց կարճ է: Պետք է լինի {{ limit }} կամ ավելի սիմվոլներ. @@ -179,9 +179,9 @@ Այս արժեքը պետք է լինի օգտագործողի ներկա ծածկագիրը. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Այս արժեքը պետք է ունենա ճիշտ {{ limit }} սիմվոլներ. - \ No newline at end of file + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 139c6b8e1b..816489f7a1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -23,11 +23,11 @@ Nilai yang dipilih tidak tepat. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Anda harus memilih paling tidak {{ limit }} pilihan. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Anda harus memilih paling banyak {{ limit }} pilihan. @@ -75,7 +75,7 @@ Nilai ini harus {{ limit }} atau kurang. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Nilai ini terlalu panjang. Seharusnya {{ limit }} karakter atau kurang. @@ -83,7 +83,7 @@ Nilai ini harus {{ limit }} atau lebih. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Nilai ini terlalu pendek. Seharusnya {{ limit }} karakter atau lebih. @@ -179,7 +179,7 @@ Nilai ini harus kata sandi pengguna saat ini. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Nilai ini harus memiliki tepat {{ limit }} karakter. @@ -203,15 +203,15 @@ Sebuah ekstensi PHP menyebabkan kegagalan unggah. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Kumpulan ini harus memiliki {{ limit }} elemen atau lebih. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Kumpulan ini harus memiliki kurang dari {{ limit }} elemen. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Kumpulan ini harus memiliki tepat {{ limit }} elemen. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index a463e247cc..9068ba43c1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -23,11 +23,11 @@ Questo valore dovrebbe essere una delle opzioni disponibili. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Si dovrebbe selezionare almeno {{ limit }} opzione.|Si dovrebbero selezionare almeno {{ limit }} opzioni. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Si dovrebbe selezionare al massimo {{ limit }} opzione.|Si dovrebbero selezionare al massimo {{ limit }} opzioni. @@ -75,7 +75,7 @@ Questo valore dovrebbe essere {{ limit }} o inferiore. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Questo valore è troppo lungo. Dovrebbe essere al massimo di {{ limit }} carattere.|Questo valore è troppo lungo. Dovrebbe essere al massimo di {{ limit }} caratteri. @@ -83,7 +83,7 @@ Questo valore dovrebbe essere {{ limit }} o superiore. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Questo valore è troppo corto. Dovrebbe essere almeno di {{ limit }} carattere.|Questo valore è troppo corto. Dovrebbe essere almeno di {{ limit }} caratteri. @@ -179,7 +179,7 @@ Questo valore dovrebbe essere la password attuale dell'utente. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Questo valore dovrebbe contenere esattamente {{ limit }} carattere.|Questo valore dovrebbe contenere esattamente {{ limit }} caratteri. @@ -203,15 +203,15 @@ Un'estensione PHP ha causato il fallimento del caricamento. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Questa collezione dovrebbe contenere almeno {{ limit }} elemento.|Questa collezione dovrebbe contenere almeno {{ limit }} elementi. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Questa collezione dovrebbe contenere massimo {{ limit }} elemento.|Questa collezione dovrebbe contenere massimo {{ limit }} elementi. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Questa collezione dovrebbe contenere esattamente {{ limit }} elemento.|Questa collezione dovrebbe contenere esattamente {{ limit }} elementi. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index c8b4632330..cc823ea301 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -23,11 +23,11 @@ 選択された値は選択肢として有効な値ではありません. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. {{ limit }}個以上選択してください. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. {{ limit }}個以内で選択してください. @@ -75,7 +75,7 @@ 値は{{ limit }}以下でなければなりません. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. 値が長すぎます。{{ limit }}文字以内でなければなりません. @@ -83,7 +83,7 @@ 値は{{ limit }}以上でなければなりません. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. 値が短すぎます。{{ limit }}文字以上でなければなりません. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf index ab3ea6bb78..c66f1fd67e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf @@ -23,11 +23,11 @@ Dëse Wäert sollt enger vun de Wielméiglechkeeten entspriechen. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Dir sollt mindestens {{ limit }} Méiglechkeete wielen. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Dir sollt héchstens {{ limit }} Méiglechkeete wielen. @@ -75,7 +75,7 @@ Dëse Wäert soll méi kleng oder gläich {{ limit }} sinn. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Dës Zeecheketten ass ze laang. Se sollt héchstens {{ limit }} Zeechen hunn. @@ -83,7 +83,7 @@ Dëse Wäert sollt méi grouss oder gläich {{ limit }} sinn. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Dës Zeecheketten ass ze kuerz. Se sollt mindestens {{ limit }} Zeechen hunn. @@ -179,7 +179,7 @@ Dëse Wäert sollt dem aktuelle Benotzerpasswuert entspriechen. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Dëse Wäert sollt exactly {{ limit }} Buschtaf hunn.|Dëse Wäert sollt exakt {{ limit }} Buschtawen hunn. @@ -203,15 +203,15 @@ Eng PHP-Erweiderung huet den Upload verhënnert. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Dës Sammlung sollt {{ limit }} oder méi Elementer hunn. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Dës Sammlung sollt {{ limit }} oder manner Elementer hunn. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Dës Sammlung sollt exakt {{ limit }} Element hunn.|Dës Sammlung sollt exakt {{ limit }} Elementer hunn. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index 140e6977ce..d47fa54b16 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -23,11 +23,11 @@ Neteisingas pasirinkimas. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Turite pasirinkti bent {{ limit }} variantą.|Turite pasirinkti bent {{ limit }} variantus.|Turite pasirinkti bent {{ limit }} variantų. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Turite pasirinkti ne daugiau kaip {{ limit }} variantą.|Turite pasirinkti ne daugiau kaip {{ limit }} variantus.|Turite pasirinkti ne daugiau kaip {{ limit }} variantų. @@ -75,7 +75,7 @@ Reikšmė turi būti {{ limit }} arba mažiau. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Per didelis simbolių skaičius. Turi susidaryti iš {{ limit }} arba mažiau simbolių.|Per didelis simbolių skaičius. Turi susidaryti iš {{ limit }} arba mažiau simbolių.|Per didelis simbolių skaičius. Turi susidaryti iš {{ limit }} arba mažiau simbolių. @@ -83,7 +83,7 @@ Reikšmė turi būti {{ limit }} arba daugiau. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Per mažas simbolių skaičius. Turi susidaryti iš {{ limit }} arba daugiau simbolių.|Per mažas simbolių skaičius. Turi susidaryti iš {{ limit }} arba daugiau simbolių.|Per mažas simbolių skaičius. Turi susidaryti iš {{ limit }} arba daugiau simbolių. @@ -179,7 +179,7 @@ Ši reikšmė turi sutapti su dabartiniu vartotojo slaptažodžiu. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Ši reikšmė turi turėti lygiai {{ limit }} simbolį.|Ši reikšmė turi turėti lygiai {{ limit }} simbolius.|Ši reikšmė turi turėti lygiai {{ limit }} simbolių. @@ -203,15 +203,15 @@ PHP plėtinys sutrukdė failo įkėlimą ir jis nepavyko. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Sąraše turi būti {{ limit }} arba daugiau įrašų.|Sąraše turi būti {{ limit }} arba daugiau įrašų.|Sąraše turi būti {{ limit }} arba daugiau įrašų. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Sąraše turi būti {{ limit }} arba mažiau įrašų.|Sąraše turi būti {{ limit }} arba mažiau įrašų.|Sąraše turi būti {{ limit }} arba mažiau įrašų. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Sąraše turi būti lygiai {{ limit }} įrašas.|Sąraše turi būti lygiai {{ limit }} įrašai.|Sąraše turi būti lygiai {{ limit }} įrašų. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf index ab4ab09179..e238061338 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf @@ -23,11 +23,11 @@ Сонгосон утга буруу байна. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Хамгийн багадаа {{ limit }} утга сонгогдсон байх ёстой. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Хамгийн ихдээ {{ limit }} утга сонгогдох боломжтой. @@ -75,7 +75,7 @@ Энэ утга {{ limit }} юмуу эсвэл бага байна. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Энэ утга хэтэрхий урт байна. {{ limit }} тэмдэгтийн урттай юмуу эсвэл бага байна. @@ -83,7 +83,7 @@ Энэ утга {{ limit }} юмуу эсвэл их байна. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Энэ утга хэтэрхий богино байна. {{ limit }} тэмдэгт эсвэл их байна. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf index 248c64259b..086b8b0b08 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf @@ -23,11 +23,11 @@ Verdien skal være en av de gitte valg. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Du skal velge minst {{ limit }} valg. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Du kan maks velge {{ limit }} valg. @@ -75,7 +75,7 @@ Verdien skal være {{ limit }} eller mindre. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Verdien er for lang. Den skal ha {{ limit }} bokstaver eller mindre. @@ -83,7 +83,7 @@ Verdien skal være {{ limit }} eller mer. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Verdien er for kort. Den skal ha {{ limit }} tegn eller flere. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 252030a9e4..e9630ae19f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -23,11 +23,11 @@ De geselecteerde waarde is geen geldige optie. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Selecteer ten minste {{ limit }} optie.|Selecteer ten minste {{ limit }} opties. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Selecteer maximaal {{ limit }} optie.|Selecteer maximaal {{ limit }} opties. @@ -75,7 +75,7 @@ Deze waarde moet {{ limit }} of minder zijn. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Deze waarde is te lang. Hij mag maximaal {{ limit }} teken bevatten.|Deze waarde is te lang. Hij mag maximaal {{ limit }} tekens bevatten. @@ -83,7 +83,7 @@ Deze waarde moet {{ limit }} of meer zijn. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Deze waarde is te kort. Hij moet tenminste {{ limit }} teken bevatten.|Deze waarde is te kort. Hij moet tenminste {{ limit }} tekens bevatten. @@ -179,7 +179,7 @@ Deze waarde moet het huidige wachtwoord van de gebruiker zijn. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Deze waarde moet exact {{ limit }} tekens lang zijn. @@ -203,15 +203,15 @@ De upload is mislukt vanwege een PHP-extensie. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Deze collectie moet {{ limit }} element of meer bevatten.|Deze collectie moet {{ limit }} elementen of meer bevatten. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Deze collectie moet {{ limit }} element of minder bevatten.|Deze collectie moet {{ limit }} elementen of minder bevatten. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Deze collectie moet exact {{ limit }} element bevatten.|Deze collectie moet exact {{ limit }} elementen bevatten. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index 94d8462b88..51d0cae142 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -23,11 +23,11 @@ Verdien du valgte er ikkje gyldig. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Du må velge minst {{ limit }} valg. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Du kan maksimalt gjere {{ limit }} valg. @@ -75,7 +75,7 @@ Verdien må vere {{ limit }} eller mindre. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Verdien er for lang. Den må vere {{ limit }} bokstavar eller mindre. @@ -83,7 +83,7 @@ Verdien må vere {{ limit }} eller meir. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Verdien er for kort. Den må ha {{ limit }} teikn eller fleire. @@ -179,7 +179,7 @@ Verdien må vere brukaren sitt noverande passord. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Verdien må vere nøyaktig {{ limit }} teikn. @@ -203,15 +203,15 @@ Ei PHP-udviding forårsaka feil under opplasting. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Denne samlinga må innehalde {{ limit }} element eller meir.|Denne samlinga må innehalde {{ limit }} element eller meir. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Denne samlinga må innehalde {{ limit }} element eller færre.|Denne samlinga må innehalde {{ limit }} element eller færre. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Denne samlinga må innehalde nøyaktig {{ limit }} element.|Denne samlinga må innehalde nøyaktig {{ limit }} element. @@ -224,4 +224,4 @@ - \ No newline at end of file + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index 0d0b91ab8c..18d03b6c6e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -23,11 +23,11 @@ Ta wartość powinna być jedną z podanych opcji. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Powinieneś wybrać co najmniej {{ limit }} opcję.|Powinieneś wybrać co najmniej {{ limit }} opcje.|Powinieneś wybrać co najmniej {{ limit }} opcji. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Powinieneś wybrać maksymalnie {{ limit }} opcję.|Powinieneś wybrać maksymalnie {{ limit }} opcje.|Powinieneś wybrać maksymalnie {{ limit }} opcji. @@ -75,7 +75,7 @@ Ta wartość powinna wynosić {{ limit }} lub mniej. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Ta wartość jest zbyt długa. Powinna mieć {{ limit }} lub mniej znaków.|Ta wartość jest zbyt długa. Powinna mieć {{ limit }} lub mniej znaków.|Ta wartość jest zbyt długa. Powinna mieć {{ limit }} lub mniej znaków. @@ -83,7 +83,7 @@ Ta wartość powinna wynosić {{ limit }} lub więcej. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Ta wartość jest zbyt krótka. Powinna mieć {{ limit }} lub więcej znaków.|Ta wartość jest zbyt krótka. Powinna mieć {{ limit }} lub więcej znaków.|Ta wartość jest zbyt krótka. Powinna mieć {{ limit }} lub więcej znaków. @@ -179,7 +179,7 @@ Ta wartość powinna być aktualnym hasłem użytkownika. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Ta wartość powinna mieć dokładnie {{ limit }} znak.|Ta wartość powinna mieć dokładnie {{ limit }} znaki.|Ta wartość powinna mieć dokładnie {{ limit }} znaków. @@ -203,15 +203,15 @@ Rozszerzenie PHP spowodowało błąd podczas wgrywania. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Ten zbiór powinien zawierać {{ limit }} lub więcej elementów. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Ten zbiór powinien zawierać {{ limit }} lub mniej elementów. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Ten zbiór powinien zawierać dokładnie {{ limit }} element.|Ten zbiór powinien zawierać dokładnie {{ limit }} elementy.|Ten zbiór powinien zawierać dokładnie {{ limit }} elementów. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index ce9bb90464..454e17612c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -23,11 +23,11 @@ O valor selecionado não é uma opção válida. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Você deveria selecionar {{ limit }} opção no mínimo.|Você deveria selecionar {{ limit }} opções no mínimo. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Você deve selecionar, no máximo {{ limit }} opção.|Você deve selecionar, no máximo {{ limit }} opções. @@ -75,7 +75,7 @@ Este valor deveria ser {{ limit }} ou menor. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. O valor é muito longo. Deveria ter {{ limit }} caracteres ou menos. @@ -83,7 +83,7 @@ Este valor deveria ser {{ limit }} ou mais. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. O valor é muito curto. Deveria de ter {{ limit }} caractere ou mais.|O valor é muito curto. Deveria de ter {{ limit }} caracteres ou mais. @@ -179,7 +179,7 @@ Este valor deveria de ser a password atual do utilizador. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Este valor tem de ter exatamente {{ limit }} carateres. @@ -203,15 +203,15 @@ Uma extensão PHP causou a falha no envio. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Esta coleção deve conter {{ limit }} elemento ou mais.|Esta coleção deve conter {{ limit }} elementos ou mais. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Esta coleção deve conter {{ limit }} elemento ou menos.|Esta coleção deve conter {{ limit }} elementos ou menos. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Esta coleção deve conter exatamente {{ limit }} elemento.|Esta coleção deve conter exatamente {{ limit }} elementos. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index 40df6f4466..fb4524248b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -23,11 +23,11 @@ O valor selecionado não é uma opção válida. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Você deve selecionar, no mínimo, {{ limit }} opção.|Você deve selecionar, no mínimo, {{ limit }} opções - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Você deve selecionar, no máximo, {{ limit }} opção.|Você deve selecionar, no máximo, {{ limit }} opções. @@ -75,7 +75,7 @@ Este valor deve ser {{ limit }} ou menos. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Este valor é muito longo. Deve ter {{ limit }} caractere ou menos.|Este valor é muito longo. Deve ter {{ limit }} caracteres ou menos. @@ -83,7 +83,7 @@ Este valor deve ser {{ limit }} ou mais. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Este valor é muito curto. Deve ter {{ limit }} caractere ou mais.|Este valor é muito curto. Deve ter {{ limit }} caracteres ou mais. @@ -179,7 +179,7 @@ Este valor deve ser a senha atual do usuário. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Este valor deve ter exatamente {{ limit }} caractere.|Este valor deve ter exatamente {{ limit }} caracteres. @@ -203,15 +203,15 @@ Uma extensão PHP fez com que o envio falhasse. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Esta coleção deve conter {{ limit }} elemento ou mais.|Esta coleção deve conter {{ limit }} elementos ou mais. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Esta coleção deve conter {{ limit }} elemento ou menos.|Esta coleção deve conter {{ limit }} elementos ou menos. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Esta coleção deve conter exatamente {{ limit }} elemento.|Esta coleção deve conter exatamente {{ limit }} elementos. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index e1c4c44a2c..fa45d3ed75 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -23,11 +23,11 @@ Valoarea selectată nu este o opțiune validă. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Trebuie să selectați cel puțin {{ limit }} opțiuni. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Trebuie să selectați cel mult {{ limit }} opțiuni. @@ -75,7 +75,7 @@ Această valoare ar trebui să fie cel mult {{ limit }}. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Această valoare este prea lungă. Ar trebui să aibă maxim {{ limit }} caracter.|Această valoare este prea lungă. Ar trebui să aibă maxim {{ limit }} caractere. @@ -83,7 +83,7 @@ Această valoare ar trebui să fie cel puțin {{ limit }}. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Această valoare este prea scurtă. Ar trebui să aibă minim {{ limit }} caracter.|Această valoare este prea scurtă. Ar trebui să aibă minim {{ limit }} caractere. @@ -179,7 +179,7 @@ Această valoare trebuie să fie parola curentă a utilizatorului. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Această valoare trebuie să conțină exact {{ limit }} caracter.|Această valoare trebuie să conțină exact {{ limit }} caractere. @@ -203,15 +203,15 @@ O extensie PHP a prevenit încărcarea cu succes a fișierului. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Această colecție trebuie să conțină cel puțin {{ limit }} elemente. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Această colecție trebuie să conțină cel mult {{ limit }} elemente. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Această colecție trebuie să conțină {{ limit }} elemente. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index c5977dd5a3..4fd4b96b2b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -23,11 +23,11 @@ Выбранное Вами значение недопустимо. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Вы должны выбрать хотя бы {{ limit }} вариант.|Вы должны выбрать хотя бы {{ limit }} варианта.|Вы должны выбрать хотя бы {{ limit }} вариантов. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Вы должны выбрать не более чем {{ limit }} вариант.|Вы должны выбрать не более чем {{ limit }} варианта.|Вы должны выбрать не более чем {{ limit }} вариантов. @@ -75,7 +75,7 @@ Значение должно быть {{ limit }} или меньше. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Значение слишком длинное. Должно быть равно {{ limit }} символу или меньше.|Значение слишком длинное. Должно быть равно {{ limit }} символам или меньше.|Значение слишком длинное. Должно быть равно {{ limit }} символам или меньше. @@ -83,7 +83,7 @@ Значение должно быть {{ limit }} или больше. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Значение слишком короткое. Должно быть равно {{ limit }} символу или больше.|Значение слишком короткое. Должно быть равно {{ limit }} символам или больше.|Значение слишком короткое. Должно быть равно {{ limit }} символам или больше. @@ -179,7 +179,7 @@ Значение должно быть текущим паролем пользователя. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Значение должно быть равно {{ limit }} символу.|Значение должно быть равно {{ limit }} символам.|Значение должно быть равно {{ limit }} символам. @@ -203,15 +203,15 @@ Расширение PHP вызвало ошибку при загрузке. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Эта коллекция должна содержать {{ limit }} элемент или больше.|Эта коллекция должна содержать {{ limit }} элемента или больше.|Эта коллекция должна содержать {{ limit }} элементов или больше. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Эта коллекция должна содержать {{ limit }} элемент или меньше.|Эта коллекция должна содержать {{ limit }} элемента или меньше.|Эта коллекция должна содержать {{ limit }} элементов или меньше. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Эта коллекция должна содержать ровно {{ limit }} элемент.|Эта коллекция должна содержать ровно {{ limit }} элемента.|Эта коллекция должна содержать ровно {{ limit }} элементов. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf index e57a7eca49..e2055d7503 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf @@ -23,11 +23,11 @@ Táto hodnota by mala byť jednou z poskytnutých možností. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Mali by ste vybrať minimálne {{ limit }} možnosti. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Mali by ste vybrať najviac {{ limit }} možnosti. @@ -75,7 +75,7 @@ Táto hodnota by mala byť {{ limit }} alebo menej. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Táto hodnota obsahuje viac znakov ako je povolené. Mala by obsahovať najviac {{ limit }} znakov. @@ -83,7 +83,7 @@ Táto hodnota by mala byť viac ako {{ limit }}. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Táto hodnota nemá dostatočný počet znakov. Minimálny počet znakov je {{ limit }}. @@ -179,7 +179,7 @@ Táto hodnota by mala byť aktuálne heslo používateľa. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Táto hodnota by mala mať presne {{ limit }} znakov. @@ -203,15 +203,15 @@ Rozšírenie PHP zabránilo nahraniu súboru. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Táto kolekcia by mala obsahovať aspoň {{ limit }} prvok alebo viac.|Táto kolekcia by mala obsahovať aspoň {{ limit }} prvky alebo viac.|Táto kolekcia by mala obsahovať aspoň {{ limit }} prvkov alebo viac. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Táto kolekcia by mala maximálne {{ limit }} prvok.|Táto kolekcia by mala obsahovať maximálne {{ limit }} prvky.|Táto kolekcia by mala obsahovať maximálne {{ limit }} prvkov. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Táto kolekcia by mala obsahovať presne {{ limit }} prvok.|Táto kolekcia by mala obsahovať presne {{ limit }} prvky.|Táto kolekcia by mala obsahovať presne {{ limit }} prvkov. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index 1cc8921c4e..b68be59d18 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -23,11 +23,11 @@ Vrednost naj bo ena izmed podanih možnosti. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Izberite vsaj {{ limit }} možnosti. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Izberete lahko največ {{ limit }} možnosti. @@ -75,7 +75,7 @@ Vrednost mora biti manjša od {{ limit }}. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Vpisana vrednost je predolga. Največja dolžina je {{ limit }} znakov. @@ -83,7 +83,7 @@ Vpisana vrednost naj vsebuje vsaj {{ limit }} znakov. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Vpisana vrednost je prekratka. Vpišite vsaj {{ limit }} znakov. @@ -179,7 +179,7 @@ Vrednost bi morala biti trenutno uporabnikovo geslo. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Vrednost bi morala imeti točno {{ limit }} znakov. @@ -203,15 +203,15 @@ Nalaganje ni uspelo (razlog: PHP extension). - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Ta zbirka bi morala vsebovati {{ limit }} ali več elementov. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Ta zbirka bi morala vsebovati {{ limit }} ali manj elementov. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Ta zbirka bi morala vsebovati točno {{ limit }} element.|Ta zbirka bi morala vsebovati točno {{ limit }} elementa.|Ta zbirka bi morala vsebovati točno {{ limit }} elemente.|Ta zbirka bi morala vsebovati točno {{ limit }} elementov. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf index 690ad20863..e6190fca11 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf @@ -23,11 +23,11 @@ Vlera që keni zgjedhur nuk është alternativë e vlefshme. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Duhet të zgjedhni së paku {{ limit }} alternativa.|Duhet të zgjedhni së paku {{ limit }} alternativa. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Duhet të zgjedhni më së shumti {{ limit }} alternativa.|Duhet të zgjedhni më së shumti {{ limit }} alternativa. @@ -75,7 +75,7 @@ Kjo vlerë duhet të jetë {{ limit }} ose më pak. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Kjo vlerë është shumë e gjatë. Duhet t'i ketë {{ limit }} ose më pak karaktere.|Kjo vlerë është shumë e gjatë. Duhet t'i ketë {{ limit }} ose më pak karaktere. @@ -83,7 +83,7 @@ Kjo vlerë duhet të jetë {{ limit }} ose më shumë. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Kjo vlerë është shumë e shkurtër. Duhet t'i ketë {{ limit }} ose më shumë karaktere.|Kjo vlerë është shumë e shkurtër. Duhet t'i ketë {{ limit }} ose më shumë karaktere. @@ -179,7 +179,7 @@ Kjo vlerë duhet të jetë fjalëkalimi aktual i përdoruesit. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Kjo vlerë duhet të ketë saktësisht {{ limit }} karaktere.|Kjo vlerë duhet të ketë saktësisht {{ limit }} karaktere. @@ -203,15 +203,15 @@ Një ekstenzion i PHP-së bëri të dështojë ngarkimi i files. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente.|Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente.|Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Ky kolekcion duhet të përmbajë saktësisht {{ limit }} elemente.|Ky kolekcion duhet të përmbajë saktësisht {{ limit }} elemente. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf index 3e558f9dfa..d85a3d9b26 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf @@ -23,11 +23,11 @@ Вредност треба да буде једна од понуђених. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Изаберите бар {{ limit }} могућност.|Изаберите бар {{ limit }} могућности.|Изаберите бар {{ limit }} могућности. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Изаберите највише {{ limit }} могућност.|Изаберите највише {{ limit }} могућности.|Изаберите највише {{ limit }} могућности. @@ -75,7 +75,7 @@ Вредност треба да буде {{ limit }} или мање. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Вредност је предугачка. Треба да има {{ limit }} карактер или мање.|Вредност је предугачка. Треба да има {{ limit }} карактера или мање.|Вредност је предугачка. Треба да има {{ limit }} карактера или мање. @@ -83,7 +83,7 @@ Вредност треба да буде {{ limit }} или више. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Вредност је прекратка. Треба да има {{ limit }} карактер или више.|Вредност је прекратка. Треба да има {{ limit }} карактера или више.|Вредност је прекратка. Треба да има {{ limit }} карактера или више. @@ -179,7 +179,7 @@ Вредност треба да буде тренутна корисничка лозинка. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Вредност треба да има тачно {{ limit }} карактер.|Вредност треба да има тачно {{ limit }} карактера.|Вредност треба да има тачно {{ limit }} карактера. @@ -203,15 +203,15 @@ PHP екстензија је проузроковала неуспех отпремања датотеке. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Ова колекција треба да садржи {{ limit }} или више елемената.|Ова колекција треба да садржи {{ limit }} или више елемената.|Ова колекција треба да садржи {{ limit }} или више елемената. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Ова колекција треба да садржи {{ limit }} или мање елемената.|Ова колекција треба да садржи {{ limit }} или мање елемената.|Ова колекција треба да садржи {{ limit }} или мање елемената. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Ова колекција треба да садржи тачно {{ limit }} елемент.|Ова колекција треба да садржи тачно {{ limit }} елемента.|Ова колекција треба да садржи тачно {{ limit }} елемената. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index 81d134861b..28d23dbbb5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -23,11 +23,11 @@ Vrednost treba da bude jedna od ponuđenih. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Izaberite bar {{ limit }} mogućnost.|Izaberite bar {{ limit }} mogućnosti.|Izaberite bar {{ limit }} mogućnosti. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Izaberite najviše {{ limit }} mogućnost.|Izaberite najviše {{ limit }} mogućnosti.|Izaberite najviše {{ limit }} mogućnosti. @@ -75,7 +75,7 @@ Vrednost treba da bude {{ limit }} ili manje. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Vrednost je predugačka. Treba da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Treba da ima {{ limit }} karaktera ili manje.|Vrednost je predugačka. Treba da ima {{ limit }} karaktera ili manje. @@ -83,7 +83,7 @@ Vrednost treba da bude {{ limit }} ili više. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Vrednost je prekratka. Treba da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Treba da ima {{ limit }} karaktera ili više.|Vrednost je prekratka. Treba da ima {{ limit }} karaktera ili više. @@ -179,7 +179,7 @@ Vrednost treba da bude trenutna korisnička lozinka. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Vrednost treba da ima tačno {{ limit }} karakter.|Vrednost treba da ima tačno {{ limit }} karaktera.|Vrednost treba da ima tačno {{ limit }} karaktera. @@ -203,15 +203,15 @@ PHP ekstenzija je prouzrokovala neuspeh otpremanja datoteke. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Ova kolekcija treba da sadrži {{ limit }} ili više elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili više elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili više elemenata. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Ova kolekcija treba da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili manje elemenata. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Ova kolekcija treba da sadrži tačno {{ limit }} element.|Ova kolekcija treba da sadrži tačno {{ limit }} elementa.|Ova kolekcija treba da sadrži tačno {{ limit }} elemenata. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index 8383e508cf..f66926fea6 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -23,11 +23,11 @@ Värdet ska vara ett av de givna valen. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Du måste välja minst {{ limit }} val.|Du måste välja minst {{ limit }} val. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Du kan som mest välja {{ limit }} val.|Du kan som mest välja {{ limit }} val. @@ -75,7 +75,7 @@ Värdet ska vara {{ limit }} eller mindre. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Värdet är för långt. Det ska ha {{ limit }} tecken eller färre.|Värdet är för långt. Det ska ha {{ limit }} tecken eller färre. @@ -83,7 +83,7 @@ Värdet ska vara {{ limit }} eller mer. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Värdet är för kort. Det ska ha {{ limit }} tecken eller mer.|Värdet är för kort. Det ska ha {{ limit }} tecken eller mer. @@ -179,7 +179,7 @@ Värdet ska vara användarens nuvarande lösenord. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Värdet ska ha exakt {{ limit }} tecken.|Värdet ska ha exakt {{ limit }} tecken. @@ -203,17 +203,17 @@ En PHP extension gjorde att uppladdningen misslyckades. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Den här samlingen ska innehålla {{ limit }} element eller mer.|Den här samlingen ska innehålla {{ limit }} element eller mer. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Den här samlingen ska innehålla {{ limit }} element eller mindre.|Den här samlingen ska innehålla {{ limit }} element eller mindre. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Den här samlingen ska innehålla exakt {{ limit }} element.|Den här samlingen ska innehålla exakt {{ limit }} element. - \ No newline at end of file + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 4b05ba2c80..d2f3984fed 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -23,11 +23,11 @@ Seçtiğiniz değer geçerli bir seçenek değil. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. En az {{ limit }} seçenek belirtmelisiniz. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. En çok {{ limit }} seçenek belirtmelisiniz. @@ -75,7 +75,7 @@ Bu değer {{ limit }} ve altında olmalıdır. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Bu değer çok uzun. {{ limit }} karakter veya daha az olmalıdır. @@ -83,7 +83,7 @@ Bu değer {{ limit }} veya daha fazla olmalıdır. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Bu değer çok kısa. {{ limit }} karakter veya daha fazla olmaldır. @@ -179,7 +179,7 @@ Bu değer kullanıcının şu anki şifresi olmalıdır. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Bu değer tam olarak {{ limit }} karakter olmaldır. @@ -203,15 +203,15 @@ Bir PHP eklentisi dosyanın yüklemesini başarısız kıldı. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Bu derlem {{ limit }} veya daha çok eleman içermelidir - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Bu derlem {{ limit }} veya daha az eleman içermelidir - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Bu derlem {{ limit }} eleman içermelidir diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index 02afcd4209..91bb7b9922 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -23,11 +23,11 @@ Обране вами значення недопустиме. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. Ви повинні обрати хоча б {{ limit }} варіант.|Ви повинні обрати хоча б {{ limit }} варіанти.|Ви повинні обрати хоча б {{ limit }} варіантів. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. Ви повинні обрати не більше ніж {{ limit }} варіантів @@ -75,7 +75,7 @@ Значення повинно бути {{ limit }} або менше. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. Значення занадто довге. Повинно бути рівне {{ limit }} символу або менше.|Значення занадто довге. Повинно бути рівне {{ limit }} символам або менше.|Значення занадто довге. Повинно бути рівне {{ limit }} символам або менше. @@ -83,7 +83,7 @@ Значення повинно бути {{ limit }} або більше. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. Значення занадто коротке. Повинно бути рівне {{ limit }} символу або більше.|Значення занадто коротке. Повинно бути рівне {{ limit }} символам або більше.|Значення занадто коротке. Повинно бути рівне {{ limit }} символам або більше. @@ -179,7 +179,7 @@ Значення має бути поточним паролем користувача. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. Значення повиино бути рівним {{ limit }} символу.|Значення повиино бути рівним {{ limit }} символам.|Значення повиино бути рівним {{ limit }} символам. @@ -203,15 +203,15 @@ Розширення PHP викликало помилку при завантаженні. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. Ця колекція повинна містити {{ limit }} елемент чи більше.|Ця колекція повинна містити {{ limit }} елемента чи більше.|Ця колекція повинна містити {{ limit }} елементів чи більше. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. Ця колекція повинна містити {{ limit }} елемент чи менше.|Ця колекція повинна містити {{ limit }} елемента чи менше.|Ця колекція повинна містити {{ limit }} елементов чи менше. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. Ця колекція повинна містити рівно {{ limit }} елемент.|Ця колекція повинна містити рівно {{ limit }} елемента.|Ця колекція повинна містити рівно {{ limit }} елементів. @@ -224,4 +224,4 @@ - \ No newline at end of file + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf index 1130fa8e11..8bad4fb45f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf @@ -23,11 +23,11 @@ 选定变量的值不是有效的选项. - You must select at least {{ limit }} choices. + You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. 您至少要选择 {{ limit }} 个选项. - You must select at most {{ limit }} choices. + You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. 您最多能选择 {{ limit }} 个选项. @@ -75,7 +75,7 @@ 这个变量的值应该小于或等于 {{ limit }}. - This value is too long. It should have {{ limit }} characters or less. + This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. 字符串太长, 长度不可超过 {{ limit }} 个字符. @@ -83,7 +83,7 @@ 该变量的值应该大于或等于 {{ limit }}. - This value is too short. It should have {{ limit }} characters or more. + This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. 字符串太短, 长度不可少于 {{ limit }} 个字符. @@ -179,7 +179,7 @@ 该变量应为用户当前的密码. - This value should have exactly {{ limit }} characters. + This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. 该变量应为 {{ limit }} 个字符. @@ -203,15 +203,15 @@ 某个PHP扩展造成上传失败. - This collection should contain {{ limit }} elements or more. + This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. 该集合最少应包含 {{ limit }} 个元素. - This collection should contain {{ limit }} elements or less. + This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. 该集合最多包含 {{ limit }} 个元素. - This collection should contain exactly {{ limit }} elements. + This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. 该集合应包含正好 {{ limit }} 个元素element. From e00e5ecf4e65126da9994e6ffd17be09d52d29c8 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 18 Dec 2012 12:13:58 +0100 Subject: [PATCH 041/128] [Validator] Fixed failing test --- src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php b/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php index 1bbb33e26f..2868f57a82 100644 --- a/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php +++ b/src/Symfony/Component/Validator/Tests/ValidationVisitorTest.php @@ -459,6 +459,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase $violations = new ConstraintViolationList(array( // generated by the root object new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', @@ -467,6 +468,7 @@ class ValidationVisitorTest extends \PHPUnit_Framework_TestCase ), // nothing generated by the reference! new ConstraintViolation( + 'Failed', 'Failed', array(), 'Root', From cd662ccf7a7d29f0ed15c8fd6a0c2033fd14d709 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 8 Jan 2013 15:20:14 +0100 Subject: [PATCH 042/128] [Validator] Added ExceptionInterface, BadMethodCallException and InvalidArgumentException --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + .../Component/Validator/DefaultTranslator.php | 8 ++++--- .../Exception/BadMethodCallException.php | 21 +++++++++++++++++++ .../Exception/ExceptionInterface.php | 21 +++++++++++++++++++ .../Exception/InvalidArgumentException.php | 21 +++++++++++++++++++ 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Validator/Exception/BadMethodCallException.php create mode 100644 src/Symfony/Component/Validator/Exception/ExceptionInterface.php create mode 100644 src/Symfony/Component/Validator/Exception/InvalidArgumentException.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index b0f47b233b..fa26425aef 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -38,6 +38,7 @@ CHANGELOG * [BC BREAK] added `setTranslator()` and `setTranslationDomain()` to `ValidatorBuilderInterface` * improved the Validator to support pluralized messages by default * [BC BREAK] changed the source of all pluralized messages in the translation files to the pluralized version + * added ExceptionInterface, BadMethodCallException and InvalidArgumentException 2.1.0 ----- diff --git a/src/Symfony/Component/Validator/DefaultTranslator.php b/src/Symfony/Component/Validator/DefaultTranslator.php index c46856752d..455729bc16 100644 --- a/src/Symfony/Component/Validator/DefaultTranslator.php +++ b/src/Symfony/Component/Validator/DefaultTranslator.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Validator; +use Symfony\Component\Validator\Exception\BadMethodCallException; +use Symfony\Component\Validator\Exception\InvalidArgumentException; use Symfony\Component\Translation\TranslatorInterface; /** @@ -43,7 +45,7 @@ class DefaultTranslator implements TranslatorInterface } if (!isset($ids[1])) { - throw new \InvalidArgumentException(sprintf('The message "%s" cannot be pluralized, because it is missing a plural (e.g. "There is one apple|There are %%count%% apples").', $id)); + throw new InvalidArgumentException(sprintf('The message "%s" cannot be pluralized, because it is missing a plural (e.g. "There is one apple|There are %%count%% apples").', $id)); } return strtr($ids[1], $parameters); @@ -54,7 +56,7 @@ class DefaultTranslator implements TranslatorInterface */ public function setLocale($locale) { - throw new \BadMethodCallException('Unsupported method.'); + throw new BadMethodCallException('Unsupported method.'); } /** @@ -62,6 +64,6 @@ class DefaultTranslator implements TranslatorInterface */ public function getLocale() { - throw new \BadMethodCallException('Unsupported method.'); + throw new BadMethodCallException('Unsupported method.'); } } diff --git a/src/Symfony/Component/Validator/Exception/BadMethodCallException.php b/src/Symfony/Component/Validator/Exception/BadMethodCallException.php new file mode 100644 index 0000000000..939161bff3 --- /dev/null +++ b/src/Symfony/Component/Validator/Exception/BadMethodCallException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Exception; + +/** + * Base BadMethodCallException for the Validator component. + * + * @author Bernhard Schussek + */ +class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Validator/Exception/ExceptionInterface.php b/src/Symfony/Component/Validator/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..77d09b9029 --- /dev/null +++ b/src/Symfony/Component/Validator/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Exception; + +/** + * Base ExceptionInterface for the Validator component. + * + * @author Bernhard Schussek + */ +interface ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Validator/Exception/InvalidArgumentException.php b/src/Symfony/Component/Validator/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..22da39bb26 --- /dev/null +++ b/src/Symfony/Component/Validator/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Exception; + +/** + * Base InvalidArgumentException for the Validator component. + * + * @author Bernhard Schussek + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} From 2155719398132eb824280950dee3687377626ff5 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Tue, 8 Jan 2013 15:45:08 +0100 Subject: [PATCH 043/128] [Component] [Security] fixed PSR-2 coding violation in ClassUtilsTest class. --- .../Component/Security/Tests/Core/Util/ClassUtilsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Tests/Core/Util/ClassUtilsTest.php b/src/Symfony/Component/Security/Tests/Core/Util/ClassUtilsTest.php index 16378a646b..4266f21ed8 100644 --- a/src/Symfony/Component/Security/Tests/Core/Util/ClassUtilsTest.php +++ b/src/Symfony/Component/Security/Tests/Core/Util/ClassUtilsTest.php @@ -6,7 +6,7 @@ namespace Symfony\Component\Security\Tests\Core\Util class ClassUtilsTest extends \PHPUnit_Framework_TestCase { - static public function dataGetClass() + public static function dataGetClass() { return array( array('stdClass', 'stdClass'), From 58bfd60b0fdc24328cac5f43e360dce500fa6c73 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 8 Jan 2013 15:20:50 +0100 Subject: [PATCH 044/128] [Validator] Improved the inline documentation of DefaultTranslator --- .../Component/Validator/DefaultTranslator.php | 108 +++++++++++++++++- 1 file changed, 103 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Validator/DefaultTranslator.php b/src/Symfony/Component/Validator/DefaultTranslator.php index 455729bc16..7c38cbbb6b 100644 --- a/src/Symfony/Component/Validator/DefaultTranslator.php +++ b/src/Symfony/Component/Validator/DefaultTranslator.php @@ -19,14 +19,57 @@ use Symfony\Component\Translation\TranslatorInterface; * Simple translator implementation that simply replaces the parameters in * the message IDs. * - * Does not support translation domains or locales. + * Example usage: + * + * $translator = new DefaultTranslator(); + * + * echo $translator->trans( + * 'This is a {{ var }}.', + * array('{{ var }}' => 'donkey') + * ); + * + * // -> This is a donkey. + * + * echo $translator->transChoice( + * 'This is {{ count }} donkey.|These are {{ count }} donkeys.', + * 3, + * array('{{ count }}' => 'three') + * ); + * + * // -> These are three donkeys. + * + * This translator does not support message catalogs, translation domains or + * locales. Instead, it implements a subset of the capabilities of + * {@link \Symfony\Component\Translation\Translator} and can be used in places + * where translation is not required by default but should be optional. * * @author Bernhard Schussek */ class DefaultTranslator implements TranslatorInterface { /** - * {@inheritdoc} + * Interpolates the given message. + * + * Parameters are replaced in the message in the same manner that + * {@link strtr()} uses. + * + * Example usage: + * + * $translator = new DefaultTranslator(); + * + * echo $translator->trans( + * 'This is a {{ var }}.', + * array('{{ var }}' => 'donkey') + * ); + * + * // -> This is a donkey. + * + * @param string $id The message id + * @param array $parameters An array of parameters for the message + * @param string $domain Ignored + * @param string $locale Ignored + * + * @return string The interpolated string */ public function trans($id, array $parameters = array(), $domain = null, $locale = null) { @@ -34,7 +77,56 @@ class DefaultTranslator implements TranslatorInterface } /** - * {@inheritdoc} + * Interpolates the given choice message by choosing a variant according to a number. + * + * The variants are passed in the message ID using the format + * "|". "" is chosen if the passed $number is + * exactly 1. "" is chosen otherwise. + * + * This format is consistent with the format supported by + * {@link \Symfony\Component\Translation\Translator}, but it does not + * have the same expressiveness. While Translator supports intervals in + * message translations, which are needed for languages other than English, + * this translator does not. You should use Translator or a custom + * implementation of {@link TranslatorInterface} if you need this or similar + * functionality. + * + * Example usage: + * + * echo $translator->transChoice( + * 'This is {{ count }} donkey.|These are {{ count }} donkeys.', + * 0, + * array('{{ count }}' => 0) + * ); + * + * // -> These are 0 donkeys. + * + * echo $translator->transChoice( + * 'This is {{ count }} donkey.|These are {{ count }} donkeys.', + * 1, + * array('{{ count }}' => 1) + * ); + * + * // -> This is 1 donkey. + * + * echo $translator->transChoice( + * 'This is {{ count }} donkey.|These are {{ count }} donkeys.', + * 3, + * array('{{ count }}' => 3) + * ); + * + * // -> These are 3 donkeys. + * + * @param string $id The message id + * @param integer $number The number to use to find the index of the message + * @param array $parameters An array of parameters for the message + * @param string $domain Ignored + * @param string $locale Ignored + * + * @return string The translated string + * + * @throws InvalidArgumentException If the message id does not have the format + * "singular|plural". */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { @@ -52,7 +144,11 @@ class DefaultTranslator implements TranslatorInterface } /** - * {@inheritdoc} + * Not supported. + * + * @param string $locale The locale + * + * @throws BadMethodCallException */ public function setLocale($locale) { @@ -60,7 +156,9 @@ class DefaultTranslator implements TranslatorInterface } /** - * {@inheritdoc} + * Not supported. + * + * @throws BadMethodCallException */ public function getLocale() { From 586a16e8f8b6a1b039465320135429c5ab155154 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Tue, 8 Jan 2013 15:27:42 +0100 Subject: [PATCH 045/128] [Validator] Changed DefaultTranslator::getLocale() to always return 'en' --- src/Symfony/Component/Validator/DefaultTranslator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/DefaultTranslator.php b/src/Symfony/Component/Validator/DefaultTranslator.php index 7c38cbbb6b..c4f685e693 100644 --- a/src/Symfony/Component/Validator/DefaultTranslator.php +++ b/src/Symfony/Component/Validator/DefaultTranslator.php @@ -156,12 +156,12 @@ class DefaultTranslator implements TranslatorInterface } /** - * Not supported. + * Returns the locale of the translator. * - * @throws BadMethodCallException + * @return string Always returns 'en' */ public function getLocale() { - throw new BadMethodCallException('Unsupported method.'); + return 'en'; } } From 113271c2df924379fc72275f8c6514093e80eef0 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Tue, 8 Jan 2013 16:05:00 +0100 Subject: [PATCH 046/128] [Bundle] [FrameworkBundle] fixed indentation in esi.xml services file. --- src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml index 015afef397..d047196429 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml @@ -13,8 +13,8 @@ - - + + From 8ca1b805cea4d20339adf2e819688afa34e2182f Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 8 Jan 2013 17:05:32 +0100 Subject: [PATCH 047/128] [Console] Make style formatter matching less greedy to avoid having to escape when not needed --- .../Component/Console/Formatter/OutputFormatter.php | 2 +- .../Console/Tests/Formatter/OutputFormatterTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index b16e8447cc..8c44e36fc3 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -23,7 +23,7 @@ class OutputFormatter implements OutputFormatterInterface /** * The pattern to phrase the format. */ - const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>((?:(?!\\\\?<).)*)#is'; + const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>((?:(?!\\\\?<(?:/?[a-z]|/>)).)*)#is'; private $decorated; private $styles = array(); diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index 33187a7d26..3fc4c8c361 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -73,6 +73,16 @@ class FormatterStyleTest extends \PHPUnit_Framework_TestCase ); } + public function testStyleMatchingNotGreedy() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "(\033[32m>=2.0,<2.3\033[0m)", + $formatter->format('(>=2.0,<2.3)') + ); + } + public function testDeepNestedStyles() { $formatter = new OutputFormatter(true); From eb93e66aa72892b2a02c09e469a55cd889aeceb7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 8 Jan 2013 17:21:26 +0100 Subject: [PATCH 048/128] [Console] Fix style escaping parsing --- .../Component/Console/Formatter/OutputFormatter.php | 2 +- .../Console/Tests/Formatter/OutputFormatterTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index 8c44e36fc3..2e7219b6df 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -23,7 +23,7 @@ class OutputFormatter implements OutputFormatterInterface /** * The pattern to phrase the format. */ - const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>((?:(?!\\\\?<(?:/?[a-z]|/>)).)*)#is'; + const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>((?: [^<\\\\]+ | (?!<(?:/?[a-z]|/>)). | .(?<=\\\\<) )*)#isx'; private $decorated; private $styles = array(); diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index 3fc4c8c361..497630e87c 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -83,6 +83,16 @@ class FormatterStyleTest extends \PHPUnit_Framework_TestCase ); } + public function testStyleEscaping() + { + $formatter = new OutputFormatter(true); + + $this->assertEquals( + "(\033[32mz>=2.0,format('('.$formatter->escape('z>=2.0,)') + ); + } + public function testDeepNestedStyles() { $formatter = new OutputFormatter(true); From 2b14410a1f861b67d69a19160bbc42041e9bb50a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 8 Jan 2013 19:55:25 +0100 Subject: [PATCH 049/128] updated VERSION for 2.2.0-BETA1 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 46440a3468..cfcfb8081f 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -62,12 +62,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $classes; protected $errorReportingLevel; - const VERSION = '2.2.0-DEV'; + const VERSION = '2.2.0-BETA1'; const VERSION_ID = '20100'; const MAJOR_VERSION = '2'; const MINOR_VERSION = '2'; const RELEASE_VERSION = '0'; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = 'BETA1'; /** * Constructor. From 84e4f4b23fc525675689b196f15d5809e8b91849 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 8 Jan 2013 20:27:11 +0100 Subject: [PATCH 050/128] [Swiftmailer] updated Swiftmailer dep --- src/Symfony/Bridge/Swiftmailer/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Swiftmailer/composer.json b/src/Symfony/Bridge/Swiftmailer/composer.json index 28fb63fd4d..7d96c19300 100644 --- a/src/Symfony/Bridge/Swiftmailer/composer.json +++ b/src/Symfony/Bridge/Swiftmailer/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=5.3.3", - "swiftmailer/swiftmailer": ">=4.2.0,<4.3-dev" + "swiftmailer/swiftmailer": ">=4.2.0,<4.4-dev" }, "suggest": { "symfony/http-kernel": "2.2.*" From 91a86f8bec0e1653cc976ac3fc6163b43c40acfa Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 8 Jan 2013 23:26:48 +0100 Subject: [PATCH 051/128] [HttpKernel][Monolog] Add PSR-3 support to the LoggerInterface --- composer.json | 3 +- .../Bridge/Monolog/Handler/DebugHandler.php | 5 +- src/Symfony/Bridge/Monolog/composer.json | 2 +- .../HttpKernel/Log/LoggerInterface.php | 24 +----- .../Component/HttpKernel/Log/NullLogger.php | 35 ++++++++ .../Controller/ControllerResolverTest.php | 2 +- .../EventListener/ExceptionListenerTest.php | 4 +- .../Component/HttpKernel/Tests/Logger.php | 80 ++++++++++++++----- .../Component/HttpKernel/composer.json | 3 +- 9 files changed, 107 insertions(+), 51 deletions(-) diff --git a/composer.json b/composer.json index 5daf0b9aaa..995fe11c1b 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,8 @@ "doctrine/data-fixtures": "1.0.*", "doctrine/dbal": ">=2.2,<2.4-dev", "doctrine/orm": ">=2.2.3,<2.4-dev", - "monolog/monolog": ">=1.0,<1.3-dev", + "monolog/monolog": "~1.3", + "psr/log": "~1.0", "propel/propel1": "dev-master" }, "autoload": { diff --git a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php index 96b7fdd073..7ba04ab942 100644 --- a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php @@ -47,10 +47,7 @@ class DebugHandler extends TestHandler implements DebugLoggerInterface public function countErrors() { $cnt = 0; - $levels = array(Logger::ERROR, Logger::CRITICAL, Logger::ALERT); - if (defined('Monolog\Logger::EMERGENCY')) { - $levels[] = Logger::EMERGENCY; - } + $levels = array(Logger::ERROR, Logger::CRITICAL, Logger::ALERT, Logger::EMERGENCY); foreach ($levels as $level) { if (isset($this->recordsByLevel[$level])) { $cnt += count($this->recordsByLevel[$level]); diff --git a/src/Symfony/Bridge/Monolog/composer.json b/src/Symfony/Bridge/Monolog/composer.json index 09327f2564..0e89cf2346 100644 --- a/src/Symfony/Bridge/Monolog/composer.json +++ b/src/Symfony/Bridge/Monolog/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=5.3.3", "symfony/http-kernel": "2.2.*", - "monolog/monolog": ">=1.0,<1.3-dev" + "monolog/monolog": "~1.3" }, "autoload": { "psr-0": { "Symfony\\Bridge\\Monolog\\": "" } diff --git a/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php b/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php index 34847c8098..db3fb47c54 100644 --- a/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php +++ b/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpKernel\Log; +use Psr\Log\LoggerInterface as PsrLogger; + /** * LoggerInterface. * @@ -18,18 +20,13 @@ namespace Symfony\Component\HttpKernel\Log; * * @api */ -interface LoggerInterface +interface LoggerInterface extends PsrLogger { /** * @api */ public function emerg($message, array $context = array()); - /** - * @api - */ - public function alert($message, array $context = array()); - /** * @api */ @@ -44,19 +41,4 @@ interface LoggerInterface * @api */ public function warn($message, array $context = array()); - - /** - * @api - */ - public function notice($message, array $context = array()); - - /** - * @api - */ - public function info($message, array $context = array()); - - /** - * @api - */ - public function debug($message, array $context = array()); } diff --git a/src/Symfony/Component/HttpKernel/Log/NullLogger.php b/src/Symfony/Component/HttpKernel/Log/NullLogger.php index 8edec8913b..67ad1bfbec 100644 --- a/src/Symfony/Component/HttpKernel/Log/NullLogger.php +++ b/src/Symfony/Component/HttpKernel/Log/NullLogger.php @@ -22,6 +22,13 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface; */ class NullLogger implements LoggerInterface { + /** + * @api + */ + public function log($level, $message, array $context = array()) + { + } + /** * @api */ @@ -29,6 +36,13 @@ class NullLogger implements LoggerInterface { } + /** + * @api + */ + public function emergency($message, array $context = array()) + { + } + /** * @api */ @@ -43,6 +57,13 @@ class NullLogger implements LoggerInterface { } + /** + * @api + */ + public function critical($message, array $context = array()) + { + } + /** * @api */ @@ -50,6 +71,13 @@ class NullLogger implements LoggerInterface { } + /** + * @api + */ + public function error($message, array $context = array()) + { + } + /** * @api */ @@ -57,6 +85,13 @@ class NullLogger implements LoggerInterface { } + /** + * @api + */ + public function warning($message, array $context = array()) + { + } + /** * @api */ diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php index d0afdf3318..c19af8216d 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ControllerResolverTest.php @@ -30,7 +30,7 @@ class ControllerResolverTest extends \PHPUnit_Framework_TestCase $request = Request::create('/'); $this->assertFalse($resolver->getController($request), '->getController() returns false when the request has no _controller attribute'); - $this->assertEquals(array('Unable to look for the controller as the "_controller" parameter is missing'), $logger->getLogs('warn')); + $this->assertEquals(array('Unable to look for the controller as the "_controller" parameter is missing'), $logger->getLogs('warning')); $request->attributes->set('_controller', 'Symfony\Component\HttpKernel\Tests\ControllerResolverTest::testGetController'); $controller = $resolver->getController($request); diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php index a10ae9b6fb..41b3dec0f5 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ExceptionListenerTest.php @@ -93,7 +93,7 @@ class ExceptionListenerTest extends \PHPUnit_Framework_TestCase } $this->assertEquals(3, $logger->countErrors()); - $this->assertCount(3, $logger->getLogs('crit')); + $this->assertCount(3, $logger->getLogs('critical')); } public function provider() @@ -117,7 +117,7 @@ class TestLogger extends Logger implements DebugLoggerInterface { public function countErrors() { - return count($this->logs['crit']); + return count($this->logs['critical']); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Logger.php b/src/Symfony/Component/HttpKernel/Tests/Logger.php index 88babf3142..278cd9c677 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Logger.php +++ b/src/Symfony/Component/HttpKernel/Tests/Logger.php @@ -22,67 +22,107 @@ class Logger implements LoggerInterface $this->clear(); } - public function getLogs($priority = false) + public function getLogs($level = false) { - return false === $priority ? $this->logs : $this->logs[$priority]; + return false === $level ? $this->logs : $this->logs[$level]; } public function clear() { $this->logs = array( - 'emerg' => array(), + 'emergency' => array(), 'alert' => array(), - 'crit' => array(), - 'err' => array(), - 'warn' => array(), + 'critical' => array(), + 'error' => array(), + 'warning' => array(), 'notice' => array(), 'info' => array(), 'debug' => array(), ); } - public function log($message, $priority) + public function log($level, $message, array $context = array()) { - $this->logs[$priority][] = $message; + $this->logs[$level][] = $message; } - public function emerg($message, array $context = array()) + public function emergency($message, array $context = array()) { - $this->log($message, 'emerg'); + $this->log('emergency', $message, $context); } public function alert($message, array $context = array()) { - $this->log($message, 'alert'); + $this->log('alert', $message, $context); } - public function crit($message, array $context = array()) + public function critical($message, array $context = array()) { - $this->log($message, 'crit'); + $this->log('critical', $message, $context); } - public function err($message, array $context = array()) + public function error($message, array $context = array()) { - $this->log($message, 'err'); + $this->log('error', $message, $context); } - public function warn($message, array $context = array()) + public function warning($message, array $context = array()) { - $this->log($message, 'warn'); + $this->log('warning', $message, $context); } public function notice($message, array $context = array()) { - $this->log($message, 'notice'); + $this->log('notice', $message, $context); } public function info($message, array $context = array()) { - $this->log($message, 'info'); + $this->log('info', $message, $context); } public function debug($message, array $context = array()) { - $this->log($message, 'debug'); + $this->log('debug', $message, $context); + } + + /** + * @deprecated + */ + public function emerg($message, array $context = array()) + { + trigger_error('Use emergency() which is PSR-3 compatible', E_USER_DEPRECATED); + + $this->log('emergency', $message, $context); + } + + /** + * @deprecated + */ + public function crit($message, array $context = array()) + { + trigger_error('Use crit() which is PSR-3 compatible', E_USER_DEPRECATED); + + $this->log('critical', $message, $context); + } + + /** + * @deprecated + */ + public function err($message, array $context = array()) + { + trigger_error('Use err() which is PSR-3 compatible', E_USER_DEPRECATED); + + $this->log('error', $message, $context); + } + + /** + * @deprecated + */ + public function warn($message, array $context = array()) + { + trigger_error('Use warn() which is PSR-3 compatible', E_USER_DEPRECATED); + + $this->log('warning', $message, $context); } } diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index a6cf81f10e..9680fadd2a 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -18,7 +18,8 @@ "require": { "php": ">=5.3.3", "symfony/event-dispatcher": "2.2.*", - "symfony/http-foundation": "2.2.*" + "symfony/http-foundation": "2.2.*", + "psr/log": "~1.0" }, "require-dev": { "symfony/browser-kit": "2.2.*", From 36197dcb8303f6ebd225d856b818d3875fd400ed Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Tue, 8 Jan 2013 18:19:54 +0000 Subject: [PATCH 052/128] Fixed typos --- src/Symfony/Component/Finder/Shell/Command.php | 2 +- src/Symfony/Component/Form/Form.php | 4 ++-- src/Symfony/Component/HttpFoundation/Request.php | 4 ++-- .../Session/Storage/Handler/MemcachedSessionHandlerTest.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Finder/Shell/Command.php b/src/Symfony/Component/Finder/Shell/Command.php index 14111797ed..0c4a3118cf 100644 --- a/src/Symfony/Component/Finder/Shell/Command.php +++ b/src/Symfony/Component/Finder/Shell/Command.php @@ -198,7 +198,7 @@ class Command public function end() { if (null === $this->parent) { - throw new \RuntimeException('Calling end on root command dont makes sense.'); + throw new \RuntimeException('Calling end on root command doesn\'t make sense.'); } return $this->parent; diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index ad44f15d35..eb93637877 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -542,7 +542,7 @@ class Form implements \IteratorAggregate, FormInterface } // Check whether the form is compound. - // This check is preferrable over checking the number of children, + // This check is preferable over checking the number of children, // since forms without children may also be compound. // (think of empty collection forms) if ($this->config->getCompound()) { @@ -837,7 +837,7 @@ class Form implements \IteratorAggregate, FormInterface */ public function getChildren() { - trigger_error('getChilren() is deprecated since version 2.1 and will be removed in 2.3. Use all() instead.', E_USER_DEPRECATED); + trigger_error('getChildren() is deprecated since version 2.1 and will be removed in 2.3. Use all() instead.', E_USER_DEPRECATED); return $this->all(); } diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 3b5d1448a0..e145a7e698 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -572,7 +572,7 @@ class Request * Be warned that enabling this feature might lead to CSRF issues in your code. * Check that you are using CSRF tokens when required. * - * The HTTP method can only be overriden when the real HTTP method is POST. + * The HTTP method can only be overridden when the real HTTP method is POST. */ public static function enableHttpMethodParameterOverride() { @@ -722,7 +722,7 @@ class Request * * * http://localhost/mysite returns an empty string * * http://localhost/mysite/about returns '/about' - * * htpp://localhost/mysite/enco%20ded returns '/enco%20ded' + * * http://localhost/mysite/enco%20ded returns '/enco%20ded' * * http://localhost/mysite/about?var=1 returns '/about' * * @return string The raw path (i.e. not urldecoded) diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php index 6f158cd1b7..7fbfd0a479 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php @@ -13,7 +13,7 @@ namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler; -class MemcacheddSessionHandlerTest extends \PHPUnit_Framework_TestCase +class MemcachedSessionHandlerTest extends \PHPUnit_Framework_TestCase { const PREFIX = 'prefix_'; const TTL = 1000; From 1e5a890864d3bd0a2c09aaca264165bcddbd0d0d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 8 Jan 2013 23:27:26 +0100 Subject: [PATCH 053/128] [Monolog] Mark old non-PSR3 methods as deprecated --- composer.json | 4 +-- src/Symfony/Bridge/Monolog/Logger.php | 32 +++++++++++++++++++ .../Bridge/Propel1/Logger/PropelLogger.php | 6 ++-- .../Controller/ControllerResolver.php | 2 +- .../HttpKernel/Debug/ErrorHandler.php | 2 +- .../EventListener/ExceptionListener.php | 4 +-- .../HttpKernel/Log/LoggerInterface.php | 5 +++ .../HttpKernel/Profiler/Profiler.php | 2 +- .../Routing/Generator/UrlGenerator.php | 4 +-- .../Http/Firewall/ContextListener.php | 4 +-- .../Http/Firewall/ExceptionListener.php | 2 +- .../Http/Firewall/RememberMeListener.php | 2 +- .../RememberMe/AbstractRememberMeServices.php | 2 +- 13 files changed, 54 insertions(+), 17 deletions(-) diff --git a/composer.json b/composer.json index 995fe11c1b..85d7cc2ef3 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "require": { "php": ">=5.3.3", "doctrine/common": ">2.2,<2.4-dev", - "twig/twig": ">=1.11.0,<2.0-dev" + "twig/twig": ">=1.11.0,<2.0-dev", + "psr/log": "~1.0" }, "replace": { "symfony/browser-kit": "self.version", @@ -60,7 +61,6 @@ "doctrine/dbal": ">=2.2,<2.4-dev", "doctrine/orm": ">=2.2.3,<2.4-dev", "monolog/monolog": "~1.3", - "psr/log": "~1.0", "propel/propel1": "dev-master" }, "autoload": { diff --git a/src/Symfony/Bridge/Monolog/Logger.php b/src/Symfony/Bridge/Monolog/Logger.php index f8183819f9..da5fff744d 100644 --- a/src/Symfony/Bridge/Monolog/Logger.php +++ b/src/Symfony/Bridge/Monolog/Logger.php @@ -22,6 +22,38 @@ use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; */ class Logger extends BaseLogger implements LoggerInterface, DebugLoggerInterface { + /** + * @deprecated since 2.2, to be removed in 3.0. Use emergency() which is PSR-3 compatible. + */ + public function emerg($message, array $context = array()) + { + return parent::addRecord(BaseLogger::EMERGENCY, $message, $context); + } + + /** + * @deprecated since 2.2, to be removed in 3.0. Use critical() which is PSR-3 compatible. + */ + public function crit($message, array $context = array()) + { + return parent::addRecord(BaseLogger::CRITICAL, $message, $context); + } + + /** + * @deprecated since 2.2, to be removed in 3.0. Use error() which is PSR-3 compatible. + */ + public function err($message, array $context = array()) + { + return parent::addRecord(BaseLogger::ERROR, $message, $context); + } + + /** + * @deprecated since 2.2, to be removed in 3.0. Use warning() which is PSR-3 compatible. + */ + public function warn($message, array $context = array()) + { + return parent::addRecord(BaseLogger::WARNING, $message, $context); + } + /** * @see Symfony\Component\HttpKernel\Log\DebugLoggerInterface */ diff --git a/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php b/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php index 1fd7dedf90..bcdcd13e23 100644 --- a/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php +++ b/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php @@ -73,7 +73,7 @@ class PropelLogger public function crit($message) { if (null !== $this->logger) { - $this->logger->crit($message); + $this->logger->critical($message); } } @@ -85,7 +85,7 @@ class PropelLogger public function err($message) { if (null !== $this->logger) { - $this->logger->err($message); + $this->logger->error($message); } } @@ -97,7 +97,7 @@ class PropelLogger public function warning($message) { if (null !== $this->logger) { - $this->logger->warn($message); + $this->logger->warning($message); } } diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php index 0d308c9d83..b37bef5560 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php @@ -58,7 +58,7 @@ class ControllerResolver implements ControllerResolverInterface { if (!$controller = $request->attributes->get('_controller')) { if (null !== $this->logger) { - $this->logger->warn('Unable to look for the controller as the "_controller" parameter is missing'); + $this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing'); } return false; diff --git a/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php b/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php index 50eadfe0a5..672b77dfe3 100644 --- a/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php +++ b/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php @@ -95,7 +95,7 @@ class ErrorHandler : debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10) ); - self::$logger->warn($message, $deprecation); + self::$logger->warning($message, $deprecation); } return true; diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php index 8c49d022b0..643f6cf573 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php @@ -97,9 +97,9 @@ class ExceptionListener implements EventSubscriberInterface $isCritical = !$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500; if (null !== $this->logger) { if ($isCritical) { - $this->logger->crit($message); + $this->logger->critical($message); } else { - $this->logger->err($message); + $this->logger->error($message); } } elseif (!$original || $isCritical) { error_log($message); diff --git a/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php b/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php index db3fb47c54..148c92c4cc 100644 --- a/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php +++ b/src/Symfony/Component/HttpKernel/Log/LoggerInterface.php @@ -18,27 +18,32 @@ use Psr\Log\LoggerInterface as PsrLogger; * * @author Fabien Potencier * + * @deprecated since 2.2, to be removed in 3.0. Type-hint \Psr\Log\LoggerInterface instead. * @api */ interface LoggerInterface extends PsrLogger { /** * @api + * @deprecated since 2.2, to be removed in 3.0. Use emergency() which is PSR-3 compatible. */ public function emerg($message, array $context = array()); /** * @api + * @deprecated since 2.2, to be removed in 3.0. Use critical() which is PSR-3 compatible. */ public function crit($message, array $context = array()); /** * @api + * @deprecated since 2.2, to be removed in 3.0. Use error() which is PSR-3 compatible. */ public function err($message, array $context = array()); /** * @api + * @deprecated since 2.2, to be removed in 3.0. Use warning() which is PSR-3 compatible. */ public function warn($message, array $context = array()); } diff --git a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php index ea93a24aea..cbe8b590dc 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php +++ b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php @@ -110,7 +110,7 @@ class Profiler public function saveProfile(Profile $profile) { if (!($ret = $this->storage->write($profile)) && null !== $this->logger) { - $this->logger->warn('Unable to store the profiler information.'); + $this->logger->warning('Unable to store the profiler information.'); } return $ret; diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index aa0a3ee8f2..86d7cde119 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -166,7 +166,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt } if ($this->logger) { - $this->logger->err($message); + $this->logger->error($message); } return null; @@ -224,7 +224,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt } if ($this->logger) { - $this->logger->err($message); + $this->logger->error($message); } return null; diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 0b5c955563..2f16ab4681 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -89,7 +89,7 @@ class ContextListener implements ListenerInterface $token = $this->refreshUser($token); } elseif (null !== $token) { if (null !== $this->logger) { - $this->logger->warn(sprintf('Session includes a "%s" where a security token is expected', is_object($token) ? get_class($token) : gettype($token))); + $this->logger->warning(sprintf('Session includes a "%s" where a security token is expected', is_object($token) ? get_class($token) : gettype($token))); } $token = null; @@ -161,7 +161,7 @@ class ContextListener implements ListenerInterface // let's try the next user provider } catch (UsernameNotFoundException $notFound) { if (null !== $this->logger) { - $this->logger->warn(sprintf('Username "%s" could not be found.', $user->getUsername())); + $this->logger->warning(sprintf('Username "%s" could not be found.', $user->getUsername())); } return null; diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index f134f9c819..54bddd30a4 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -134,7 +134,7 @@ class ExceptionListener } } catch (\Exception $e) { if (null !== $this->logger) { - $this->logger->err(sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage())); + $this->logger->error(sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage())); } $event->setException(new \RuntimeException('Exception thrown when handling an exception.', 0, $e)); diff --git a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php index 3614f7915d..219606f57d 100644 --- a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php @@ -82,7 +82,7 @@ class RememberMeListener implements ListenerInterface } } catch (AuthenticationException $failed) { if (null !== $this->logger) { - $this->logger->warn( + $this->logger->warning( 'SecurityContext not populated with remember-me token as the' .' AuthenticationManager rejected the AuthenticationToken returned' .' by the RememberMeServices: '.$failed->getMessage() diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php index e49ce14d72..e80ccd45ad 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php @@ -129,7 +129,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface } } catch (UnsupportedUserException $unSupported) { if (null !== $this->logger) { - $this->logger->warn('User class for remember-me cookie not supported.'); + $this->logger->warning('User class for remember-me cookie not supported.'); } } catch (AuthenticationException $invalid) { if (null !== $this->logger) { From dca4528ba83e70626fd590ed97a04f810438c2c8 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Jan 2013 10:17:38 +0100 Subject: [PATCH 054/128] [HttpKernel] Extend psr/log's NullLogger class --- .../Component/HttpKernel/Log/NullLogger.php | 70 ++----------------- 1 file changed, 6 insertions(+), 64 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Log/NullLogger.php b/src/Symfony/Component/HttpKernel/Log/NullLogger.php index 67ad1bfbec..c403084b1a 100644 --- a/src/Symfony/Component/HttpKernel/Log/NullLogger.php +++ b/src/Symfony/Component/HttpKernel/Log/NullLogger.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Log; use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\NullLogger as PsrNullLogger; /** * NullLogger. @@ -20,17 +21,11 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface; * * @api */ -class NullLogger implements LoggerInterface +class NullLogger extends PsrNullLogger { /** * @api - */ - public function log($level, $message, array $context = array()) - { - } - - /** - * @api + * @deprecated since 2.2, to be removed in 3.0. Use emergency() which is PSR-3 compatible. */ public function emerg($message, array $context = array()) { @@ -38,20 +33,7 @@ class NullLogger implements LoggerInterface /** * @api - */ - public function emergency($message, array $context = array()) - { - } - - /** - * @api - */ - public function alert($message, array $context = array()) - { - } - - /** - * @api + * @deprecated since 2.2, to be removed in 3.0. Use critical() which is PSR-3 compatible. */ public function crit($message, array $context = array()) { @@ -59,13 +41,7 @@ class NullLogger implements LoggerInterface /** * @api - */ - public function critical($message, array $context = array()) - { - } - - /** - * @api + * @deprecated since 2.2, to be removed in 3.0. Use error() which is PSR-3 compatible. */ public function err($message, array $context = array()) { @@ -73,43 +49,9 @@ class NullLogger implements LoggerInterface /** * @api - */ - public function error($message, array $context = array()) - { - } - - /** - * @api + * @deprecated since 2.2, to be removed in 3.0. Use warning() which is PSR-3 compatible. */ public function warn($message, array $context = array()) { } - - /** - * @api - */ - public function warning($message, array $context = array()) - { - } - - /** - * @api - */ - public function notice($message, array $context = array()) - { - } - - /** - * @api - */ - public function info($message, array $context = array()) - { - } - - /** - * @api - */ - public function debug($message, array $context = array()) - { - } } From c1aff96eb05cb681ba0a78cd1ff36d4bea6a207a Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Wed, 9 Jan 2013 10:35:45 +0100 Subject: [PATCH 055/128] [Form] Fixed regression introduced when merging 2.1 into master --- src/Symfony/Component/Form/FormBuilder.php | 1 - src/Symfony/Component/Form/Tests/FormBuilderTest.php | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index 9d11b5f750..0dfd8d0962 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -211,7 +211,6 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB { $config = parent::getFormConfig(); - $config->factory = null; $config->parent = null; $config->children = array(); $config->unresolvedChildren = array(); diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php index 6836ea140d..14c8746f8b 100644 --- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php @@ -247,17 +247,14 @@ class FormBuilderTest extends \PHPUnit_Framework_TestCase $config = $builder->getFormConfig(); $reflClass = new \ReflectionClass($config); - $factory = $reflClass->getProperty('factory'); $parent = $reflClass->getProperty('parent'); $children = $reflClass->getProperty('children'); $unresolvedChildren = $reflClass->getProperty('unresolvedChildren'); - $factory->setAccessible(true); $parent->setAccessible(true); $children->setAccessible(true); $unresolvedChildren->setAccessible(true); - $this->assertNull($factory->getValue($config)); $this->assertNull($parent->getValue($config)); $this->assertEmpty($children->getValue($config)); $this->assertEmpty($unresolvedChildren->getValue($config)); From 67d742345680d74bf741591b06e7f0d8b513e0ca Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Jan 2013 10:41:17 +0100 Subject: [PATCH 056/128] Remove use of deprecated HttpKernel LoggerInterface --- src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php | 2 +- src/Symfony/Bridge/Propel1/Logger/PropelLogger.php | 2 +- .../FrameworkBundle/Controller/ControllerResolver.php | 2 +- .../Bundle/FrameworkBundle/Routing/DelegatingLoader.php | 2 +- .../Bundle/FrameworkBundle/Templating/Debugger.php | 2 +- .../HttpKernel/Controller/ControllerResolver.php | 2 +- src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php | 2 +- .../HttpKernel/Debug/TraceableEventDispatcher.php | 2 +- .../EventListener/DeprecationLoggerListener.php | 2 +- .../HttpKernel/EventListener/ExceptionListener.php | 2 +- .../Component/HttpKernel/EventListener/RouterListener.php | 2 +- src/Symfony/Component/HttpKernel/Log/NullLogger.php | 2 +- src/Symfony/Component/HttpKernel/Profiler/Profiler.php | 2 +- .../Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php | 4 ++-- .../Tests/Debug/TraceableEventDispatcherTest.php | 4 ++-- src/Symfony/Component/HttpKernel/Tests/Logger.php | 2 +- .../Routing/Generator/Dumper/PhpGeneratorDumper.php | 2 +- src/Symfony/Component/Routing/Generator/UrlGenerator.php | 2 +- src/Symfony/Component/Routing/Router.php | 2 +- .../Routing/Tests/Generator/UrlGeneratorTest.php | 8 ++++---- src/Symfony/Component/Routing/composer.json | 3 ++- src/Symfony/Component/Security/Acl/Voter/AclVoter.php | 2 +- src/Symfony/Component/Security/Core/Util/SecureRandom.php | 2 +- .../DefaultAuthenticationFailureHandler.php | 2 +- .../Http/EntryPoint/DigestAuthenticationEntryPoint.php | 2 +- .../Http/Firewall/AbstractAuthenticationListener.php | 2 +- .../Http/Firewall/AbstractPreAuthenticatedListener.php | 2 +- .../Component/Security/Http/Firewall/AccessListener.php | 2 +- .../Http/Firewall/AnonymousAuthenticationListener.php | 2 +- .../Http/Firewall/BasicAuthenticationListener.php | 2 +- .../Component/Security/Http/Firewall/ChannelListener.php | 2 +- .../Component/Security/Http/Firewall/ContextListener.php | 2 +- .../Http/Firewall/DigestAuthenticationListener.php | 2 +- .../Security/Http/Firewall/ExceptionListener.php | 2 +- .../Security/Http/Firewall/RememberMeListener.php | 2 +- .../Security/Http/Firewall/SwitchUserListener.php | 2 +- .../UsernamePasswordFormAuthenticationListener.php | 2 +- .../Security/Http/Firewall/X509AuthenticationListener.php | 2 +- .../Http/RememberMe/AbstractRememberMeServices.php | 2 +- .../Tests/Http/Firewall/RememberMeListenerTest.php | 2 +- src/Symfony/Component/Security/composer.json | 3 ++- 41 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php index 9d441a2738..853f8d4887 100644 --- a/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php +++ b/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php @@ -11,7 +11,7 @@ namespace Symfony\Bridge\Doctrine\Logger; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\Stopwatch\Stopwatch; use Doctrine\DBAL\Logging\SQLLogger; diff --git a/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php b/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php index bcdcd13e23..91c0061f4c 100644 --- a/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php +++ b/src/Symfony/Bridge/Propel1/Logger/PropelLogger.php @@ -12,7 +12,7 @@ namespace Symfony\Bridge\Propel1\Logger; use Symfony\Component\Stopwatch\Stopwatch; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * PropelLogger. diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php index 08a76f01ea..a620546b16 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php @@ -11,7 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Controller; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php index a1baa9a51d..e0ec390f1e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php @@ -14,7 +14,7 @@ namespace Symfony\Bundle\FrameworkBundle\Routing; use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser; use Symfony\Component\Config\Loader\DelegatingLoader as BaseDelegatingLoader; use Symfony\Component\Config\Loader\LoaderResolverInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * DelegatingLoader delegates route loading to other loaders using a loader resolver. diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Debugger.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Debugger.php index e63d034158..19a59381d0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Debugger.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Debugger.php @@ -12,7 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\Templating; use Symfony\Component\Templating\DebuggerInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * Binds the Symfony templating loader debugger to the Symfony logger. diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php index b37bef5560..bbe7746734 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\Controller; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; /** diff --git a/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php b/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php index 672b77dfe3..80ece22653 100644 --- a/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php +++ b/src/Symfony/Component/HttpKernel/Debug/ErrorHandler.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\HttpKernel\Exception\FatalErrorException; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * ErrorHandler. diff --git a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php index a8a27d9eab..adbd4969ab 100644 --- a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php @@ -13,7 +13,7 @@ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Profiler\Profile; use Symfony\Component\HttpKernel\Profiler\Profiler; use Symfony\Component\HttpKernel\HttpKernelInterface; diff --git a/src/Symfony/Component/HttpKernel/EventListener/DeprecationLoggerListener.php b/src/Symfony/Component/HttpKernel/EventListener/DeprecationLoggerListener.php index a40e866155..ca2c480582 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/DeprecationLoggerListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/DeprecationLoggerListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\EventListener; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Debug\ErrorHandler; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\KernelEvents; diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php index 643f6cf573..d3c3a31eff 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\EventListener; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\KernelEvents; diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index 208ffc1782..606b358e72 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\EventListener; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; diff --git a/src/Symfony/Component/HttpKernel/Log/NullLogger.php b/src/Symfony/Component/HttpKernel/Log/NullLogger.php index c403084b1a..b5aa2e3094 100644 --- a/src/Symfony/Component/HttpKernel/Log/NullLogger.php +++ b/src/Symfony/Component/HttpKernel/Log/NullLogger.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\Log; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Psr\Log\NullLogger as PsrNullLogger; /** diff --git a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php index cbe8b590dc..1ca3e97303 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/Profiler.php +++ b/src/Symfony/Component/HttpKernel/Profiler/Profiler.php @@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Profiler\ProfilerStorageInterface; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * Profiler. diff --git a/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php b/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php index fdd02eaaf5..7cf6ce7c2f 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Debug/ErrorHandlerTest.php @@ -67,7 +67,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase restore_error_handler(); - $logger = $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface'); + $logger = $this->getMock('Psr\Log\LoggerInterface'); $that = $this; $warnArgCheck = function($message, $context) use ($that) { @@ -84,7 +84,7 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase $logger ->expects($this->once()) - ->method('warn') + ->method('warning') ->will($this->returnCallback($warnArgCheck)) ; diff --git a/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php index 07faa8a688..e1679d977e 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Debug/TraceableEventDispatcherTest.php @@ -102,7 +102,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase public function testLogger() { - $logger = $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface'); + $logger = $this->getMock('Psr\Log\LoggerInterface'); $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); @@ -117,7 +117,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase public function testLoggerWithStoppedEvent() { - $logger = $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface'); + $logger = $this->getMock('Psr\Log\LoggerInterface'); $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); diff --git a/src/Symfony/Component/HttpKernel/Tests/Logger.php b/src/Symfony/Component/HttpKernel/Tests/Logger.php index 278cd9c677..1be77f26ab 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Logger.php +++ b/src/Symfony/Component/HttpKernel/Tests/Logger.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\Tests; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; class Logger implements LoggerInterface { diff --git a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php index c85f0201e4..005f95fd65 100644 --- a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php +++ b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php @@ -47,7 +47,7 @@ class PhpGeneratorDumper extends GeneratorDumper use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Exception\RouteNotFoundException; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * {$options['class']} diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 86d7cde119..c6fe78a0df 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -16,7 +16,7 @@ use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Exception\InvalidParameterException; use Symfony\Component\Routing\Exception\RouteNotFoundException; use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * UrlGenerator generates a URL based on a set of routes. diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index 68d73ab24d..66c69b8937 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Routing; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\ConfigCache; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\Routing\Generator\ConfigurableRequirementsInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Matcher\UrlMatcherInterface; diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index 7b6495f3c9..8a8161ec8e 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -206,14 +206,14 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger() { - if (!interface_exists('Symfony\Component\HttpKernel\Log\LoggerInterface')) { - $this->markTestSkipped('The "HttpKernel" component is not available'); + if (!interface_exists('Psr\Log\LoggerInterface')) { + $this->markTestSkipped('The "psr/log" package is not available'); } $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+'))); - $logger = $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface'); + $logger = $this->getMock('Psr\Log\LoggerInterface'); $logger->expects($this->once()) - ->method('err'); + ->method('error'); $generator = $this->getGenerator($routes, array(), $logger); $generator->setStrictRequirements(false); $this->assertNull($generator->generate('test', array('foo' => 'bar'), true)); diff --git a/src/Symfony/Component/Routing/composer.json b/src/Symfony/Component/Routing/composer.json index d3f653b761..d29f645424 100644 --- a/src/Symfony/Component/Routing/composer.json +++ b/src/Symfony/Component/Routing/composer.json @@ -22,7 +22,8 @@ "symfony/config": "2.2.*", "symfony/yaml": "2.2.*", "symfony/http-kernel": "2.2.*", - "doctrine/common": ">=2.2,<2.4-dev" + "doctrine/common": ">=2.2,<2.4-dev", + "psr/log": "~1.0" }, "suggest": { "symfony/config": "2.2.*", diff --git a/src/Symfony/Component/Security/Acl/Voter/AclVoter.php b/src/Symfony/Component/Security/Acl/Voter/AclVoter.php index 456c434b92..5e9aee6fa6 100644 --- a/src/Symfony/Component/Security/Acl/Voter/AclVoter.php +++ b/src/Symfony/Component/Security/Acl/Voter/AclVoter.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Security\Acl\Voter; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\Security\Acl\Exception\NoAceFoundException; use Symfony\Component\Security\Acl\Exception\AclNotFoundException; use Symfony\Component\Security\Acl\Model\AclProviderInterface; diff --git a/src/Symfony/Component/Security/Core/Util/SecureRandom.php b/src/Symfony/Component/Security/Core/Util/SecureRandom.php index 77f1d8c265..841b9af38b 100644 --- a/src/Symfony/Component/Security/Core/Util/SecureRandom.php +++ b/src/Symfony/Component/Security/Core/Util/SecureRandom.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Security\Core\Util; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * A secure random number generator implementation. diff --git a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php index d54374557b..64f84f0e9f 100644 --- a/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php +++ b/src/Symfony/Component/Security/Http/Authentication/DefaultAuthenticationFailureHandler.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Security\Http\Authentication; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Http\HttpUtils; diff --git a/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php b/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php index 37fba8595e..1131b58917 100644 --- a/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php +++ b/src/Symfony/Component/Security/Http/EntryPoint/DigestAuthenticationEntryPoint.php @@ -16,7 +16,7 @@ use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface use Symfony\Component\Security\Core\Exception\NonceExpiredException; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * DigestAuthenticationEntryPoint starts an HTTP Digest authentication. diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php index 087aa082c3..80f47f7581 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php @@ -19,7 +19,7 @@ use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\SessionUnavailableException; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php index 66041be7b6..d7e46cf2b2 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -18,7 +18,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcherInterface; diff --git a/src/Symfony/Component/Security/Http/Firewall/AccessListener.php b/src/Symfony/Component/Security/Http/Firewall/AccessListener.php index 67766efd76..c3894ef0ed 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AccessListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AccessListener.php @@ -15,7 +15,7 @@ use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Http\AccessMapInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; diff --git a/src/Symfony/Component/Security/Http/Firewall/AnonymousAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/AnonymousAuthenticationListener.php index d00865d041..af2213bc25 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AnonymousAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AnonymousAuthenticationListener.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\SecurityContextInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; diff --git a/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php index e331179543..5b1c8b318d 100644 --- a/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/BasicAuthenticationListener.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; diff --git a/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php b/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php index 9b0f8c63db..9e4a6ee453 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ChannelListener.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Http\AccessMapInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; /** diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 2f16ab4681..bfbf0ee68d 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; diff --git a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php index 3c83c87807..7ab3dcf757 100644 --- a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\BadCredentialsException; diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 54bddd30a4..f12cd4900b 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -23,7 +23,7 @@ use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationExceptio use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; diff --git a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php index 219606f57d..5a856e27f4 100644 --- a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index 8e4f4e5209..bad6b2b7cc 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -16,7 +16,7 @@ use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserCheckerInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\HttpFoundation\RedirectResponse; diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 388c014948..81c2b374d0 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; diff --git a/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php index 2f4b78a7cb..0b5a6ae540 100644 --- a/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php index e80ccd45ad..ae61dd73b1 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php @@ -22,7 +22,7 @@ use Symfony\Component\Security\Core\Exception\CookieTheftException; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Cookie; -use Symfony\Component\HttpKernel\Log\LoggerInterface; +use Psr\Log\LoggerInterface; /** * Base class implementing the RememberMeServicesInterface diff --git a/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php b/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php index 5f312731ac..8ad4c55a94 100644 --- a/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php +++ b/src/Symfony/Component/Security/Tests/Http/Firewall/RememberMeListenerTest.php @@ -177,7 +177,7 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase protected function getLogger() { - return $this->getMock('Symfony\Component\HttpKernel\Log\LoggerInterface'); + return $this->getMock('Psr\Log\LoggerInterface'); } protected function getManager() diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json index 73e07b513e..7192d57202 100644 --- a/src/Symfony/Component/Security/composer.json +++ b/src/Symfony/Component/Security/composer.json @@ -26,7 +26,8 @@ "symfony/routing": "2.2.*", "symfony/validator": "2.2.*", "doctrine/common": ">=2.2,<2.4-dev", - "doctrine/dbal": ">=2.2,<2.4-dev" + "doctrine/dbal": ">=2.2,<2.4-dev", + "psr/log": "~1.0" }, "suggest": { "symfony/class-loader": "2.2.*", From 16b342607c543e30d49b90e2418348344f5f8bbb Mon Sep 17 00:00:00 2001 From: Lee McDermott Date: Wed, 9 Jan 2013 10:34:35 +0000 Subject: [PATCH 057/128] Show PHP SAPI in WDT --- .../Resources/views/Collector/config.html.twig | 4 ++++ .../HttpKernel/DataCollector/ConfigDataCollector.php | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig index bbb6fa0365..dc4eb861b9 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig @@ -35,6 +35,10 @@ xdebug accel
+
+ PHP SAPI + {{ collector.sapiName }} +
{% endspaceless %} {% endset %} {% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': false } %} diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php index cfaa0b7277..3cd17b12cf 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php @@ -54,6 +54,7 @@ class ConfigDataCollector extends DataCollector 'xcache_enabled' => extension_loaded('xcache') && ini_get('xcache.cacher'), 'wincache_enabled' => extension_loaded('wincache') && ini_get('wincache.ocenabled'), 'bundles' => array(), + 'sapi_name' => php_sapi_name() ); if (isset($this->kernel)) { @@ -188,6 +189,16 @@ class ConfigDataCollector extends DataCollector return $this->data['bundles']; } + /** + * Gets the PHP SAPI name. + * + * @return string The environment + */ + public function getSapiName() + { + return $this->data['sapi_name']; + } + /** * {@inheritdoc} */ From 9aaceb19eebef484ba954bd67965276babf0a9e6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 19 Dec 2012 08:54:53 +0100 Subject: [PATCH 058/128] moved the logic from HttpKernel in FrameworkBundle to the HttpKernel component --- .../Twig/Extension/HttpKernelExtension.php | 61 +++------ .../Extension/HttpKernelExtensionTest.php | 23 ++-- .../Compiler/HttpRenderingStrategyPass.php | 37 ++++++ .../FrameworkExtension.php | 1 + .../FrameworkBundle/FrameworkBundle.php | 2 + .../Bundle/FrameworkBundle/HttpKernel.php | 94 +------------ .../Resources/config/content_generator.xml | 48 +++++++ .../Resources/config/routing/proxy.xml | 8 ++ .../Resources/config/templating_php.xml | 2 +- .../Templating/Helper/ActionsHelper.php | 20 ++- .../TwigBundle/Resources/config/twig.xml | 3 +- .../Component/HttpFoundation/Request.php | 10 ++ .../Controller/ControllerReference.php | 31 +++++ .../EventListener/RouterProxyListener.php | 78 +++++++++++ .../HttpKernel/HttpContentRenderer.php | 124 ++++++++++++++++++ .../DefaultRenderingStrategy.php | 101 ++++++++++++++ .../EsiRenderingStrategy.php | 66 ++++++++++ .../GeneratorAwareRenderingStrategy.php | 75 +++++++++++ .../HIncludeRenderingStrategy.php | 96 ++++++++++++++ .../RenderingStrategyInterface.php | 38 ++++++ 20 files changed, 760 insertions(+), 158 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/proxy.xml create mode 100644 src/Symfony/Component/HttpKernel/Controller/ControllerReference.php create mode 100644 src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php create mode 100644 src/Symfony/Component/HttpKernel/HttpContentRenderer.php create mode 100644 src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php create mode 100644 src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php create mode 100644 src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php create mode 100644 src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php create mode 100644 src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php index bdf882ef4a..a9bfaac44e 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php @@ -11,83 +11,54 @@ namespace Symfony\Bridge\Twig\Extension; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\HttpContentRenderer; +use Symfony\Component\HttpKernel\Controller\ControllerReference; /** * Provides integration with the HttpKernel component. * * @author Fabien Potencier */ -class HttpKernelExtension extends \Twig_Extension implements EventSubscriberInterface +class HttpKernelExtension extends \Twig_Extension { - private $kernel; - private $request; + private $renderer; /** * Constructor. * - * @param HttpKernelInterface $kernel A HttpKernelInterface install + * @param HttpContentRenderer $kernel A HttpContentRenderer instance */ - public function __construct(HttpKernelInterface $kernel) + public function __construct(HttpContentRenderer $renderer) { - $this->kernel = $kernel; + $this->renderer = $renderer; } public function getFunctions() { return array( - 'render' => new \Twig_Function_Method($this, 'render', array('needs_environment' => true, 'is_safe' => array('html'))), + 'render' => new \Twig_Function_Method($this, 'render', array('is_safe' => array('html'))), + 'controller' => new \Twig_Function_Method($this, 'controller'), ); } /** * Renders a URI. * - * @param \Twig_Environment $twig A \Twig_Environment instance - * @param string $uri The URI to render + * @param string $uri A URI + * @param array $options An array of options * * @return string The Response content * - * @throws \RuntimeException + * @see Symfony\Component\HttpKernel\HttpContentRenderer::render() */ - public function render(\Twig_Environment $twig, $uri) + public function render($uri, $options = array()) { - if (null !== $this->request) { - $cookies = $this->request->cookies->all(); - $server = $this->request->server->all(); - } else { - $cookies = array(); - $server = array(); - } - - $subRequest = Request::create($uri, 'get', array(), $cookies, array(), $server); - if (null !== $this->request && $this->request->getSession()) { - $subRequest->setSession($this->request->getSession()); - } - - $response = $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false); - - if (!$response->isSuccessful()) { - throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $subRequest->getUri(), $response->getStatusCode())); - } - - return $response->getContent(); + return $this->renderer->render($uri, $options); } - public function onKernelRequest(GetResponseEvent $event) + public function controller($controller, $attributes = array(), $query = array()) { - $this->request = $event->getRequest(); - } - - public static function getSubscribedEvents() - { - return array( - KernelEvents::REQUEST => array('onKernelRequest'), - ); + return new ControllerReference($controller, $attributes, $query); } public function getName() diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php index f5390d31be..dd6030ea54 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -14,7 +14,7 @@ namespace Symfony\Bridge\Twig\Tests\Extension; use Symfony\Bridge\Twig\Extension\HttpKernelExtension; use Symfony\Bridge\Twig\Tests\TestCase; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\HttpContentRenderer; class HttpKernelExtensionTest extends TestCase { @@ -31,7 +31,7 @@ class HttpKernelExtensionTest extends TestCase public function testRenderWithoutMasterRequest() { - $kernel = $this->getKernel($this->returnValue(new Response('foo'))); + $kernel = $this->getHttpContentRenderer($this->returnValue('foo')); $this->assertEquals('foo', $this->renderTemplate($kernel)); } @@ -41,7 +41,7 @@ class HttpKernelExtensionTest extends TestCase */ public function testRenderWithError() { - $kernel = $this->getKernel($this->throwException(new \Exception('foo'))); + $kernel = $this->getHttpContentRenderer($this->throwException(new \Exception('foo'))); $loader = new \Twig_Loader_Array(array('index' => '{{ render("foo") }}')); $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); @@ -50,23 +50,20 @@ class HttpKernelExtensionTest extends TestCase $this->renderTemplate($kernel); } - protected function getKernel($return) + protected function getHttpContentRenderer($return) { - $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); - $kernel - ->expects($this->once()) - ->method('handle') - ->will($return) - ; + $strategy = $this->getMock('Symfony\\Component\\HttpKernel\\RenderingStrategy\\RenderingStrategyInterface'); + $strategy->expects($this->once())->method('getName')->will($this->returnValue('default')); + $strategy->expects($this->once())->method('render')->will($return); - return $kernel; + return new HttpContentRenderer(array($strategy)); } - protected function renderTemplate(HttpKernelInterface $kernel, $template = '{{ render("foo") }}') + protected function renderTemplate(HttpContentRenderer $renderer, $template = '{{ render("foo") }}') { $loader = new \Twig_Loader_Array(array('index' => $template)); $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); - $twig->addExtension(new HttpKernelExtension($kernel)); + $twig->addExtension(new HttpKernelExtension($renderer)); return $twig->render('index'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php new file mode 100644 index 0000000000..3d31def579 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Exception\LogicException; + +/** + * Adds services tagged kernel.content_renderer_strategy as HTTP content rendering strategies. + * + * @author Fabien Potencier + */ +class HttpRenderingStrategyPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (false === $container->hasDefinition('http_content_renderer')) { + return; + } + + $definition = $container->getDefinition('http_content_renderer'); + foreach (array_keys($container->findTaggedServiceIds('kernel.content_renderer_strategy')) as $id) { + $definition->addMethodCall('addStrategy', array(new Reference($id))); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index baeb0abba8..3de40ec1fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -41,6 +41,7 @@ class FrameworkExtension extends Extension $loader->load('web.xml'); $loader->load('services.xml'); + $loader->load('content_generator.xml'); // A translator must always be registered (as support is included by // default in the Form component). If disabled, an identity translator diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index aec13c4aab..3f18da7892 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -25,6 +25,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilder use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CompilerDebugDumpPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationExtractorPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\HttpRenderingStrategyPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\Scope; @@ -65,6 +66,7 @@ class FrameworkBundle extends Bundle $container->addCompilerPass(new AddCacheClearerPass()); $container->addCompilerPass(new TranslationExtractorPass()); $container->addCompilerPass(new TranslationDumperPass()); + $container->addCompilerPass(new HttpRenderingStrategyPass()); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php index 4f2d2a19ec..12dc5e80ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php @@ -30,8 +30,6 @@ class HttpKernel extends BaseHttpKernel { protected $container; - private $esiSupport; - public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver) { parent::__construct($dispatcher, $controllerResolver); @@ -96,97 +94,13 @@ class HttpKernel extends BaseHttpKernel * * @throws \RuntimeException * @throws \Exception + * + * @deprecated in 2.2, will be removed in 2.3 (use Symfony\Component\HttpKernel\HttpContentRenderer::render() instead) */ public function render($uri, array $options = array()) { - $request = $this->container->get('request'); + trigger_error('render() is deprecated since version 2.2 and will be removed in 2.3. Use Symfony\Component\HttpKernel\HttpContentRenderer::render() instead.', E_USER_DEPRECATED); - $options = array_merge(array( - 'ignore_errors' => !$this->container->getParameter('kernel.debug'), - 'alt' => null, - 'standalone' => false, - 'comment' => '', - 'default' => null, - ), $options); - - if (null === $this->esiSupport) { - $this->esiSupport = $this->container->has('esi') && $this->container->get('esi')->hasSurrogateEsiCapability($request); - } - - if ($this->esiSupport && (true === $options['standalone'] || 'esi' === $options['standalone'])) { - return $this->container->get('esi')->renderIncludeTag($uri, $options['alt'], $options['ignore_errors'], $options['comment']); - } - - if ('js' === $options['standalone']) { - $defaultContent = null; - - $templating = $this->container->get('templating'); - - if ($options['default']) { - if ($templating->exists($options['default'])) { - $defaultContent = $templating->render($options['default']); - } else { - $defaultContent = $options['default']; - } - } elseif ($template = $this->container->getParameter('templating.hinclude.default_template')) { - $defaultContent = $templating->render($template); - } - - return $this->renderHIncludeTag($uri, $defaultContent); - } - - $subRequest = Request::create($uri, 'get', array(), $request->cookies->all(), array(), $request->server->all()); - if ($session = $request->getSession()) { - $subRequest->setSession($session); - } - - $level = ob_get_level(); - try { - $response = $this->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false); - - if (!$response->isSuccessful()) { - throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode())); - } - - if (!$response instanceof StreamedResponse) { - return $response->getContent(); - } - - $response->sendContent(); - } catch (\Exception $e) { - if ($options['alt']) { - $alt = $options['alt']; - unset($options['alt']); - - return $this->render($alt, $options); - } - - if (!$options['ignore_errors']) { - throw $e; - } - - // let's clean up the output buffers that were created by the sub-request - while (ob_get_level() > $level) { - ob_get_clean(); - } - } - } - - /** - * Renders an HInclude tag. - * - * @param string $uri A URI - * @param string $defaultContent Default content - * - * @return string - */ - public function renderHIncludeTag($uri, $defaultContent = null) - { - return sprintf('%s', $uri, $defaultContent); - } - - public function hasEsiSupport() - { - return $this->esiSupport; + $this->container->get('http_content_renderer')->render($uri, $options); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml new file mode 100644 index 0000000000..bb381281e6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml @@ -0,0 +1,48 @@ + + + + + + Symfony\Component\HttpKernel\HttpContentRenderer + Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy + Symfony\Component\HttpKernel\RenderingStrategy\EsiRenderingStrategy + Symfony\Component\HttpKernel\RenderingStrategy\HIncludeRenderingStrategy + + Symfony\Component\HttpKernel\EventListener\RouterProxyListener + + + + + + + %kernel.debug% + + + + + + + + + + + + + + + + + + + %http_content_renderer.strategy.hinclude.global_template% + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/proxy.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/proxy.xml new file mode 100644 index 0000000000..21ca146126 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/proxy.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml index ea1795455f..f93c7c7db4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml @@ -81,7 +81,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php index a4fdc3510e..cc5f486fa1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php @@ -12,7 +12,8 @@ namespace Symfony\Bundle\FrameworkBundle\Templating\Helper; use Symfony\Component\Templating\Helper\Helper; -use Symfony\Bundle\FrameworkBundle\HttpKernel; +use Symfony\Component\HttpKernel\HttpContentRenderer; +use Symfony\Component\HttpKernel\Controller\ControllerReference; /** * ActionsHelper manages action inclusions. @@ -21,16 +22,16 @@ use Symfony\Bundle\FrameworkBundle\HttpKernel; */ class ActionsHelper extends Helper { - protected $kernel; + private $renderer; /** * Constructor. * - * @param HttpKernel $kernel A HttpKernel instance + * @param HttpContentRenderer $kernel A HttpContentRenderer instance */ - public function __construct(HttpKernel $kernel) + public function __construct(HttpContentRenderer $renderer) { - $this->kernel = $kernel; + $this->renderer = $renderer; } /** @@ -41,11 +42,16 @@ class ActionsHelper extends Helper * * @return string * - * @see Symfony\Bundle\FrameworkBundle\HttpKernel::render() + * @see Symfony\Component\HttpKernel\HttpContentRenderer::render() */ public function render($uri, array $options = array()) { - return $this->kernel->render($uri, $options); + return $this->renderer->render($uri, $options); + } + + public function controller($controller, $attributes = array(), $query = array()) + { + return new ControllerReference($controller, $attributes, $query); } /** diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index c12c0898b1..2a106d6c3b 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -90,8 +90,7 @@ - - + diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 5ec5fd3510..9a647c43fc 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -486,6 +486,16 @@ class Request self::$trustProxy = $proxies ? true : false; } + /** + * Gets the list of trusted proxies. + * + * @return array An array of trusted proxies. + */ + public static function getTrustedProxies() + { + return self::$trustedProxies; + } + /** * Sets the name for trusted headers. * diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerReference.php b/src/Symfony/Component/HttpKernel/Controller/ControllerReference.php new file mode 100644 index 0000000000..90ac2ba41a --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerReference.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Controller; + +/** + * ControllerReference. + * + * @author Fabien Potencier + */ +class ControllerReference +{ + public $controller; + public $attributes = array(); + public $query = array(); + + public function __construct($controller, array $attributes = array(), array $query = array()) + { + $this->controller = $controller; + $this->attributes = $attributes; + $this->query = $query; + } +} diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php new file mode 100644 index 0000000000..bb471ae28b --- /dev/null +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\IpUtils; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Proxies URIs when the current route name is "_proxy". + * + * If the request does not come from a trusted, it throws an + * AccessDeniedHttpException exception. + * + * @author Fabien Potencier + */ +class RouterProxyListener implements EventSubscriberInterface +{ + /** + * Fixes request attributes when the route is '_proxy'. + * + * @param GetResponseEvent $event A GetResponseEvent instance + * + * @throws AccessDeniedHttpException if the request does not come from a trusted IP. + */ + public function onKernelRequest(GetResponseEvent $event) + { + $request = $event->getRequest(); + + if ('_proxy' !== $request->attributes->get('_route')) { + return; + } + + $this->checkRequest($request); + + parse_str($request->query->get('path', ''), $attributes); + $request->attributes->add($attributes); + $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params'), $attributes)); + $request->query->remove('path'); + } + + protected function checkRequest(Request $request) + { + $trustedIps = array_merge($this->getLocalIpAddresses(), $request->getTrustedProxies()); + $remoteAddress = $request->server->get('REMOTE_ADDR'); + foreach ($trustedIps as $ip) { + if (IpUtils::checkIp($remoteAddress, $ip)) { + return; + } + } + + throw new AccessDeniedHttpException(); + } + + protected function getLocalIpAddresses() + { + return array('127.0.0.1', 'fe80::1', '::1'); + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => array(array('onKernelRequest', 16)), + ); + } +} diff --git a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php new file mode 100644 index 0000000000..b62e0491c3 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * + * @author Fabien Potencier + */ +class HttpContentRenderer implements EventSubscriberInterface +{ + private $debug; + private $strategies; + private $requests; + + public function __construct(array $strategies = array(), $debug = false) + { + $this->strategies = array(); + foreach ($strategies as $strategy) { + $this->addStrategy($strategy); + } + $this->debug = $debug; + $this->requests = array(); + } + + public function addStrategy(RenderingStrategyInterface $strategy) + { + $this->strategies[$strategy->getName()] = $strategy; + } + + /** + * Stores the Request object. + * + * @param GetResponseEvent $event A GetResponseEvent instance + */ + public function onKernelRequest(GetResponseEvent $event) + { + array_unshift($this->requests, $event->getRequest()); + } + + /** + * Removes the most recent Request object. + * + * @param FilterResponseEvent $event A FilterResponseEvent instance + */ + public function onKernelResponse(FilterResponseEvent $event) + { + array_shift($this->requests); + } + + /** + * Renders a URI and returns the Response content. + * + * * ignore_errors: true to return an empty string in case of an error + * * strategy: the strategy to use for rendering + * + * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance + * @param array $options An array of options + * + * @return string The Response content + */ + public function render($uri, array $options = array()) + { + if (!isset($options['ignore_errors'])) { + $options['ignore_errors'] = !$this->debug; + } + + $options = $this->fixOptions($options); + + $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; + + if (!isset($this->strategies[$strategy])) { + throw new \InvalidArgumentException(sprintf('The "%s" rendering strategy does not exist.', $strategy)); + } + + return $this->strategies[$strategy]->render($uri, $this->requests ? $this->requests[0] : null, $options); + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => 'onKernelRequest', + KernelEvents::RESPONSE => 'onKernelResponse', + ); + } + + private function fixOptions($options) + { + // support for the standalone option is @deprecated in 2.2 and replaced with the strategy option + if (isset($options['standalone'])) { + trigger_error('The "standalone" option is deprecated in version 2.2 and replaced with the "strategy" option.', E_USER_DEPRECATED); + + // support for the true value is @deprecated in 2.2, will be removed in 2.3 + if (true === $options['standalone']) { + trigger_error('The "true" value for the "standalone" option is deprecated in version 2.2 and replaced with the "esi" value.', E_USER_DEPRECATED); + + $options['standalone'] = 'esi'; + } elseif ('js' === $options['standalone']) { + trigger_error('The "js" value for the "standalone" option is deprecated in version 2.2 and replaced with the "hinclude" value.', E_USER_DEPRECATED); + + $options['standalone'] = 'hinclude'; + } + + $options['strategy'] = $options['standalone']; + } + + return $options; + } +} diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php new file mode 100644 index 0000000000..1b6d252365 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\RenderingStrategy; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\Controller\ControllerReference; + +/** + * + * @author Fabien Potencier + */ +class DefaultRenderingStrategy extends GeneratorAwareRenderingStrategy +{ + private $kernel; + + public function __construct(HttpKernelInterface $kernel) + { + $this->kernel = $kernel; + } + + public function render($uri, Request $request = null, array $options = array()) + { + if ($uri instanceof ControllerReference) { + $uri = $this->generateProxyUri($uri, $request); + } + + $subRequest = $this->createSubRequest($uri, $request); + + $level = ob_get_level(); + try { + return $this->handle($subRequest); + } catch (\Exception $e) { + // let's clean up the output buffers that were created by the sub-request + while (ob_get_level() > $level) { + ob_get_clean(); + } + + if (isset($options['alt'])) { + $alt = $options['alt']; + unset($options['alt']); + + return $this->render($alt, $request, $options); + } + + if (!isset($options['ignore_errors']) || !$options['ignore_errors']) { + throw $e; + } + } + } + + protected function handle(Request $request) + { + $response = $this->kernel->handle($request, HttpKernelInterface::SUB_REQUEST, false); + + if (!$response->isSuccessful()) { + throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode())); + } + + if (!$response instanceof StreamedResponse) { + return $response->getContent(); + } + + $response->sendContent(); + } + + protected function createSubRequest($uri, Request $request = null) + { + if (null !== $request) { + $cookies = $request->cookies->all(); + $server = $request->server->all(); + + // the sub-request is internal + $server['REMOTE_ADDR'] = '127.0.0.1'; + } else { + $cookies = array(); + $server = array(); + } + + $subRequest = Request::create($uri, 'get', array(), $cookies, array(), $server); + if (null !== $request && $session = $request->getSession()) { + $subRequest->setSession($session); + } + + return $subRequest; + } + + public function getName() + { + return 'default'; + } +} diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php new file mode 100644 index 0000000000..be9bdb9351 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\RenderingStrategy; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\HttpCache\Esi; + +/** + * + * @author Fabien Potencier + */ +class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy +{ + private $esi; + private $defaultStrategy; + + public function __construct(Esi $esi, RenderingStrategyInterface $defaultStrategy) + { + $this->esi = $esi; + $this->defaultStrategy = $defaultStrategy; + } + + /** + * + * Note that this method generates an esi:include tag only when both the standalone + * option is set to true and the request has ESI capability (@see Symfony\Component\HttpKernel\HttpCache\ESI). + * + * Available options: + * + * * ignore_errors: true to return an empty string in case of an error + * * alt: an alternative URI to execute in case of an error + * * comment: a comment to add when returning an esi:include tag + */ + public function render($uri, Request $request = null, array $options = array()) + { + if (!$this->esi->hasSurrogateEsiCapability($request)) { + return $this->defaultStrategy->render($uri, $request, $options); + } + + if ($uri instanceof ControllerReference) { + $uri = $this->generateProxyUri($uri, $request); + } + + $alt = isset($options['alt']) ? $options['alt'] : null; + if ($alt instanceof ControllerReference) { + $alt = $this->generateProxyUri($alt, $request); + } + + return $this->esi->renderIncludeTag($uri, $alt, $options['ignore_errors'], isset($options['comment']) ? $options['comment'] : ''); + } + + public function getName() + { + return 'esi'; + } +} diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php new file mode 100644 index 0000000000..7b5ecb5295 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\RenderingStrategy; + +use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Routing\Exception\RouteNotFoundException; + +/** + * + * @author Fabien Potencier + */ +abstract class GeneratorAwareRenderingStrategy implements RenderingStrategyInterface +{ + protected $generator; + + public function setUrlGenerator(UrlGeneratorInterface $generator) + { + $this->generator = $generator; + } + + /** + * Generates a proxy URI for a given controller. + * + * This method only works when using the Symfony Routing component and + * if a "_proxy" route is defined with a {_controller} and {_format} + * placeholders. + * + * @param ControllerReference $reference A ControllerReference instance + * @param Request $request A Request instance + * + * @return string A proxy URI + */ + protected function generateProxyUri(ControllerReference $reference, Request $request = null) + { + if (null === $this->generator) { + throw new \LogicException('Unable to generate a proxy URL as there is no registered route generator.'); + } + + if (isset($reference->attributes['_format'])) { + $format = $reference->attributes['_format']; + unset($reference->attributes['_format']); + } elseif (null !== $request) { + $format = $request->getRequestFormat(); + } else { + $format = 'html'; + } + + try { + $uri = $this->generator->generate('_proxy', array('_controller' => $reference->controller, '_format' => $format), true); + } catch (RouteNotFoundException $e) { + throw new \LogicException('Unable to generate a proxy URL as the "_proxy" route is not registered.', 0, $e); + } + + if ($path = http_build_query($reference->attributes, '', '&')) { + $reference->query['path'] = $path; + } + + if ($qs = http_build_query($reference->query, '', '&')) { + $uri .= '?'.$qs; + } + + return $uri; + } +} diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php new file mode 100644 index 0000000000..ec1cbc2e29 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\RenderingStrategy; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Templating\EngineInterface; +use Symfony\Component\HttpKernel\Controller\ControllerReference; + +/** + * + * @author Fabien Potencier + */ +class HIncludeRenderingStrategy implements RenderingStrategyInterface +{ + private $templating; + private $globalDefaultTemplate; + + public function __construct($templating, $globalDefaultTemplate = null) + { + if (!$templating instanceof EngineInterface && !$templating instanceof \Twig_Environment) { + throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of \Twig_Environment or Symfony\Component\Templating\EngineInterface'); + } + + $this->templating = $templating; + $this->globalDefaultTemplate = $globalDefaultTemplate; + } + + public function render($uri, Request $request = null, array $options = array()) + { + if ($uri instanceof ControllerReference) { + // FIXME: can we sign the proxy URL instead? + throw new \LogicException('You must use a proper URI when using the Hinclude rendering strategy.'); + } + + $defaultTemplate = $options['default'] ?: null; + $defaultContent = null; + + if (null !== $defaultTemplate) { + if ($this->templateExists($defaultTemplate)) { + $defaultContent = $this->templating->render($defaultContent); + } else { + $defaultContent = $defaultTemplate; + } + } elseif ($this->globalDefaultTemplate) { + $defaultContent = $this->templating->render($this->globalDefaultTemplate); + } + + return $this->renderHIncludeTag($uri, $defaultContent); + } + + /** + * Renders an HInclude tag. + * + * @param string $uri A URI + * @param string $defaultContent Default content + */ + protected function renderHIncludeTag($uri, $defaultContent = null) + { + return sprintf('%s', $uri, $defaultContent); + } + + private function templateExists($template) + { + if ($this->templating instanceof EngineInterface) { + return $this->templating->exists($template); + } + + $loader = $this->templating->getLoader(); + if ($loader instanceof \Twig_ExistsLoaderInterface) { + return $loader->exists($template); + } + + try { + $loader->getSource($template); + + return true; + } catch (\Twig_Error_Loader $e) { + } + + return false; + } + + public function getName() + { + return 'hinclude'; + } +} diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php new file mode 100644 index 0000000000..e386751448 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\RenderingStrategy; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ControllerReference; + +/** + * + * @author Fabien Potencier + */ +interface RenderingStrategyInterface +{ + /** + * Renders a URI and returns the Response content. + * + * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance + * @param Request $request A Request instance + * @param array $options An array of options + */ + public function render($uri, Request $request = null, array $options = array()); + + /** + * Gets the name of the strategy. + * + * @return string The strategy name + */ + public function getName(); +} From a0c49c3a94e8b5efa1e73eeda147ed1b1d8b06eb Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 3 Jan 2013 18:51:16 +0100 Subject: [PATCH 059/128] [TwigBridge] added a render_* function to ease usage of custom rendering strategies Here is the code you need to write when using the regular render function for an ESI strategy: {{ render(path('path'), { strategy: 'esi' }) }} And the same with the new render_* function: {{ render_esi(path('path')) }} --- src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php index a9bfaac44e..14d5a5c8ad 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php @@ -37,6 +37,7 @@ class HttpKernelExtension extends \Twig_Extension { return array( 'render' => new \Twig_Function_Method($this, 'render', array('is_safe' => array('html'))), + 'render_*' => new \Twig_Function_Method($this, 'renderStrategy', array('is_safe' => array('html'))), 'controller' => new \Twig_Function_Method($this, 'controller'), ); } @@ -56,6 +57,13 @@ class HttpKernelExtension extends \Twig_Extension return $this->renderer->render($uri, $options); } + public function renderStrategy($strategy, $uri, $options = array()) + { + $options['strategy'] = $strategy; + + return $this->renderer->render($uri, $options); + } + public function controller($controller, $attributes = array(), $query = array()) { return new ControllerReference($controller, $attributes, $query); From 892f00ffeeb1e392e0fb0373dfd94b8abd3f194e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 3 Jan 2013 19:22:22 +0100 Subject: [PATCH 060/128] [HttpKernel] added a URL signer mechanism for hincludes --- .../Resources/config/content_generator.xml | 3 + .../Resources/config/services.xml | 5 ++ .../EventListener/RouterProxyListener.php | 23 +++++- .../HIncludeRenderingStrategy.php | 16 +++-- .../Component/HttpKernel/UriSigner.php | 72 +++++++++++++++++++ 5 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 src/Symfony/Component/HttpKernel/UriSigner.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml index bb381281e6..7dd51b127f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml @@ -36,12 +36,15 @@ + %http_content_renderer.strategy.hinclude.global_template% + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index 36f01f09e4..fbddc0e07f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -11,6 +11,7 @@ Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer Symfony\Component\HttpKernel\Config\FileLocator + Symfony\Component\HttpKernel\UriSigner @@ -51,5 +52,9 @@ %kernel.root_dir%/Resources + + + %kernel.secret% + diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php index bb471ae28b..ff339dc020 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\IpUtils; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\UriSigner; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -28,6 +29,13 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; */ class RouterProxyListener implements EventSubscriberInterface { + private $signer; + + public function __construct(UriSigner $signer) + { + $this->signer = $signer; + } + /** * Fixes request attributes when the route is '_proxy'. * @@ -43,7 +51,7 @@ class RouterProxyListener implements EventSubscriberInterface return; } - $this->checkRequest($request); + $this->validateRequest($request); parse_str($request->query->get('path', ''), $attributes); $request->attributes->add($attributes); @@ -51,8 +59,14 @@ class RouterProxyListener implements EventSubscriberInterface $request->query->remove('path'); } - protected function checkRequest(Request $request) + protected function validateRequest(Request $request) { + // is the Request safe? + if (!$request->isMethodSafe()) { + throw new AccessDeniedHttpException(); + } + + // does the Request come from a trusted IP? $trustedIps = array_merge($this->getLocalIpAddresses(), $request->getTrustedProxies()); $remoteAddress = $request->server->get('REMOTE_ADDR'); foreach ($trustedIps as $ip) { @@ -61,6 +75,11 @@ class RouterProxyListener implements EventSubscriberInterface } } + // is the Request signed? + if ($this->signer->check($request->getUri())) { + return; + } + throw new AccessDeniedHttpException(); } diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php index ec1cbc2e29..b91a3b8800 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php @@ -14,17 +14,19 @@ namespace Symfony\Component\HttpKernel\RenderingStrategy; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Templating\EngineInterface; use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\UriSigner; /** * * @author Fabien Potencier */ -class HIncludeRenderingStrategy implements RenderingStrategyInterface +class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy { private $templating; private $globalDefaultTemplate; + private $signer; - public function __construct($templating, $globalDefaultTemplate = null) + public function __construct($templating, UriSigner $signer = null, $globalDefaultTemplate = null) { if (!$templating instanceof EngineInterface && !$templating instanceof \Twig_Environment) { throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of \Twig_Environment or Symfony\Component\Templating\EngineInterface'); @@ -32,16 +34,20 @@ class HIncludeRenderingStrategy implements RenderingStrategyInterface $this->templating = $templating; $this->globalDefaultTemplate = $globalDefaultTemplate; + $this->signer = $signer; } public function render($uri, Request $request = null, array $options = array()) { if ($uri instanceof ControllerReference) { - // FIXME: can we sign the proxy URL instead? - throw new \LogicException('You must use a proper URI when using the Hinclude rendering strategy.'); + if (null === $this->signer) { + throw new \LogicException('You must use a proper URI when using the Hinclude rendering strategy or set a URL signer.'); + } + + $uri = $this->signer->sign($this->generateProxyUri($uri, $request)); } - $defaultTemplate = $options['default'] ?: null; + $defaultTemplate = isset($options['default']) ? $options['default'] : null; $defaultContent = null; if (null !== $defaultTemplate) { diff --git a/src/Symfony/Component/HttpKernel/UriSigner.php b/src/Symfony/Component/HttpKernel/UriSigner.php new file mode 100644 index 0000000000..2ff6b9b2aa --- /dev/null +++ b/src/Symfony/Component/HttpKernel/UriSigner.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +/** + * UriSigner. + * + * @author Fabien Potencier + */ +class UriSigner +{ + private $secret; + + /** + * Constructor. + * + * @param string $secret A secret + */ + public function __construct($secret) + { + $this->secret = $secret; + } + + /** + * Signs a URI. + * + * The given URI is signed by adding a _hash query string parameter + * which value depends on the URI and the secret. + * + * @param string $uri A URI to sign + * + * @return string The signed URI + */ + public function sign($uri) + { + return $uri.(false === (strpos($uri, '?')) ? '?' : '&').'_hash='.$this->computeHash($uri); + } + + /** + * Checks that a URI contains the correct hash. + * + * @param string $uri A signed URI + * + * @return Boolean True if the URI is signed correctly, false otherwise + */ + public function check($uri) + { + if (!preg_match('/(\?|&)_hash=(.+?)(&|$)/', $uri, $matches, PREG_OFFSET_CAPTURE)) { + return false; + } + + // the naked URI is the URI without the _hash parameter (we need to keep the ? if there is some other parameters after) + $offset = ('?' == $matches[1][0] && '&' != $matches[3][0]) ? 0 : 1; + $nakedUri = substr($uri, 0, $matches[0][1] + $offset).substr($uri, $matches[0][1] + strlen($matches[0][0])); + + return $this->computeHash($nakedUri) === $matches[2][0]; + } + + private function computeHash($uri) + { + return urlencode(base64_encode(hash_hmac('sha1', $uri, $this->secret, true))); + } +} From 403bb060ce45cc48df9b0ff299ba8f2aa53de21a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 4 Jan 2013 18:38:08 +0100 Subject: [PATCH 061/128] [HttpKernel] added missing phpdoc and tweaked existing ones --- .../Controller/ControllerReference.php | 16 +++++++++++- .../EventListener/RouterProxyListener.php | 2 +- .../HttpKernel/HttpContentRenderer.php | 18 ++++++++++++- .../DefaultRenderingStrategy.php | 12 +++++++++ .../EsiRenderingStrategy.php | 26 +++++++++++++++---- .../GeneratorAwareRenderingStrategy.php | 6 +++++ .../HIncludeRenderingStrategy.php | 14 ++++++++++ .../RenderingStrategyInterface.php | 8 ++++++ .../Component/HttpKernel/UriSigner.php | 2 +- 9 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Controller/ControllerReference.php b/src/Symfony/Component/HttpKernel/Controller/ControllerReference.php index 90ac2ba41a..905e89f5dc 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ControllerReference.php +++ b/src/Symfony/Component/HttpKernel/Controller/ControllerReference.php @@ -12,9 +12,16 @@ namespace Symfony\Component\HttpKernel\Controller; /** - * ControllerReference. + * Acts as a marker and a data holder for a Controller. + * + * Some methods in Symfony accept both a URI (as a string) or a controller as + * an argument. In the latter case, instead of passing an array representing + * the controller, you can use an instance of this class. * * @author Fabien Potencier + * + * @see Symfony\Component\HttpKernel\HttpContentRenderer + * @see Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface */ class ControllerReference { @@ -22,6 +29,13 @@ class ControllerReference public $attributes = array(); public $query = array(); + /** + * Constructor. + * + * @param string $controller The controller name + * @param array $attributes An array of parameters to add to the Request attributes + * @param array $query An array of parameters to add to the Request query string + */ public function __construct($controller, array $attributes = array(), array $query = array()) { $this->controller = $controller; diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php index ff339dc020..05e8717fc0 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php @@ -22,7 +22,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Proxies URIs when the current route name is "_proxy". * - * If the request does not come from a trusted, it throws an + * If the request does not come from a trusted IP, it throws an * AccessDeniedHttpException exception. * * @author Fabien Potencier diff --git a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php index b62e0491c3..5344917ee1 100644 --- a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php +++ b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php @@ -19,6 +19,7 @@ use Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** + * Renders a URI using different strategies. * * @author Fabien Potencier */ @@ -28,6 +29,12 @@ class HttpContentRenderer implements EventSubscriberInterface private $strategies; private $requests; + /** + * Constructor. + * + * @param RenderingStrategyInterface[] $strategies An array of RenderingStrategyInterface instances + * @param Boolean $debug Whether the debug mode is enabled or not + */ public function __construct(array $strategies = array(), $debug = false) { $this->strategies = array(); @@ -38,6 +45,11 @@ class HttpContentRenderer implements EventSubscriberInterface $this->requests = array(); } + /** + * Adds a rendering strategy. + * + * @param RenderingStrategyInterface $strategy A RenderingStrategyInterface instance + */ public function addStrategy(RenderingStrategyInterface $strategy) { $this->strategies[$strategy->getName()] = $strategy; @@ -66,13 +78,16 @@ class HttpContentRenderer implements EventSubscriberInterface /** * Renders a URI and returns the Response content. * + * When the Response is a StreamedResponse, the content is streamed immediately + * instead of being returned. + * * * ignore_errors: true to return an empty string in case of an error * * strategy: the strategy to use for rendering * * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance * @param array $options An array of options * - * @return string The Response content + * @return string|null The Response content or null when the Response is streamed */ public function render($uri, array $options = array()) { @@ -99,6 +114,7 @@ class HttpContentRenderer implements EventSubscriberInterface ); } + // to be removed in 2.3 private function fixOptions($options) { // support for the standalone option is @deprecated in 2.2 and replaced with the strategy option diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php index 1b6d252365..5198c01ba9 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Controller\ControllerReference; /** + * Implements the default rendering strategy where the Request is rendered by the current HTTP kernel. * * @author Fabien Potencier */ @@ -23,11 +24,19 @@ class DefaultRenderingStrategy extends GeneratorAwareRenderingStrategy { private $kernel; + /** + * Constructor. + * + * @param HttpKernelInterface $kernel A HttpKernelInterface instance + */ public function __construct(HttpKernelInterface $kernel) { $this->kernel = $kernel; } + /** + * {@inheritdoc} + */ public function render($uri, Request $request = null, array $options = array()) { if ($uri instanceof ControllerReference) { @@ -94,6 +103,9 @@ class DefaultRenderingStrategy extends GeneratorAwareRenderingStrategy return $subRequest; } + /** + * {@inheritdoc} + */ public function getName() { return 'default'; diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php index be9bdb9351..cf9f572079 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\HttpCache\Esi; /** + * Implements the ESI rendering strategy. * * @author Fabien Potencier */ @@ -24,6 +25,16 @@ class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy private $esi; private $defaultStrategy; + /** + * Constructor. + * + * The "fallback" strategy when ESI is not available should always be an + * instance of DefaultRenderingStrategy (or a class you are using for the + * default strategy). + * + * @param Esi $esi An Esi instance + * @param RenderingStrategyInterface $defaultStrategy The default strategy to use when ESI is not supported + */ public function __construct(Esi $esi, RenderingStrategyInterface $defaultStrategy) { $this->esi = $esi; @@ -31,15 +42,17 @@ class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy } /** + * {@inheritdoc} * - * Note that this method generates an esi:include tag only when both the standalone - * option is set to true and the request has ESI capability (@see Symfony\Component\HttpKernel\HttpCache\ESI). + * Note that if the current Request has no ESI capability, this method + * falls back to use the default rendering strategy. * - * Available options: + * Additional available options: * - * * ignore_errors: true to return an empty string in case of an error - * * alt: an alternative URI to execute in case of an error + * * alt: an alternative URI to render in case of an error * * comment: a comment to add when returning an esi:include tag + * + * @see Symfony\Component\HttpKernel\HttpCache\ESI */ public function render($uri, Request $request = null, array $options = array()) { @@ -59,6 +72,9 @@ class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy return $this->esi->renderIncludeTag($uri, $alt, $options['ignore_errors'], isset($options['comment']) ? $options['comment'] : ''); } + /** + * {@inheritdoc} + */ public function getName() { return 'esi'; diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php index 7b5ecb5295..408d682326 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php @@ -17,6 +17,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Exception\RouteNotFoundException; /** + * Adds the possibility to generate a proxy URI for a given Controller. * * @author Fabien Potencier */ @@ -24,6 +25,11 @@ abstract class GeneratorAwareRenderingStrategy implements RenderingStrategyInter { protected $generator; + /** + * Sets a URL generator to use for proxy URIs generation. + * + * @param UrlGeneratorInterface $generator An UrlGeneratorInterface instance + */ public function setUrlGenerator(UrlGeneratorInterface $generator) { $this->generator = $generator; diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php index b91a3b8800..1a67cbe45c 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\UriSigner; /** + * Implements the Hinclude rendering strategy. * * @author Fabien Potencier */ @@ -26,6 +27,13 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy private $globalDefaultTemplate; private $signer; + /** + * Constructor. + * + * @param EngineInterface|\Twig_Environment $templating An EngineInterface or a \Twig_Environment instance + * @param UriSigner $signer A UriSigner instance + * @param string $globalDefaultTemplate The content of the global default template + */ public function __construct($templating, UriSigner $signer = null, $globalDefaultTemplate = null) { if (!$templating instanceof EngineInterface && !$templating instanceof \Twig_Environment) { @@ -37,6 +45,9 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy $this->signer = $signer; } + /** + * {@inheritdoc} + */ public function render($uri, Request $request = null, array $options = array()) { if ($uri instanceof ControllerReference) { @@ -95,6 +106,9 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy return false; } + /** + * {@inheritdoc} + */ public function getName() { return 'hinclude'; diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php index e386751448..36419c3792 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/RenderingStrategyInterface.php @@ -15,17 +15,25 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerReference; /** + * Interface implemented by all rendering strategies. * * @author Fabien Potencier + * + * @see Symfony\Component\HttpKernel\HttpContentRenderer */ interface RenderingStrategyInterface { /** * Renders a URI and returns the Response content. * + * When the Response is a StreamedResponse, the content is streamed immediately + * instead of being returned. + * * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance * @param Request $request A Request instance * @param array $options An array of options + * + * @return string|null The Response content or null when the Response is streamed */ public function render($uri, Request $request = null, array $options = array()); diff --git a/src/Symfony/Component/HttpKernel/UriSigner.php b/src/Symfony/Component/HttpKernel/UriSigner.php index 2ff6b9b2aa..3530c31a77 100644 --- a/src/Symfony/Component/HttpKernel/UriSigner.php +++ b/src/Symfony/Component/HttpKernel/UriSigner.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpKernel; /** - * UriSigner. + * Signs URIs. * * @author Fabien Potencier */ From 1f1392dc8bce232a3111a08e1627884d77c69901 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 4 Jan 2013 18:47:22 +0100 Subject: [PATCH 062/128] [HttpKernel] simplified and enhanced code managing the hinclude strategy --- .../HIncludeRenderingStrategy.php | 35 ++++++------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php index 1a67cbe45c..7a4b77fc2f 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php @@ -32,7 +32,7 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy * * @param EngineInterface|\Twig_Environment $templating An EngineInterface or a \Twig_Environment instance * @param UriSigner $signer A UriSigner instance - * @param string $globalDefaultTemplate The content of the global default template + * @param string $globalDefaultTemplate The global default content (it can be a template name or the content) */ public function __construct($templating, UriSigner $signer = null, $globalDefaultTemplate = null) { @@ -47,6 +47,10 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy /** * {@inheritdoc} + * + * Additional available options: + * + * * default: The default content (it can be a template name or the content) */ public function render($uri, Request $request = null, array $options = array()) { @@ -58,31 +62,14 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy $uri = $this->signer->sign($this->generateProxyUri($uri, $request)); } - $defaultTemplate = isset($options['default']) ? $options['default'] : null; - $defaultContent = null; - - if (null !== $defaultTemplate) { - if ($this->templateExists($defaultTemplate)) { - $defaultContent = $this->templating->render($defaultContent); - } else { - $defaultContent = $defaultTemplate; - } - } elseif ($this->globalDefaultTemplate) { - $defaultContent = $this->templating->render($this->globalDefaultTemplate); + $template = isset($options['default']) ? $options['default'] : $this->globalDefaultTemplate; + if ($this->templateExists($template)) { + $content = $this->templating->render($template); + } else { + $content = $template; } - return $this->renderHIncludeTag($uri, $defaultContent); - } - - /** - * Renders an HInclude tag. - * - * @param string $uri A URI - * @param string $defaultContent Default content - */ - protected function renderHIncludeTag($uri, $defaultContent = null) - { - return sprintf('%s', $uri, $defaultContent); + return sprintf('%s', $uri, $content); } private function templateExists($template) From adc067e9386a87f4987275ede03833b74922adeb Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Jan 2013 08:59:41 +0100 Subject: [PATCH 063/128] [FrameworkBundle] made some services private --- .../FrameworkBundle/Resources/config/content_generator.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml index 7dd51b127f..1e6dc5c6c1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml @@ -20,19 +20,20 @@ %kernel.debug% - + - + + From 1240690cacd5a9687ed988104cb33201864adf72 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Jan 2013 09:31:07 +0100 Subject: [PATCH 064/128] [HttpKernel] made the strategy a regular parameter in HttpContentRenderer::render() --- .../Twig/Extension/HttpKernelExtension.php | 9 +++++---- .../Bundle/FrameworkBundle/HttpKernel.php | 5 ++++- .../Templating/Helper/ActionsHelper.php | 5 ++++- .../HttpKernel/HttpContentRenderer.php | 17 ++++++++++------- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php index 14d5a5c8ad..22ded3d197 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php @@ -54,14 +54,15 @@ class HttpKernelExtension extends \Twig_Extension */ public function render($uri, $options = array()) { - return $this->renderer->render($uri, $options); + $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; + unset($options['strategy']); + + return $this->renderer->render($uri, $strategy, $options); } public function renderStrategy($strategy, $uri, $options = array()) { - $options['strategy'] = $strategy; - - return $this->renderer->render($uri, $options); + return $this->renderer->render($uri, $strategy, $options); } public function controller($controller, $attributes = array(), $query = array()) diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php index 12dc5e80ff..812784b737 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php @@ -101,6 +101,9 @@ class HttpKernel extends BaseHttpKernel { trigger_error('render() is deprecated since version 2.2 and will be removed in 2.3. Use Symfony\Component\HttpKernel\HttpContentRenderer::render() instead.', E_USER_DEPRECATED); - $this->container->get('http_content_renderer')->render($uri, $options); + $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; + unset($options['strategy']); + + $this->container->get('http_content_renderer')->render($uri, $strategy, $options); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php index cc5f486fa1..94c7698294 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php @@ -46,7 +46,10 @@ class ActionsHelper extends Helper */ public function render($uri, array $options = array()) { - return $this->renderer->render($uri, $options); + $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; + unset($options['strategy']); + + return $this->renderer->render($uri, $strategy, $options); } public function controller($controller, $attributes = array(), $query = array()) diff --git a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php index 5344917ee1..94e35bb15d 100644 --- a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php +++ b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php @@ -81,23 +81,26 @@ class HttpContentRenderer implements EventSubscriberInterface * When the Response is a StreamedResponse, the content is streamed immediately * instead of being returned. * - * * ignore_errors: true to return an empty string in case of an error - * * strategy: the strategy to use for rendering + * Available options: * - * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance - * @param array $options An array of options + * * ignore_errors: true to return an empty string in case of an error + * + * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance + * @param string $strategy The strategy to use for the rendering + * @param array $options An array of options * * @return string|null The Response content or null when the Response is streamed */ - public function render($uri, array $options = array()) + public function render($uri, $strategy = 'default', array $options = array()) { if (!isset($options['ignore_errors'])) { $options['ignore_errors'] = !$this->debug; } $options = $this->fixOptions($options); - - $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; + if (isset($options['strategy'])) { + $strategy = $options['strategy']; + } if (!isset($this->strategies[$strategy])) { throw new \InvalidArgumentException(sprintf('The "%s" rendering strategy does not exist.', $strategy)); From a8ea4e4b10fca40b6283f6a7ec29fb62062cf2bd Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Jan 2013 09:48:46 +0100 Subject: [PATCH 065/128] [FrameworkBundle] deprecated HttpKernel::forward() (it is only used once now and not part of any interface anyway) --- src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php | 5 ++++- src/Symfony/Bundle/FrameworkBundle/HttpKernel.php | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php index a19030e11b..0196058642 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php @@ -59,7 +59,10 @@ class Controller extends ContainerAware */ public function forward($controller, array $path = array(), array $query = array()) { - return $this->container->get('http_kernel')->forward($controller, $path, $query); + $path['_controller'] = $controller; + $subRequest = $this->container->get('request')->duplicate($query, null, $path); + + return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php index 812784b737..b67f0c640e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php @@ -65,9 +65,13 @@ class HttpKernel extends BaseHttpKernel * @param array $query An array of request query parameters * * @return Response A Response instance + * + * @deprecated in 2.2, will be removed in 2.3 */ public function forward($controller, array $attributes = array(), array $query = array()) { + trigger_error('forward() is deprecated since version 2.2 and will be removed in 2.3.', E_USER_DEPRECATED); + $attributes['_controller'] = $controller; $subRequest = $this->container->get('request')->duplicate($query, null, $attributes); From bd102c5eba3ba7c0d432ae11b248762f27ab94d6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Jan 2013 10:59:36 +0100 Subject: [PATCH 066/128] made the content renderer work even when ESI is disabled or when no templating engine is available (the latter being mostly useful when testing) --- .../Resources/config/content_generator.xml | 10 +--------- .../Bundle/FrameworkBundle/Resources/config/esi.xml | 8 ++++++++ .../RenderingStrategy/HIncludeRenderingStrategy.php | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml index 1e6dc5c6c1..533e886fb6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml @@ -7,7 +7,6 @@ Symfony\Component\HttpKernel\HttpContentRenderer Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy - Symfony\Component\HttpKernel\RenderingStrategy\EsiRenderingStrategy Symfony\Component\HttpKernel\RenderingStrategy\HIncludeRenderingStrategy Symfony\Component\HttpKernel\EventListener\RouterProxyListener @@ -26,17 +25,10 @@ - - - - - - - - + %http_content_renderer.strategy.hinclude.global_template% diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml index 3038f40e97..45e9265442 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml @@ -7,6 +7,7 @@ Symfony\Component\HttpKernel\HttpCache\Esi Symfony\Component\HttpKernel\EventListener\EsiListener + Symfony\Component\HttpKernel\RenderingStrategy\EsiRenderingStrategy @@ -16,5 +17,12 @@ + + + + + + + diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php index 7a4b77fc2f..82abf3f71f 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/HIncludeRenderingStrategy.php @@ -34,9 +34,9 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy * @param UriSigner $signer A UriSigner instance * @param string $globalDefaultTemplate The global default content (it can be a template name or the content) */ - public function __construct($templating, UriSigner $signer = null, $globalDefaultTemplate = null) + public function __construct($templating = null, UriSigner $signer = null, $globalDefaultTemplate = null) { - if (!$templating instanceof EngineInterface && !$templating instanceof \Twig_Environment) { + if (null !== $templating && !$templating instanceof EngineInterface && !$templating instanceof \Twig_Environment) { throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of \Twig_Environment or Symfony\Component\Templating\EngineInterface'); } @@ -63,7 +63,7 @@ class HIncludeRenderingStrategy extends GeneratorAwareRenderingStrategy } $template = isset($options['default']) ? $options['default'] : $this->globalDefaultTemplate; - if ($this->templateExists($template)) { + if (null !== $this->templating && $this->templateExists($template)) { $content = $this->templating->render($template); } else { $content = $template; From 2eea7682e76e03aeb08064cba1c8a70c29f7ba0d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Jan 2013 11:00:55 +0100 Subject: [PATCH 067/128] moved the deprecation logic calls outside the new HttpContentRenderer class --- src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php | 2 ++ src/Symfony/Bundle/FrameworkBundle/HttpKernel.php | 2 ++ .../FrameworkBundle/Templating/Helper/ActionsHelper.php | 2 ++ src/Symfony/Component/HttpKernel/HttpContentRenderer.php | 8 ++------ 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php index 22ded3d197..2e406fc1d9 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php @@ -54,6 +54,8 @@ class HttpKernelExtension extends \Twig_Extension */ public function render($uri, $options = array()) { + $options = $this->renderer->fixOptions($options); + $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; unset($options['strategy']); diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php index b67f0c640e..db4c3c3fc8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php @@ -105,6 +105,8 @@ class HttpKernel extends BaseHttpKernel { trigger_error('render() is deprecated since version 2.2 and will be removed in 2.3. Use Symfony\Component\HttpKernel\HttpContentRenderer::render() instead.', E_USER_DEPRECATED); + $options = $this->renderer->fixOptions($options); + $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; unset($options['strategy']); diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php index 94c7698294..abce1d10bf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php @@ -46,6 +46,8 @@ class ActionsHelper extends Helper */ public function render($uri, array $options = array()) { + $options = $this->renderer->fixOptions($options); + $strategy = isset($options['strategy']) ? $options['strategy'] : 'default'; unset($options['strategy']); diff --git a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php index 94e35bb15d..408dffc991 100644 --- a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php +++ b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php @@ -97,11 +97,6 @@ class HttpContentRenderer implements EventSubscriberInterface $options['ignore_errors'] = !$this->debug; } - $options = $this->fixOptions($options); - if (isset($options['strategy'])) { - $strategy = $options['strategy']; - } - if (!isset($this->strategies[$strategy])) { throw new \InvalidArgumentException(sprintf('The "%s" rendering strategy does not exist.', $strategy)); } @@ -118,7 +113,7 @@ class HttpContentRenderer implements EventSubscriberInterface } // to be removed in 2.3 - private function fixOptions($options) + public function fixOptions(array $options) { // support for the standalone option is @deprecated in 2.2 and replaced with the strategy option if (isset($options['standalone'])) { @@ -136,6 +131,7 @@ class HttpContentRenderer implements EventSubscriberInterface } $options['strategy'] = $options['standalone']; + unset($options['standalone']); } return $options; From f17f5867a876772021aeb769e38b05f8ee497f07 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Jan 2013 11:02:31 +0100 Subject: [PATCH 068/128] moved the container aware HTTP kernel to the HttpKernel component --- .../Bundle/FrameworkBundle/HttpKernel.php | 40 +--------- .../ContainerAwareHttpKernel.php | 68 +++++++++++++++++ .../ContainerAwareHttpKernelTest.php} | 74 +++++-------------- .../DefaultRenderingStrategyTest.php | 64 ++++++++++++++++ 4 files changed, 156 insertions(+), 90 deletions(-) create mode 100644 src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php rename src/Symfony/{Bundle/FrameworkBundle/Tests/HttpKernelTest.php => Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php} (66%) create mode 100644 src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php index db4c3c3fc8..71a677cebe 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpKernel.php @@ -11,52 +11,20 @@ namespace Symfony\Bundle\FrameworkBundle; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpKernel\HttpKernel as BaseHttpKernel; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel; /** * This HttpKernel is used to manage scope changes of the DI container. * * @author Fabien Potencier * @author Johannes M. Schmitt + * + * @deprecated This class is deprecated in 2.2 and will be removed in 2.3 */ -class HttpKernel extends BaseHttpKernel +class HttpKernel extends ContainerAwareHttpKernel { - protected $container; - - public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver) - { - parent::__construct($dispatcher, $controllerResolver); - - $this->container = $container; - } - - public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) - { - $request->headers->set('X-Php-Ob-Level', ob_get_level()); - - $this->container->enterScope('request'); - $this->container->set('request', $request, 'request'); - - try { - $response = parent::handle($request, $type, $catch); - } catch (\Exception $e) { - $this->container->leaveScope('request'); - - throw $e; - } - - $this->container->leaveScope('request'); - - return $response; - } - /** * Forwards the request to another controller. * diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php new file mode 100644 index 0000000000..20b4a5e75e --- /dev/null +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/ContainerAwareHttpKernel.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\DependencyInjection; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\HttpKernel; +use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * This HttpKernel is used to manage scope changes of the DI container. + * + * @author Fabien Potencier + * @author Johannes M. Schmitt + */ +class ContainerAwareHttpKernel extends HttpKernel +{ + protected $container; + + /** + * Constructor. + * + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + * @param ContainerInterface $container A ContainerInterface instance + * @param ControllerResolverInterface $controllerResolver A ControllerResolverInterface instance + */ + public function __construct(EventDispatcherInterface $dispatcher, ContainerInterface $container, ControllerResolverInterface $controllerResolver) + { + parent::__construct($dispatcher, $controllerResolver); + + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) + { + $request->headers->set('X-Php-Ob-Level', ob_get_level()); + + $this->container->enterScope('request'); + $this->container->set('request', $request, 'request'); + + try { + $response = parent::handle($request, $type, $catch); + } catch (\Exception $e) { + $this->container->leaveScope('request'); + + throw $e; + } + + $this->container->leaveScope('request'); + + return $response; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php similarity index 66% rename from src/Symfony/Bundle/FrameworkBundle/Tests/HttpKernelTest.php rename to src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php index c7587f6b4b..80d5ffa61a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/ContainerAwareHttpKernelTest.php @@ -9,16 +9,31 @@ * file that was distributed with this source code. */ -namespace Symfony\Bundle\FrameworkBundle\Tests; +namespace Symfony\Component\HttpKernel\Tests; use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; -use Symfony\Bundle\FrameworkBundle\HttpKernel; use Symfony\Component\EventDispatcher\EventDispatcher; -class HttpKernelTest extends \PHPUnit_Framework_TestCase +class ContainerAwareHttpKernelTest extends \PHPUnit_Framework_TestCase { + protected function setUp() + { + if (!class_exists('Symfony\Component\DependencyInjection\Container')) { + $this->markTestSkipped('The "DependencyInjection" component is not available'); + } + + if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) { + $this->markTestSkipped('The "EventDispatcher" component is not available'); + } + + if (!class_exists('Symfony\Component\HttpFoundation\Request')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + } + /** * @dataProvider getProviderTypes */ @@ -46,7 +61,7 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase $dispatcher = new EventDispatcher(); $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); - $kernel = new HttpKernel($dispatcher, $container, $resolver); + $kernel = new ContainerAwareHttpKernel($dispatcher, $container, $resolver); $controller = function() use ($expected) { return $expected; @@ -93,7 +108,7 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase $dispatcher = new EventDispatcher(); $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); - $kernel = new HttpKernel($dispatcher, $container, $resolver); + $kernel = new ContainerAwareHttpKernel($dispatcher, $container, $resolver); $controller = function() use ($expected) { throw $expected; @@ -123,53 +138,4 @@ class HttpKernelTest extends \PHPUnit_Framework_TestCase array(HttpKernelInterface::SUB_REQUEST), ); } - - public function testExceptionInSubRequestsDoesNotMangleOutputBuffers() - { - $request = new Request(); - - $container = $this->getMock('Symfony\\Component\\DependencyInjection\\ContainerInterface'); - $container - ->expects($this->at(0)) - ->method('get') - ->with($this->equalTo('request')) - ->will($this->returnValue($request)) - ; - $container - ->expects($this->at(1)) - ->method('getParameter') - ->with($this->equalTo('kernel.debug')) - ->will($this->returnValue(false)) - ; - $container - ->expects($this->at(2)) - ->method('has') - ->with($this->equalTo('esi')) - ->will($this->returnValue(false)) - ; - - $dispatcher = new EventDispatcher(); - $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); - $resolver->expects($this->once()) - ->method('getController') - ->will($this->returnValue(function () { - ob_start(); - echo 'bar'; - throw new \RuntimeException(); - })); - $resolver->expects($this->once()) - ->method('getArguments') - ->will($this->returnValue(array())); - - $kernel = new HttpKernel($dispatcher, $container, $resolver); - - // simulate a main request with output buffering - ob_start(); - echo 'Foo'; - - // simulate a sub-request with output buffering and an exception - $kernel->render('/'); - - $this->assertEquals('Foo', ob_get_clean()); - } } diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php new file mode 100644 index 0000000000..48a5451470 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy; + +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\HttpKernel; +use Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\EventDispatcher\EventDispatcher; + +class DefaultRenderingStrategyTest extends \PHPUnit_Framework_TestCase +{ + protected function setUp() + { + if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) { + $this->markTestSkipped('The "EventDispatcher" component is not available'); + } + + if (!class_exists('Symfony\Component\HttpFoundation\Request')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + } + + public function testExceptionInSubRequestsDoesNotMangleOutputBuffers() + { + $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); + $resolver + ->expects($this->once()) + ->method('getController') + ->will($this->returnValue(function () { + ob_start(); + echo 'bar'; + throw new \RuntimeException(); + })) + ; + $resolver + ->expects($this->once()) + ->method('getArguments') + ->will($this->returnValue(array())) + ; + + $kernel = new HttpKernel(new EventDispatcher(), $resolver); + $renderer = new DefaultRenderingStrategy($kernel); + + // simulate a main request with output buffering + ob_start(); + echo 'Foo'; + + // simulate a sub-request with output buffering and an exception + $renderer->render('/', Request::create('/'), array('ignore_errors' => true)); + + $this->assertEquals('Foo', ob_get_clean()); + } +} From 68257d372f45efa6e67115acbf80e7e48e4ba1e9 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Thu, 10 Jan 2013 02:11:10 +0100 Subject: [PATCH 069/128] Enhanced the triggering of E_USER_DEPRECATED errors - Removed useless error handlers around FormEvent as the triggering has been fixed in it. - Enhanced the triggering of deprecation errors for places where the BC method provide some user logic needing to be converted to a new way. - Enhanced the deprecation messages to mention the replacement whenever possible. --- src/Symfony/Component/Form/AbstractType.php | 22 +++++++++----- .../Component/Form/AbstractTypeExtension.php | 22 +++++++++----- .../Component/Form/CallbackValidator.php | 2 +- src/Symfony/Component/Form/Form.php | 23 +++++++++----- src/Symfony/Component/Form/FormBuilder.php | 4 +-- .../Form/Test/DeprecationErrorHandler.php | 12 -------- .../Component/Form/Tests/CompoundFormTest.php | 4 +-- .../FixRadioInputListenerTest.php | 8 ++--- .../FixUrlProtocolListenerTest.php | 8 ++--- .../MergeCollectionListenerTest.php | 20 ++++++------- .../EventListener/ResizeFormListenerTest.php | 30 +++++++++---------- .../Core/EventListener/TrimListenerTest.php | 8 ++--- .../CsrfValidationListenerTest.php | 4 +-- .../EventListener/BindRequestListenerTest.php | 18 +++++------ .../EventListener/ValidationListenerTest.php | 10 +++---- .../Component/Form/Tests/SimpleFormTest.php | 3 +- .../Component/HttpFoundation/Request.php | 2 -- .../Loader/QtTranslationsLoader.php | 6 +++- .../Validator/ConstraintValidator.php | 3 +- .../Component/Validator/Constraints/Max.php | 2 +- .../Validator/Constraints/MaxLength.php | 2 +- .../Component/Validator/Constraints/Min.php | 2 +- .../Validator/Constraints/MinLength.php | 2 +- .../Mapping/ClassMetadataFactory.php | 20 ++----------- .../Mapping/ClassMetadataFactoryAdapter.php | 18 ++--------- 25 files changed, 116 insertions(+), 139 deletions(-) diff --git a/src/Symfony/Component/Form/AbstractType.php b/src/Symfony/Component/Form/AbstractType.php index 00d374b7f7..8769415ea6 100644 --- a/src/Symfony/Component/Form/AbstractType.php +++ b/src/Symfony/Component/Form/AbstractType.php @@ -51,10 +51,20 @@ abstract class AbstractType implements FormTypeInterface */ public function setDefaultOptions(OptionsResolverInterface $resolver) { - set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handleBC')); - $resolver->setDefaults($this->getDefaultOptions(array())); - $resolver->addAllowedValues($this->getAllowedOptionValues(array())); - restore_error_handler(); + $defaults = $this->getDefaultOptions(array()); + $allowedTypes = $this->getAllowedOptionValues(array()); + + if (!empty($defaults)) { + trigger_error('getDefaultOptions() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); + + $resolver->setDefaults($defaults); + } + + if (!empty($allowedTypes)) { + trigger_error('getAllowedOptionValues() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); + + $resolver->addAllowedValues($allowedTypes); + } } /** @@ -69,8 +79,6 @@ abstract class AbstractType implements FormTypeInterface */ public function getDefaultOptions(array $options) { - trigger_error('getDefaultOptions() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); - return array(); } @@ -86,8 +94,6 @@ abstract class AbstractType implements FormTypeInterface */ public function getAllowedOptionValues(array $options) { - trigger_error('getAllowedOptionValues() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); - return array(); } diff --git a/src/Symfony/Component/Form/AbstractTypeExtension.php b/src/Symfony/Component/Form/AbstractTypeExtension.php index 38f4a8f1b6..3e51ed442b 100644 --- a/src/Symfony/Component/Form/AbstractTypeExtension.php +++ b/src/Symfony/Component/Form/AbstractTypeExtension.php @@ -44,10 +44,20 @@ abstract class AbstractTypeExtension implements FormTypeExtensionInterface */ public function setDefaultOptions(OptionsResolverInterface $resolver) { - set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handleBC')); - $resolver->setDefaults($this->getDefaultOptions()); - $resolver->addAllowedValues($this->getAllowedOptionValues()); - restore_error_handler(); + $defaults = $this->getDefaultOptions(array()); + $allowedTypes = $this->getAllowedOptionValues(array()); + + if (!empty($defaults)) { + trigger_error('getDefaultOptions() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); + + $resolver->setDefaults($defaults); + } + + if (!empty($allowedTypes)) { + trigger_error('getAllowedOptionValues() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); + + $resolver->addAllowedValues($allowedTypes); + } } /** @@ -60,8 +70,6 @@ abstract class AbstractTypeExtension implements FormTypeExtensionInterface */ public function getDefaultOptions() { - trigger_error('getDefaultOptions() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); - return array(); } @@ -75,8 +83,6 @@ abstract class AbstractTypeExtension implements FormTypeExtensionInterface */ public function getAllowedOptionValues() { - trigger_error('getAllowedOptionValues() is deprecated since version 2.1 and will be removed in 2.3. Use setDefaultOptions() instead.', E_USER_DEPRECATED); - return array(); } } diff --git a/src/Symfony/Component/Form/CallbackValidator.php b/src/Symfony/Component/Form/CallbackValidator.php index 0e7c8012eb..f769cc7cbd 100644 --- a/src/Symfony/Component/Form/CallbackValidator.php +++ b/src/Symfony/Component/Form/CallbackValidator.php @@ -27,7 +27,7 @@ class CallbackValidator implements FormValidatorInterface */ public function __construct($callback) { - trigger_error('CallbackValidator is deprecated since version 2.1 and will be removed in 2.3.', E_USER_DEPRECATED); + trigger_error('CallbackValidator is deprecated since version 2.1 and will be removed in 2.3. Use the FormEvents::POST_BIND event instead.', E_USER_DEPRECATED); $this->callback = $callback; } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index eb93637877..eb729ebc1f 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -367,11 +367,12 @@ class Form implements \IteratorAggregate, FormInterface // Hook to change content of the data if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA) || $dispatcher->hasListeners(FormEvents::SET_DATA)) { - set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handleBC')); $event = new FormEvent($this, $modelData); - restore_error_handler(); $dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); // BC until 2.3 + if ($dispatcher->hasListeners(FormEvents::SET_DATA)) { + trigger_error('The FormEvents::SET_DATA event is deprecated since 2.1 and will be removed in 2.3. Use the FormEvents::PRE_SET_DATA event instead.', E_USER_DEPRECATED); + } $dispatcher->dispatch(FormEvents::SET_DATA, $event); $modelData = $event->getData(); } @@ -532,11 +533,12 @@ class Form implements \IteratorAggregate, FormInterface // Hook to change content of the data bound by the browser if ($dispatcher->hasListeners(FormEvents::PRE_BIND) || $dispatcher->hasListeners(FormEvents::BIND_CLIENT_DATA)) { - set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handleBC')); $event = new FormEvent($this, $submittedData); - restore_error_handler(); $dispatcher->dispatch(FormEvents::PRE_BIND, $event); // BC until 2.3 + if ($dispatcher->hasListeners(FormEvents::BIND_CLIENT_DATA)) { + trigger_error('The FormEvents::BIND_CLIENT_DATA event is deprecated since 2.1 and will be removed in 2.3. Use the FormEvents::PRE_BIND event instead.', E_USER_DEPRECATED); + } $dispatcher->dispatch(FormEvents::BIND_CLIENT_DATA, $event); $submittedData = $event->getData(); } @@ -594,11 +596,12 @@ class Form implements \IteratorAggregate, FormInterface // Hook to change content of the data into the normalized // representation if ($dispatcher->hasListeners(FormEvents::BIND) || $dispatcher->hasListeners(FormEvents::BIND_NORM_DATA)) { - set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handleBC')); $event = new FormEvent($this, $normData); - restore_error_handler(); $dispatcher->dispatch(FormEvents::BIND, $event); // BC until 2.3 + if ($dispatcher->hasListeners(FormEvents::BIND_NORM_DATA)) { + trigger_error('The FormEvents::BIND_NORM_DATA event is deprecated since 2.1 and will be removed in 2.3. Use the FormEvents::BIND event instead.', E_USER_DEPRECATED); + } $dispatcher->dispatch(FormEvents::BIND_NORM_DATA, $event); $normData = $event->getData(); } @@ -621,10 +624,14 @@ class Form implements \IteratorAggregate, FormInterface } set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handleBC')); - foreach ($this->config->getValidators() as $validator) { + $validators = $this->config->getValidators(); + restore_error_handler(); + + foreach ($validators as $validator) { + trigger_error(sprintf('FormConfigInterface::getValidators() is deprecated since 2.1 and will be removed in 2.3. Convert your %s class to a listener on the FormEvents::POST_BIND event.', get_class($validator)), E_USER_DEPRECATED); + $validator->validate($this); } - restore_error_handler(); return $this; } diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index 0dfd8d0962..a47d969e05 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -301,12 +301,12 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB */ public function getTypes() { + trigger_error('getTypes() is deprecated since version 2.1 and will be removed in 2.3. Use getConfig() and FormConfigInterface::getType() instead.', E_USER_DEPRECATED); + if ($this->locked) { throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.'); } - trigger_error('getTypes() is deprecated since version 2.1 and will be removed in 2.3. Use getConfig() and FormConfigInterface::getType() instead.', E_USER_DEPRECATED); - $types = array(); for ($type = $this->getType(); null !== $type; $type = $type->getParent()) { diff --git a/src/Symfony/Component/Form/Test/DeprecationErrorHandler.php b/src/Symfony/Component/Form/Test/DeprecationErrorHandler.php index 8c6dd90831..21b3a6e6b0 100644 --- a/src/Symfony/Component/Form/Test/DeprecationErrorHandler.php +++ b/src/Symfony/Component/Form/Test/DeprecationErrorHandler.php @@ -2,9 +2,6 @@ namespace Symfony\Component\Form\Test; -use Symfony\Component\Form\FormInterface as NonTestFormInterface; -use Symfony\Component\Form\FormEvent; - class DeprecationErrorHandler { public static function handle($errorNumber, $message, $file, $line, $context) @@ -24,13 +21,4 @@ class DeprecationErrorHandler return false; } - - public static function getFormEvent(NonTestFormInterface $form, $data) - { - set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handle')); - $event = new FormEvent($form, $data); - restore_error_handler(); - - return $event; - } } diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php index 9f1ce08d9e..ca97c8ec2a 100644 --- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php +++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php @@ -231,9 +231,7 @@ class CompoundFormTest extends AbstractFormTest $this->form->remove('foo'); $this->assertNull($child->getParent()); - set_error_handler(array('Symfony\Component\Form\Test\DeprecationErrorHandler', 'handle')); - $this->assertFalse($this->form->hasChildren()); - restore_error_handler(); + $this->assertCount(0, $this->form); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php index 5a7f5e7d17..35bc7323dd 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixRadioInputListenerTest.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; +use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener; use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList; -use Symfony\Component\Form\Test\DeprecationErrorHandler; class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase { @@ -42,7 +42,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase { $data = '1'; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $this->listener->preBind($event); @@ -53,7 +53,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase { $data = '0'; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $this->listener->preBind($event); @@ -64,7 +64,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase { $data = ''; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $this->listener->preBind($event); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php index 70db9b421e..2517f40b04 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; +use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener; -use Symfony\Component\Form\Test\DeprecationErrorHandler; class FixUrlProtocolListenerTest extends \PHPUnit_Framework_TestCase { @@ -27,7 +27,7 @@ class FixUrlProtocolListenerTest extends \PHPUnit_Framework_TestCase { $data = "www.symfony.com"; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $filter = new FixUrlProtocolListener('http'); $filter->onBind($event); @@ -39,7 +39,7 @@ class FixUrlProtocolListenerTest extends \PHPUnit_Framework_TestCase { $data = "http://www.symfony.com"; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $filter = new FixUrlProtocolListener('http'); $filter->onBind($event); @@ -51,7 +51,7 @@ class FixUrlProtocolListenerTest extends \PHPUnit_Framework_TestCase { $data = "ftp://www.symfony.com"; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $filter = new FixUrlProtocolListener('http'); $filter->onBind($event); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php index bf83e057e9..b6ca56e7a4 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; +use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener; -use Symfony\Component\Form\Test\DeprecationErrorHandler; abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase { @@ -84,7 +84,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); // The original object was modified @@ -108,7 +108,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); // The original object was modified @@ -133,7 +133,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); // We still have the original object @@ -157,7 +157,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); // The original object was modified @@ -182,7 +182,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); // We still have the original object @@ -201,7 +201,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase public function testRequireArrayOrTraversable($allowAdd, $allowDelete) { $newData = 'no array or traversable'; - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener = new MergeCollectionListener($allowAdd, $allowDelete); $listener->onBind($event); } @@ -215,7 +215,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); $this->assertSame($originalData, $event->getData()); @@ -233,7 +233,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); $this->assertSame($newData, $event->getData()); @@ -251,7 +251,7 @@ abstract class MergeCollectionListenerTest extends \PHPUnit_Framework_TestCase $this->form->setData($originalData); - $event = DeprecationErrorHandler::getFormEvent($this->form, $newData); + $event = new FormEvent($this->form, $newData); $listener->onBind($event); $this->assertNull($event->getData()); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php index 459b1d7f24..5dfcc3d789 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php @@ -13,7 +13,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener; use Symfony\Component\Form\FormBuilder; -use Symfony\Component\Form\Test\DeprecationErrorHandler; +use Symfony\Component\Form\FormEvent; class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase { @@ -80,7 +80,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue($this->getForm('2'))); $data = array(1 => 'string', 2 => 'string'); - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array('max_length' => '10'), false, false); $listener->preSetData($event); @@ -95,7 +95,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase public function testPreSetDataRequiresArrayOrTraversable() { $data = 'no array or traversable'; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, false); $listener->preSetData($event); } @@ -105,7 +105,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->factory->expects($this->never())->method('createNamed'); $data = null; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, false); $listener->preSetData($event); } @@ -120,7 +120,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue($this->getForm('1'))); $data = array(0 => 'string', 1 => 'string'); - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array('max_length' => 10), true, false); $listener->preBind($event); @@ -134,7 +134,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('1')); $data = array(0 => 'string'); - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, true); $listener->preBind($event); @@ -148,7 +148,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('0')); $data = array(); - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, true); $listener->preBind($event); @@ -161,7 +161,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('1')); $data = array(0 => 'string', 2 => 'string'); - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, false); $listener->preBind($event); @@ -176,7 +176,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase public function testPreBindRequiresArrayOrTraversable() { $data = 'no array or traversable'; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, false); $listener->preBind($event); } @@ -186,7 +186,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('1')); $data = null; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, true); $listener->preBind($event); @@ -199,7 +199,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('1')); $data = ''; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, true); $listener->preBind($event); @@ -211,7 +211,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('1')); $data = array(0 => 'first', 1 => 'second', 2 => 'third'); - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, true); $listener->onBind($event); @@ -223,7 +223,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('1')); $data = array(0 => 'first', 1 => 'second', 2 => 'third'); - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, false); $listener->onBind($event); @@ -236,7 +236,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase public function testOnBindNormDataRequiresArrayOrTraversable() { $data = 'no array or traversable'; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, false); $listener->onBind($event); } @@ -246,7 +246,7 @@ class ResizeFormListenerTest extends \PHPUnit_Framework_TestCase $this->form->add($this->getForm('1')); $data = null; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $listener = new ResizeFormListener('text', array(), false, true); $listener->onBind($event); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php index 49419065d2..9e5d20db71 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; +use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\Extension\Core\EventListener\TrimListener; -use Symfony\Component\Form\Test\DeprecationErrorHandler; class TrimListenerTest extends \PHPUnit_Framework_TestCase { @@ -27,7 +27,7 @@ class TrimListenerTest extends \PHPUnit_Framework_TestCase { $data = " Foo! "; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $filter = new TrimListener(); $filter->preBind($event); @@ -39,7 +39,7 @@ class TrimListenerTest extends \PHPUnit_Framework_TestCase { $data = 1234; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $filter = new TrimListener(); $filter->preBind($event); @@ -60,7 +60,7 @@ class TrimListenerTest extends \PHPUnit_Framework_TestCase $data = $data."ab\ncd".$data; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = DeprecationErrorHandler::getFormEvent($form, $data); + $event = new FormEvent($form, $data); $filter = new TrimListener(); $filter->preBind($event); diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php index 49c40d3b05..136ddbc1e0 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php @@ -12,8 +12,8 @@ namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; -use Symfony\Component\Form\Test\DeprecationErrorHandler; class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase { @@ -67,7 +67,7 @@ class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase public function testStringFormData() { $data = "XP4HUzmHPi"; - $event = DeprecationErrorHandler::getFormEvent($this->form, $data); + $event = new FormEvent($this->form, $data); $validation = new CsrfValidationListener('csrf', $this->csrfProvider, 'unknown'); $validation->preBind($event); diff --git a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php index 94ae47a3c4..bfb9afa0a7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/EventListener/BindRequestListenerTest.php @@ -14,9 +14,9 @@ namespace Symfony\Component\Form\Tests\Extension\HttpFoundation\EventListener; use Symfony\Component\Form\Extension\HttpFoundation\EventListener\BindRequestListener; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigBuilder; +use Symfony\Component\Form\FormEvent; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\File\UploadedFile; -use Symfony\Component\Form\Test\DeprecationErrorHandler; /** * @author Bernhard Schussek @@ -98,7 +98,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $config = new FormConfigBuilder('author', null, $dispatcher); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); @@ -125,7 +125,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $config = new FormConfigBuilder('', null, $dispatcher); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); @@ -154,7 +154,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $config->setCompound(true); $config->setDataMapper($this->getMock('Symfony\Component\Form\DataMapperInterface')); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); @@ -180,7 +180,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $config = new FormConfigBuilder('author', null, $dispatcher); $config->setCompound(false); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); @@ -203,7 +203,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $config = new FormConfigBuilder('author', null, $dispatcher); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); @@ -227,7 +227,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $config = new FormConfigBuilder('', null, $dispatcher); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); @@ -253,7 +253,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $config->setCompound(true); $config->setDataMapper($this->getMock('Symfony\Component\Form\DataMapperInterface')); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); @@ -275,7 +275,7 @@ class BindRequestListenerTest extends \PHPUnit_Framework_TestCase $config = new FormConfigBuilder('author', null, $dispatcher); $config->setCompound(false); $form = new Form($config); - $event = DeprecationErrorHandler::getFormEvent($form, $request); + $event = new FormEvent($form, $request); $listener = new BindRequestListener(); $listener->preBind($event); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php index d9555e13e1..9c2ca410dd 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php @@ -11,14 +11,12 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener; -use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormBuilder; -use Symfony\Component\Form\FormError; +use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener; use Symfony\Component\Validator\ConstraintViolation; -use Symfony\Component\Form\Test\DeprecationErrorHandler; class ValidationListenerTest extends \PHPUnit_Framework_TestCase { @@ -109,7 +107,7 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase ->method('mapViolation') ->with($violation, $form, false); - $this->listener->validateForm(DeprecationErrorHandler::getFormEvent($form, null)); + $this->listener->validateForm(new FormEvent($form, null)); } public function testMapViolationAllowsNonSyncIfInvalid() @@ -126,7 +124,7 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase // pass true now ->with($violation, $form, true); - $this->listener->validateForm(DeprecationErrorHandler::getFormEvent($form, null)); + $this->listener->validateForm(new FormEvent($form, null)); } public function testValidateIgnoresNonRoot() @@ -142,6 +140,6 @@ class ValidationListenerTest extends \PHPUnit_Framework_TestCase $this->violationMapper->expects($this->never()) ->method('mapViolation'); - $this->listener->validateForm(DeprecationErrorHandler::getFormEvent($form, null)); + $this->listener->validateForm(new FormEvent($form, null)); } } diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 0d72df3acb..d0fe3347bd 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -648,7 +648,6 @@ class SimpleFormTest extends AbstractFormTest $form = $this->getBuilder() ->addValidator($validator) ->getForm(); - restore_error_handler(); $validator->expects($this->once()) ->method('validate') @@ -658,6 +657,8 @@ class SimpleFormTest extends AbstractFormTest })); $form->bind('foobar'); + + restore_error_handler(); } public function testBindResetsErrors() diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 5ec5fd3510..376e0612e5 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -676,8 +676,6 @@ class Request * * @see http://en.wikipedia.org/wiki/X-Forwarded-For * - * @deprecated The proxy argument is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies instead. - * * @api */ public function getClientIp() diff --git a/src/Symfony/Component/Translation/Loader/QtTranslationsLoader.php b/src/Symfony/Component/Translation/Loader/QtTranslationsLoader.php index 5c3dbba817..237a3b1b4b 100644 --- a/src/Symfony/Component/Translation/Loader/QtTranslationsLoader.php +++ b/src/Symfony/Component/Translation/Loader/QtTranslationsLoader.php @@ -22,5 +22,9 @@ namespace Symfony\Component\Translation\Loader; * Use QtFileLoader instead. */ class QtTranslationsLoader extends QtFileLoader -{ +{ + public function __construct() + { + trigger_error('QtTranslationsLoader is deprecated since version 2.2 and will be removed in 2.3. Use QtFileLoader instead.', E_USER_DEPRECATED); + } } diff --git a/src/Symfony/Component/Validator/ConstraintValidator.php b/src/Symfony/Component/Validator/ConstraintValidator.php index 6fbd2a5abc..839dcb3e6e 100644 --- a/src/Symfony/Component/Validator/ConstraintValidator.php +++ b/src/Symfony/Component/Validator/ConstraintValidator.php @@ -103,6 +103,8 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface */ public function validate($value, Constraint $constraint) { + trigger_error('isValid() is deprecated since version 2.1 and will be removed in 2.3. Implement validate() instead.', E_USER_DEPRECATED); + return $this->isValid($value, $constraint); } @@ -113,6 +115,5 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface */ protected function isValid($value, Constraint $constraint) { - trigger_error('isValid() is deprecated since version 2.1 and will be removed in 2.3.', E_USER_DEPRECATED); } } diff --git a/src/Symfony/Component/Validator/Constraints/Max.php b/src/Symfony/Component/Validator/Constraints/Max.php index 9ca13704e0..4017bf8302 100644 --- a/src/Symfony/Component/Validator/Constraints/Max.php +++ b/src/Symfony/Component/Validator/Constraints/Max.php @@ -28,7 +28,7 @@ class Max extends Constraint public function __construct($options = null) { - trigger_error('Max is deprecated since version 2.1 and will be removed in 2.3.', E_USER_DEPRECATED); + trigger_error('Max is deprecated since version 2.1 and will be removed in 2.3. Use Range instead.', E_USER_DEPRECATED); parent::__construct($options); } diff --git a/src/Symfony/Component/Validator/Constraints/MaxLength.php b/src/Symfony/Component/Validator/Constraints/MaxLength.php index a737e38c46..da0ba8641c 100644 --- a/src/Symfony/Component/Validator/Constraints/MaxLength.php +++ b/src/Symfony/Component/Validator/Constraints/MaxLength.php @@ -28,7 +28,7 @@ class MaxLength extends Constraint public function __construct($options = null) { - trigger_error('MaxLength is deprecated since version 2.1 and will be removed in 2.3.', E_USER_DEPRECATED); + trigger_error('MaxLength is deprecated since version 2.1 and will be removed in 2.3. Use Length instead.', E_USER_DEPRECATED); parent::__construct($options); } diff --git a/src/Symfony/Component/Validator/Constraints/Min.php b/src/Symfony/Component/Validator/Constraints/Min.php index 2d8bf0f680..23477ec403 100644 --- a/src/Symfony/Component/Validator/Constraints/Min.php +++ b/src/Symfony/Component/Validator/Constraints/Min.php @@ -28,7 +28,7 @@ class Min extends Constraint public function __construct($options = null) { - trigger_error('Min is deprecated since version 2.1 and will be removed in 2.3.', E_USER_DEPRECATED); + trigger_error('Min is deprecated since version 2.1 and will be removed in 2.3. Use Range instead.', E_USER_DEPRECATED); parent::__construct($options); } diff --git a/src/Symfony/Component/Validator/Constraints/MinLength.php b/src/Symfony/Component/Validator/Constraints/MinLength.php index 9827ac330e..3335af4477 100644 --- a/src/Symfony/Component/Validator/Constraints/MinLength.php +++ b/src/Symfony/Component/Validator/Constraints/MinLength.php @@ -28,7 +28,7 @@ class MinLength extends Constraint public function __construct($options = null) { - trigger_error('MinLength is deprecated since version 2.1 and will be removed in 2.3.', E_USER_DEPRECATED); + trigger_error('MinLength is deprecated since version 2.1 and will be removed in 2.3. Use Length instead.', E_USER_DEPRECATED); parent::__construct($options); } diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadataFactory.php b/src/Symfony/Component/Validator/Mapping/ClassMetadataFactory.php index 362b75d5a6..c1155b9c63 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadataFactory.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadataFactory.php @@ -70,20 +70,16 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface, MetadataFac // Include constraints from the parent class if ($parent = $metadata->getReflectionClass()->getParentClass()) { - set_error_handler(array($this, 'handleBC')); - $metadata->mergeConstraints($this->getClassMetadata($parent->name)); - restore_error_handler(); + $metadata->mergeConstraints($this->getMetadataFor($parent->name)); } // Include constraints from all implemented interfaces - set_error_handler(array($this, 'handleBC')); foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) { if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name) { continue; } - $metadata->mergeConstraints($this->getClassMetadata($interface->name)); + $metadata->mergeConstraints($this->getMetadataFor($interface->name)); } - restore_error_handler(); if (null !== $this->loader) { $this->loader->loadClassMetadata($metadata); @@ -126,16 +122,4 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface, MetadataFac return $this->getMetadataFor($class); } - - /** - * @deprecated This is used to keep BC until deprecated methods are removed - */ - public function handleBC($errorNumber, $message, $file, $line, $context) - { - if ($errorNumber & E_USER_DEPRECATED) { - return true; - } - - return false; - } } diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadataFactoryAdapter.php b/src/Symfony/Component/Validator/Mapping/ClassMetadataFactoryAdapter.php index 5a2c6d0d1d..95c5849d26 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadataFactoryAdapter.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadataFactoryAdapter.php @@ -29,6 +29,8 @@ class ClassMetadataFactoryAdapter implements MetadataFactoryInterface public function __construct(ClassMetadataFactoryInterface $innerFactory) { + trigger_error(sprintf('ClassMetadataFactoryInterface is deprecated since version 2.1 and will be removed in 2.3. Implement MetadataFactoryInterface instead on %s.', get_class($innerFactory)), E_USER_DEPRECATED); + $this->innerFactory = $innerFactory; } @@ -38,9 +40,7 @@ class ClassMetadataFactoryAdapter implements MetadataFactoryInterface public function getMetadataFor($value) { $class = is_object($value) ? get_class($value) : $value; - set_error_handler(array($this, 'handleBC')); $metadata = $this->innerFactory->getClassMetadata($class); - restore_error_handler(); if (null === $metadata) { throw new NoSuchMetadataException('No metadata exists for class '. $class); @@ -56,22 +56,8 @@ class ClassMetadataFactoryAdapter implements MetadataFactoryInterface { $class = is_object($value) ? get_class($value) : $value; - set_error_handler(array($this, 'handleBC')); $return = null !== $this->innerFactory->getClassMetadata($class); - restore_error_handler(); return $return; } - - /** - * @deprecated This is used to keep BC until deprecated methods are removed - */ - public function handleBC($errorNumber, $message, $file, $line, $context) - { - if ($errorNumber & E_USER_DEPRECATED) { - return true; - } - - return false; - } } From 1bae7b242c37760b809b653a177ad61fc5b47984 Mon Sep 17 00:00:00 2001 From: Bernhard Schussek Date: Mon, 7 Jan 2013 09:19:31 +0100 Subject: [PATCH 070/128] [PropertyAccess] Extracted PropertyAccess component out of Form --- UPGRADE-2.2.md | 128 ++++ src/Symfony/Bridge/Doctrine/CHANGELOG.md | 6 + .../Form/ChoiceList/EntityChoiceList.php | 24 +- .../Doctrine/Form/DoctrineOrmExtension.php | 3 +- .../Doctrine/Form/Type/DoctrineType.php | 16 +- .../Tests/Form/Type/EntityTypeTest.php | 1 + src/Symfony/Bridge/Propel1/CHANGELOG.md | 3 + .../Form/ChoiceList/ModelChoiceList.php | 22 +- .../Bridge/Propel1/Form/PropelExtension.php | 3 +- .../Bridge/Propel1/Form/Type/ModelType.php | 19 +- .../Form/ChoiceList/ModelChoiceListTest.php | 4 + .../FrameworkBundle/Resources/config/form.xml | 5 + src/Symfony/Component/Form/CHANGELOG.md | 9 + .../Core/ChoiceList/ObjectChoiceList.php | 61 +- .../Form/Extension/Core/CoreExtension.php | 3 +- .../Core/DataMapper/PropertyPathMapper.php | 28 +- .../Form/Extension/Core/Type/FormType.php | 14 +- .../ViolationMapper/RelativePath.php | 2 +- .../ViolationMapper/ViolationMapper.php | 8 +- .../ViolationMapper/ViolationPath.php | 4 +- .../ViolationMapper/ViolationPathIterator.php | 2 +- src/Symfony/Component/Form/Form.php | 2 +- .../Component/Form/FormConfigBuilder.php | 4 +- .../Form/FormConfigBuilderInterface.php | 24 +- .../Component/Form/FormConfigInterface.php | 2 +- src/Symfony/Component/Form/FormInterface.php | 2 +- .../Core/ChoiceList/ObjectChoiceListTest.php | 3 + .../DataMapper/PropertyPathMapperTest.php | 66 +- .../Extension/Core/Type/ChoiceTypeTest.php | 2 - .../Extension/Core/Type/FormTypeTest.php | 2 +- .../EventListener/ValidationListenerTest.php | 2 +- .../ViolationMapper/ViolationMapperTest.php | 2 +- .../Component/Form/Tests/SimpleFormTest.php | 2 +- .../Form/Tests/Util/PropertyPathTest.php | 557 ---------------- src/Symfony/Component/Form/Util/FormUtil.php | 166 +---- .../Component/Form/Util/PropertyPath.php | 608 +----------------- .../Form/Util/PropertyPathBuilder.php | 284 +------- .../Form/Util/PropertyPathInterface.php | 75 +-- .../Form/Util/PropertyPathIterator.php | 41 +- .../Util/PropertyPathIteratorInterface.php | 31 +- src/Symfony/Component/Form/composer.json | 3 +- .../Component/PropertyAccess/.gitattributes | 2 + .../Component/PropertyAccess/.gitignore | 4 + .../Exception/ExceptionInterface.php} | 9 +- .../InvalidPropertyPathException.php} | 9 +- .../Exception/NoSuchPropertyException.php} | 9 +- .../Exception/OutOfBoundsException.php | 21 + .../PropertyAccessDeniedException.php | 21 + .../Exception/RuntimeException.php | 21 + .../Exception/UnexpectedTypeException.php | 25 + src/Symfony/Component/PropertyAccess/LICENSE | 19 + .../PropertyAccess/PropertyAccess.php | 37 ++ .../PropertyAccess/PropertyAccessor.php | 399 ++++++++++++ .../PropertyAccessorInterface.php | 84 +++ .../Component/PropertyAccess/PropertyPath.php | 225 +++++++ .../PropertyAccess/PropertyPathBuilder.php | 296 +++++++++ .../PropertyAccess/PropertyPathInterface.php | 86 +++ .../PropertyAccess/PropertyPathIterator.php | 55 ++ .../PropertyPathIteratorInterface.php | 34 + .../Component/PropertyAccess/README.md | 14 + .../Component/PropertyAccess/StringUtil.php | 192 ++++++ .../PropertyAccess/Tests/Fixtures/Author.php | 71 ++ .../Tests/Fixtures/Magician.php | 2 +- .../PropertyAccessorArrayObjectTest.php} | 4 +- .../Tests/PropertyAccessorArrayTest.php} | 4 +- .../Tests/PropertyAccessorCollectionTest.php} | 107 ++- ...PropertyAccessorCustomArrayObjectTest.php} | 4 +- .../Tests/PropertyAccessorTest.php | 334 ++++++++++ .../Tests}/PropertyPathBuilderTest.php | 6 +- .../PropertyAccess/Tests/PropertyPathTest.php | 191 ++++++ .../Tests/StringUtilTest.php} | 8 +- .../Component/PropertyAccess/composer.json | 31 + .../Component/PropertyAccess/phpunit.xml.dist | 29 + 73 files changed, 2706 insertions(+), 1890 deletions(-) delete mode 100644 src/Symfony/Component/Form/Tests/Util/PropertyPathTest.php create mode 100644 src/Symfony/Component/PropertyAccess/.gitattributes create mode 100644 src/Symfony/Component/PropertyAccess/.gitignore rename src/Symfony/Component/{Form/Exception/InvalidPropertyException.php => PropertyAccess/Exception/ExceptionInterface.php} (54%) rename src/Symfony/Component/{Form/Exception/PropertyAccessDeniedException.php => PropertyAccess/Exception/InvalidPropertyPathException.php} (52%) rename src/Symfony/Component/{Form/Exception/InvalidPropertyPathException.php => PropertyAccess/Exception/NoSuchPropertyException.php} (53%) create mode 100644 src/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php create mode 100644 src/Symfony/Component/PropertyAccess/Exception/PropertyAccessDeniedException.php create mode 100644 src/Symfony/Component/PropertyAccess/Exception/RuntimeException.php create mode 100644 src/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php create mode 100644 src/Symfony/Component/PropertyAccess/LICENSE create mode 100644 src/Symfony/Component/PropertyAccess/PropertyAccess.php create mode 100644 src/Symfony/Component/PropertyAccess/PropertyAccessor.php create mode 100644 src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php create mode 100644 src/Symfony/Component/PropertyAccess/PropertyPath.php create mode 100644 src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php create mode 100644 src/Symfony/Component/PropertyAccess/PropertyPathInterface.php create mode 100644 src/Symfony/Component/PropertyAccess/PropertyPathIterator.php create mode 100644 src/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php create mode 100644 src/Symfony/Component/PropertyAccess/README.md create mode 100644 src/Symfony/Component/PropertyAccess/StringUtil.php create mode 100644 src/Symfony/Component/PropertyAccess/Tests/Fixtures/Author.php rename src/Symfony/Component/{Form => PropertyAccess}/Tests/Fixtures/Magician.php (89%) rename src/Symfony/Component/{Form/Tests/Util/PropertyPathArrayObjectTest.php => PropertyAccess/Tests/PropertyAccessorArrayObjectTest.php} (73%) rename src/Symfony/Component/{Form/Tests/Util/PropertyPathArrayTest.php => PropertyAccess/Tests/PropertyAccessorArrayTest.php} (73%) rename src/Symfony/Component/{Form/Tests/Util/PropertyPathCollectionTest.php => PropertyAccess/Tests/PropertyAccessorCollectionTest.php} (73%) rename src/Symfony/Component/{Form/Tests/Util/PropertyPathCustomArrayObjectTest.php => PropertyAccess/Tests/PropertyAccessorCustomArrayObjectTest.php} (75%) create mode 100644 src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php rename src/Symfony/Component/{Form/Tests/Util => PropertyAccess/Tests}/PropertyPathBuilderTest.php (97%) create mode 100644 src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php rename src/Symfony/Component/{Form/Tests/Util/FormUtilTest.php => PropertyAccess/Tests/StringUtilTest.php} (95%) create mode 100644 src/Symfony/Component/PropertyAccess/composer.json create mode 100644 src/Symfony/Component/PropertyAccess/phpunit.xml.dist diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md index c485bf6112..33ed8c5700 100644 --- a/UPGRADE-2.2.md +++ b/UPGRADE-2.2.md @@ -84,6 +84,46 @@ {{ error.message }} ``` + * FormType, ModelType and PropertyPathMapper now have constructors. If you + extended these classes, you should call the parent constructor now. + Note that you are not recommended to extend FormType nor ModelType. You should + extend AbstractType instead and use the Form component's own inheritance + mechanism (`AbstractType::getParent()`). + + Before: + + ``` + use Symfony\Component\Form\Extensions\Core\DataMapper\PropertyPathMapper; + + class CustomMapper extends PropertyPathMapper + { + public function __construct() + { + // ... + } + + // ... + } + ``` + + After: + + ``` + use Symfony\Component\Form\Extensions\Core\DataMapper\PropertyPathMapper; + + class CustomMapper extends PropertyPathMapper + { + public function __construct() + { + parent::__construct(); + + // ... + } + + // ... + } + ``` + #### Deprecations * The methods `getParent()`, `setParent()` and `hasParent()` in @@ -91,6 +131,94 @@ You should not rely on these methods in your form type because the parent of a form can change after building it. + * The class PropertyPath and related classes were deprecated and moved to a + dedicated component PropertyAccess. If you used any of these classes or + interfaces, you should adapt the namespaces now. During the move, + InvalidPropertyException was renamed to NoSuchPropertyException. + + Before: + + ``` + use Symfony\Component\Form\Util\PropertyPath; + use Symfony\Component\Form\Util\PropertyPathBuilder; + use Symfony\Component\Form\Util\PropertyPathInterface; + use Symfony\Component\Form\Util\PropertyPathIterator; + use Symfony\Component\Form\Util\PropertyPathIteratorInterface; + use Symfony\Component\Form\Exception\InvalidPropertyException; + use Symfony\Component\Form\Exception\InvalidPropertyPathException; + use Symfony\Component\Form\Exception\PropertyAccessDeniedException; + ``` + + After: + + ``` + use Symfony\Component\PropertyAccess\PropertyPath; + use Symfony\Component\PropertyAccess\PropertyPathBuilder; + use Symfony\Component\PropertyAccess\PropertyPathInterface; + use Symfony\Component\PropertyAccess\PropertyPathIterator; + use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface; + use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; + use Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException; + use Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException; + ``` + + Also, `FormUtil::singularify()` was split away into a class StringUtil + in the new component. + + Before: + + ``` + use Symfony\Component\Form\Util\FormUtil; + + $singular = FormUtil::singularify($plural); + ``` + + After: + + ``` + use Symfony\Component\PropertyAccess\StringUtil; + + $singular = StringUtil::singularify($plural); + ``` + + The methods `getValue()` and `setValue()` were moved to a new class + PropertyAccessor. + + Before: + + ``` + use Symfony\Component\Form\Util\PropertyPath; + + $propertyPath = new PropertyPath('some.path'); + + $value = $propertyPath->getValue($object); + $propertyPath->setValue($object, 'new value'); + ``` + + After (alternative 1): + + ``` + use Symfony\Component\PropertyAccess\PropertyAccess; + + $accessor = PropertyAccess::getPropertyAccessor(); + + $value = $propertyAccessor->getValue($object, 'some.path'); + $accessor->setValue($object, 'some.path', 'new value'); + ``` + + After (alternative 2): + + ``` + use Symfony\Component\PropertyAccess\PropertyAccess; + use Symfony\Component\PropertyAccess\PropertyPath; + + $accessor = PropertyAccess::getPropertyAccessor(); + $propertyPath = new PropertyPath('some.path'); + + $value = $propertyAccessor->getValue($object, $propertyPath); + $accessor->setValue($object, $propertyPath, 'new value'); + ``` + ### Routing * RouteCollection does not behave like a tree structure anymore but as a flat diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index 6369ea3634..9c747b8abc 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +2.2.0 +----- + + * added an optional PropertyAccessorInterface parameter to DoctrineType, + EntityType and EntityChoiceList + 2.1.0 ----- diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php index 9cf636df95..16a65ebf40 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/EntityChoiceList.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\Exception\Exception; use Symfony\Component\Form\Exception\StringCastException; use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList; use Doctrine\Common\Persistence\ObjectManager; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * A choice list presenting a list of Doctrine entities as choices @@ -86,17 +87,18 @@ class EntityChoiceList extends ObjectChoiceList /** * Creates a new entity choice list. * - * @param ObjectManager $manager An EntityManager instance - * @param string $class The class name - * @param string $labelPath The property path used for the label - * @param EntityLoaderInterface $entityLoader An optional query builder - * @param array $entities An array of choices - * @param array $preferredEntities An array of preferred choices - * @param string $groupPath A property path pointing to the property used - * to group the choices. Only allowed if - * the choices are given as flat array. + * @param ObjectManager $manager An EntityManager instance + * @param string $class The class name + * @param string $labelPath The property path used for the label + * @param EntityLoaderInterface $entityLoader An optional query builder + * @param array $entities An array of choices + * @param array $preferredEntities An array of preferred choices + * @param string $groupPath A property path pointing to the property used + * to group the choices. Only allowed if + * the choices are given as flat array. + * @param PropertyAccessorInterface $propertyAccessor The reflection graph for reading property paths. */ - public function __construct(ObjectManager $manager, $class, $labelPath = null, EntityLoaderInterface $entityLoader = null, $entities = null, array $preferredEntities = array(), $groupPath = null) + public function __construct(ObjectManager $manager, $class, $labelPath = null, EntityLoaderInterface $entityLoader = null, $entities = null, array $preferredEntities = array(), $groupPath = null, PropertyAccessorInterface $propertyAccessor = null) { $this->em = $manager; $this->entityLoader = $entityLoader; @@ -122,7 +124,7 @@ class EntityChoiceList extends ObjectChoiceList $entities = array(); } - parent::__construct($entities, $labelPath, $preferredEntities, $groupPath); + parent::__construct($entities, $labelPath, $preferredEntities, $groupPath, null, $propertyAccessor); } /** diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php index 7c9941c29a..a98b2d2a24 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php @@ -13,6 +13,7 @@ namespace Symfony\Bridge\Doctrine\Form; use Doctrine\Common\Persistence\ManagerRegistry; use Symfony\Component\Form\AbstractExtension; +use Symfony\Component\PropertyAccess\PropertyAccess; class DoctrineOrmExtension extends AbstractExtension { @@ -26,7 +27,7 @@ class DoctrineOrmExtension extends AbstractExtension protected function loadTypes() { return array( - new Type\EntityType($this->registry), + new Type\EntityType($this->registry, PropertyAccess::getPropertyAccessor()), ); } diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index 8180d1a67c..df6f2077f8 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -22,6 +22,8 @@ use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; abstract class DoctrineType extends AbstractType { @@ -35,9 +37,15 @@ abstract class DoctrineType extends AbstractType */ private $choiceListCache = array(); - public function __construct(ManagerRegistry $registry) + /** + * @var PropertyAccessorInterface + */ + private $propertyAccessor; + + public function __construct(ManagerRegistry $registry, PropertyAccessorInterface $propertyAccessor = null) { $this->registry = $registry; + $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor(); } public function buildForm(FormBuilderInterface $builder, array $options) @@ -54,6 +62,7 @@ abstract class DoctrineType extends AbstractType { $choiceListCache =& $this->choiceListCache; $registry = $this->registry; + $propertyAccessor = $this->propertyAccessor; $type = $this; $loader = function (Options $options) use ($type) { @@ -64,7 +73,7 @@ abstract class DoctrineType extends AbstractType return null; }; - $choiceList = function (Options $options) use (&$choiceListCache, &$time) { + $choiceList = function (Options $options) use (&$choiceListCache, $propertyAccessor) { // Support for closures $propertyHash = is_object($options['property']) ? spl_object_hash($options['property']) @@ -118,7 +127,8 @@ abstract class DoctrineType extends AbstractType $options['loader'], $options['choices'], $options['preferred_choices'], - $options['group_by'] + $options['group_by'], + $propertyAccessor ); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index cf4606f9d4..6fdcf66f24 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -90,6 +90,7 @@ class EntityTypeTest extends TypeTestCase parent::tearDown(); $this->em = null; + $this->emRegistry = null; } protected function getExtensions() diff --git a/src/Symfony/Bridge/Propel1/CHANGELOG.md b/src/Symfony/Bridge/Propel1/CHANGELOG.md index b549e027c3..242d576c33 100644 --- a/src/Symfony/Bridge/Propel1/CHANGELOG.md +++ b/src/Symfony/Bridge/Propel1/CHANGELOG.md @@ -5,6 +5,9 @@ CHANGELOG ----- * added a collection type for the I18n behavior + * added an optional PropertyAccessorInterface parameter to ModelType and + ModelChoiceList + * [BC BREAK] ModelType now has a constructor 2.1.0 ----- diff --git a/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php b/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php index 04ec7a8c62..e33934fbff 100644 --- a/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php +++ b/src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php @@ -18,6 +18,7 @@ use \Persistent; use Symfony\Component\Form\Exception\FormException; use Symfony\Component\Form\Exception\StringCastException; use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * Widely inspired by the EntityChoiceList. @@ -69,16 +70,17 @@ class ModelChoiceList extends ObjectChoiceList * * @see Symfony\Bridge\Propel1\Form\Type\ModelType How to use the preferred choices. * - * @param string $class The FQCN of the model class to be loaded. - * @param string $labelPath A property path pointing to the property used for the choice labels. - * @param array $choices An optional array to use, rather than fetching the models. - * @param ModelCriteria $queryObject The query to use retrieving model data from database. - * @param string $groupPath A property path pointing to the property used to group the choices. - * @param array|ModelCriteria $preferred The preferred items of this choice. - * Either an array if $choices is given, - * or a ModelCriteria to be merged with the $queryObject. + * @param string $class The FQCN of the model class to be loaded. + * @param string $labelPath A property path pointing to the property used for the choice labels. + * @param array $choices An optional array to use, rather than fetching the models. + * @param ModelCriteria $queryObject The query to use retrieving model data from database. + * @param string $groupPath A property path pointing to the property used to group the choices. + * @param array|ModelCriteria $preferred The preferred items of this choice. + * Either an array if $choices is given, + * or a ModelCriteria to be merged with the $queryObject. + * @param PropertyAccessorInterface $propertyAccessor The reflection graph for reading property paths. */ - public function __construct($class, $labelPath = null, $choices = null, $queryObject = null, $groupPath = null, $preferred = array()) + public function __construct($class, $labelPath = null, $choices = null, $queryObject = null, $groupPath = null, $preferred = array(), PropertyAccessorInterface $propertyAccessor = null) { $this->class = $class; @@ -104,7 +106,7 @@ class ModelChoiceList extends ObjectChoiceList $this->identifierAsIndex = true; } - parent::__construct($choices, $labelPath, $preferred, $groupPath); + parent::__construct($choices, $labelPath, $preferred, $groupPath, null, $propertyAccessor); } /** diff --git a/src/Symfony/Bridge/Propel1/Form/PropelExtension.php b/src/Symfony/Bridge/Propel1/Form/PropelExtension.php index 408fc7f008..b238a5e6ff 100644 --- a/src/Symfony/Bridge/Propel1/Form/PropelExtension.php +++ b/src/Symfony/Bridge/Propel1/Form/PropelExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Propel1\Form; use Symfony\Component\Form\AbstractExtension; +use Symfony\Component\PropertyAccess\PropertyAccess; /** * Represents the Propel form extension, which loads the Propel functionality. @@ -23,7 +24,7 @@ class PropelExtension extends AbstractExtension protected function loadTypes() { return array( - new Type\ModelType(), + new Type\ModelType(PropertyAccess::getPropertyAccessor()), new Type\TranslationCollectionType(), new Type\TranslationType() ); diff --git a/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php b/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php index faf5f25f1c..16d633cda2 100644 --- a/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php +++ b/src/Symfony/Bridge/Propel1/Form/Type/ModelType.php @@ -17,6 +17,8 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * ModelType class. @@ -48,6 +50,16 @@ use Symfony\Component\OptionsResolver\OptionsResolverInterface; */ class ModelType extends AbstractType { + /** + * @var PropertyAccessorInterface + */ + private $propertyAccessor; + + public function __construct(PropertyAccessorInterface $propertyAccessor = null) + { + $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor(); + } + public function buildForm(FormBuilderInterface $builder, array $options) { if ($options['multiple']) { @@ -57,14 +69,17 @@ class ModelType extends AbstractType public function setDefaultOptions(OptionsResolverInterface $resolver) { - $choiceList = function (Options $options) { + $propertyAccessor = $this->propertyAccessor; + + $choiceList = function (Options $options) use ($propertyAccessor) { return new ModelChoiceList( $options['class'], $options['property'], $options['choices'], $options['query'], $options['group_by'], - $options['preferred_choices'] + $options['preferred_choices'], + $propertyAccessor ); }; diff --git a/src/Symfony/Bridge/Propel1/Tests/Form/ChoiceList/ModelChoiceListTest.php b/src/Symfony/Bridge/Propel1/Tests/Form/ChoiceList/ModelChoiceListTest.php index 6675eac727..748b1cd9b1 100644 --- a/src/Symfony/Bridge/Propel1/Tests/Form/ChoiceList/ModelChoiceListTest.php +++ b/src/Symfony/Bridge/Propel1/Tests/Form/ChoiceList/ModelChoiceListTest.php @@ -26,6 +26,10 @@ class ModelChoiceListTest extends Propel1TestCase if (!class_exists('Symfony\Component\Form\Form')) { $this->markTestSkipped('The "Form" component is not available'); } + + if (!class_exists('Symfony\Component\PropertyAccess\PropertyAccessor')) { + $this->markTestSkipped('The "PropertyAccessor" component is not available'); + } } public function testEmptyChoicesReturnsEmpty() diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml index d2df3eb60e..d614e4dc50 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form.xml @@ -10,6 +10,7 @@ Symfony\Component\Form\FormFactory Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser + Symfony\Component\PropertyAccess\PropertyAccessor @@ -53,11 +54,15 @@ + + + + diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index d8e309637f..67f8e3c18e 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -13,6 +13,15 @@ CHANGELOG * [BC BREAK] FormException is now an interface * protected FormBuilder methods from being called when it is turned into a FormConfigInterface with getFormConfig() * [BC BREAK] inserted argument `$message` in the constructor of `FormError` + * the PropertyPath class and related classes were moved to a dedicated + PropertyAccess component. During the move, InvalidPropertyException was + renamed to NoSuchPropertyException. FormUtil was split: FormUtil::singularify() + can now be found in Symfony\Component\PropertyAccess\StringUtil. The methods + getValue() and setValue() from PropertyPath were extracted into a new class + PropertyAccessor. + * added an optional PropertyAccessorInterface parameter to FormType, + ObjectChoiceList and PropertyPathMapper + * [BC BREAK] PropertyPathMapper and FormType now have a constructor 2.1.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php b/src/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php index eeb6b646c3..04be48ace4 100644 --- a/src/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php +++ b/src/Symfony/Component/Form/Extension/Core/ChoiceList/ObjectChoiceList.php @@ -11,9 +11,11 @@ namespace Symfony\Component\Form\Extension\Core\ChoiceList; -use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\Form\Exception\StringCastException; -use Symfony\Component\Form\Exception\InvalidPropertyException; +use Symfony\Component\PropertyAccess\PropertyPath; +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; /** * A choice list for object choices. @@ -32,6 +34,11 @@ use Symfony\Component\Form\Exception\InvalidPropertyException; */ class ObjectChoiceList extends ChoiceList { + /** + * @var PropertyAccessorInterface + */ + private $propertyAccessor; + /** * The property path used to obtain the choice label. * @@ -56,28 +63,30 @@ class ObjectChoiceList extends ChoiceList /** * Creates a new object choice list. * - * @param array|\Traversable $choices The array of choices. Choices may also be given - * as hierarchy of unlimited depth by creating nested - * arrays. The title of the sub-hierarchy can be - * stored in the array key pointing to the nested - * array. The topmost level of the hierarchy may also - * be a \Traversable. - * @param string $labelPath A property path pointing to the property used - * for the choice labels. The value is obtained - * by calling the getter on the object. If the - * path is NULL, the object's __toString() method - * is used instead. - * @param array $preferredChoices A flat array of choices that should be - * presented to the user with priority. - * @param string $groupPath A property path pointing to the property used - * to group the choices. Only allowed if - * the choices are given as flat array. - * @param string $valuePath A property path pointing to the property used - * for the choice values. If not given, integers - * are generated instead. + * @param array|\Traversable $choices The array of choices. Choices may also be given + * as hierarchy of unlimited depth by creating nested + * arrays. The title of the sub-hierarchy can be + * stored in the array key pointing to the nested + * array. The topmost level of the hierarchy may also + * be a \Traversable. + * @param string $labelPath A property path pointing to the property used + * for the choice labels. The value is obtained + * by calling the getter on the object. If the + * path is NULL, the object's __toString() method + * is used instead. + * @param array $preferredChoices A flat array of choices that should be + * presented to the user with priority. + * @param string $groupPath A property path pointing to the property used + * to group the choices. Only allowed if + * the choices are given as flat array. + * @param string $valuePath A property path pointing to the property used + * for the choice values. If not given, integers + * are generated instead. + * @param PropertyAccessorInterface $propertyAccessor The reflection graph for reading property paths. */ - public function __construct($choices, $labelPath = null, array $preferredChoices = array(), $groupPath = null, $valuePath = null) + public function __construct($choices, $labelPath = null, array $preferredChoices = array(), $groupPath = null, $valuePath = null, PropertyAccessorInterface $propertyAccessor = null) { + $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor(); $this->labelPath = null !== $labelPath ? new PropertyPath($labelPath) : null; $this->groupPath = null !== $groupPath ? new PropertyPath($groupPath) : null; $this->valuePath = null !== $valuePath ? new PropertyPath($valuePath) : null; @@ -108,8 +117,8 @@ class ObjectChoiceList extends ChoiceList } try { - $group = $this->groupPath->getValue($choice); - } catch (InvalidPropertyException $e) { + $group = $this->propertyAccessor->getValue($choice, $this->groupPath); + } catch (NoSuchPropertyException $e) { // Don't group items whose group property does not exist // see https://github.com/symfony/symfony/commit/d9b7abb7c7a0f28e0ce970afc5e305dce5dccddf $group = null; @@ -150,7 +159,7 @@ class ObjectChoiceList extends ChoiceList protected function createValue($choice) { if ($this->valuePath) { - return (string) $this->valuePath->getValue($choice); + return (string) $this->propertyAccessor->getValue($choice, $this->valuePath); } return parent::createValue($choice); @@ -163,7 +172,7 @@ class ObjectChoiceList extends ChoiceList $labels[$i] = array(); $this->extractLabels($choice, $labels[$i]); } elseif ($this->labelPath) { - $labels[$i] = $this->labelPath->getValue($choice); + $labels[$i] = $this->propertyAccessor->getValue($choice, $this->labelPath); } elseif (method_exists($choice, '__toString')) { $labels[$i] = (string) $choice; } else { diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php index f0f0d181da..ab6529d6dc 100644 --- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php +++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Extension\Core; use Symfony\Component\Form\AbstractExtension; +use Symfony\Component\PropertyAccess\PropertyAccess; /** * Represents the main form extension, which loads the core functionality. @@ -24,7 +25,7 @@ class CoreExtension extends AbstractExtension { return array( new Type\FieldType(), - new Type\FormType(), + new Type\FormType(PropertyAccess::getPropertyAccessor()), new Type\BirthdayType(), new Type\CheckboxType(), new Type\ChoiceType(), diff --git a/src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php b/src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php index ce850eaac7..f691ecca21 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php +++ b/src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php @@ -14,9 +14,31 @@ namespace Symfony\Component\Form\Extension\Core\DataMapper; use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Util\VirtualFormAwareIterator; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +/** + * A data mapper using property paths to read/write data. + * + * @author Bernhard Schussek + */ class PropertyPathMapper implements DataMapperInterface { + /** + * @var PropertyAccessorInterface + */ + private $propertyAccessor; + + /** + * Creates a new property path mapper. + * + * @param PropertyAccessorInterface $propertyAccessor + */ + public function __construct(PropertyAccessorInterface $propertyAccessor = null) + { + $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor(); + } + /** * {@inheritdoc} */ @@ -39,7 +61,7 @@ class PropertyPathMapper implements DataMapperInterface $config = $form->getConfig(); if (null !== $propertyPath && $config->getMapped()) { - $form->setData($propertyPath->getValue($data)); + $form->setData($this->propertyAccessor->getValue($data, $propertyPath)); } } } @@ -70,8 +92,8 @@ class PropertyPathMapper implements DataMapperInterface if (null !== $propertyPath && $config->getMapped() && $form->isSynchronized() && !$form->isDisabled()) { // If the data is identical to the value in $data, we are // dealing with a reference - if (!is_object($data) || !$config->getByReference() || $form->getData() !== $propertyPath->getValue($data)) { - $propertyPath->setValue($data, $form->getData()); + if (!is_object($data) || !$config->getByReference() || $form->getData() !== $this->propertyAccessor->getValue($data, $propertyPath)) { + $this->propertyAccessor->setValue($data, $propertyPath, $form->getData()); } } } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 0b9c38df90..44b60aaf86 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -20,9 +20,21 @@ use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Exception\Exception; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; class FormType extends AbstractType { + /** + * @var PropertyAccessorInterface + */ + private $propertyAccessor; + + public function __construct(PropertyAccessorInterface $propertyAccessor = null) + { + $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::getPropertyAccessor(); + } + /** * {@inheritdoc} */ @@ -41,7 +53,7 @@ class FormType extends AbstractType ->setCompound($options['compound']) ->setData(isset($options['data']) ? $options['data'] : null) ->setDataLocked(isset($options['data'])) - ->setDataMapper($options['compound'] ? new PropertyPathMapper() : null) + ->setDataMapper($options['compound'] ? new PropertyPathMapper($this->propertyAccessor) : null) ; if ($options['trim']) { diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php index 8f487bcc15..ef5c9fad05 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/RelativePath.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\Form\FormInterface; -use Symfony\Component\Form\Util\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPath; /** * @author Bernhard Schussek diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php index cece98804e..61d08c3e5d 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php @@ -13,9 +13,9 @@ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\Util\VirtualFormAwareIterator; -use Symfony\Component\Form\Util\PropertyPathIterator; -use Symfony\Component\Form\Util\PropertyPathBuilder; -use Symfony\Component\Form\Util\PropertyPathIteratorInterface; +use Symfony\Component\PropertyAccess\PropertyPathIterator; +use Symfony\Component\PropertyAccess\PropertyPathBuilder; +use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface; use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationPathIterator; use Symfony\Component\Form\FormError; use Symfony\Component\Validator\ConstraintViolation; @@ -265,7 +265,7 @@ class ViolationMapper implements ViolationMapperInterface $propertyPathBuilder->remove(0, $i + 1); $i = 0; } else { - /* @var \Symfony\Component\Form\Util\PropertyPathInterface $propertyPath */ + /* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */ $propertyPath = $scope->getPropertyPath(); if (null === $propertyPath) { diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php index 65cbda6b18..9c99e8618f 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPath.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; -use Symfony\Component\Form\Util\PropertyPath; -use Symfony\Component\Form\Util\PropertyPathInterface; +use Symfony\Component\PropertyAccess\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPathInterface; /** * @author Bernhard Schussek diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php index 531da861eb..50baa4533e 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationPathIterator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Extension\Validator\ViolationMapper; -use Symfony\Component\Form\Util\PropertyPathIterator; +use Symfony\Component\PropertyAccess\PropertyPathIterator; /** * @author Bernhard Schussek diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index eb93637877..7a49822425 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -16,8 +16,8 @@ use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Exception\AlreadyBoundException; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Util\FormUtil; -use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\PropertyAccess\PropertyPath; /** * Form represents a form. diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index 1b428194f8..5d1f3a2331 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -14,8 +14,8 @@ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\Exception; use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\Util\PropertyPath; -use Symfony\Component\Form\Util\PropertyPathInterface; +use Symfony\Component\PropertyAccess\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPathInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\ImmutableEventDispatcher; diff --git a/src/Symfony/Component/Form/FormConfigBuilderInterface.php b/src/Symfony/Component/Form/FormConfigBuilderInterface.php index 496fc38c66..c63f0e8aaa 100644 --- a/src/Symfony/Component/Form/FormConfigBuilderInterface.php +++ b/src/Symfony/Component/Form/FormConfigBuilderInterface.php @@ -117,7 +117,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Sets the data mapper used by the form. * - * @param DataMapperInterface $dataMapper + * @param DataMapperInterface $dataMapper * * @return self The configuration object. */ @@ -126,7 +126,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Set whether the form is disabled. * - * @param Boolean $disabled Whether the form is disabled + * @param Boolean $disabled Whether the form is disabled * * @return self The configuration object. */ @@ -135,7 +135,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Sets the data used for the client data when no value is bound. * - * @param mixed $emptyData The empty data. + * @param mixed $emptyData The empty data. * * @return self The configuration object. */ @@ -144,7 +144,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Sets whether errors bubble up to the parent. * - * @param Boolean $errorBubbling + * @param Boolean $errorBubbling * * @return self The configuration object. */ @@ -162,9 +162,9 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Sets the property path that the form should be mapped to. * - * @param null|string|PropertyPathInterface $propertyPath The property path or null if the path - * should be set automatically based on - * the form's name. + * @param null|string|\Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath + * The property path or null if the path should be set + * automatically based on the form's name. * * @return self The configuration object. */ @@ -174,7 +174,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface * Sets whether the form should be mapped to an element of its * parent's data. * - * @param Boolean $mapped Whether the form should be mapped. + * @param Boolean $mapped Whether the form should be mapped. * * @return self The configuration object. */ @@ -183,7 +183,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Sets whether the form's data should be modified by reference. * - * @param Boolean $byReference Whether the data should be + * @param Boolean $byReference Whether the data should be * modified by reference. * * @return self The configuration object. @@ -193,7 +193,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Sets whether the form should be virtual. * - * @param Boolean $virtual Whether the form should be virtual. + * @param Boolean $virtual Whether the form should be virtual. * * @return self The configuration object. */ @@ -202,7 +202,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface /** * Sets whether the form should be compound. * - * @param Boolean $compound Whether the form should be compound. + * @param Boolean $compound Whether the form should be compound. * * @return self The configuration object. * @@ -235,7 +235,7 @@ interface FormConfigBuilderInterface extends FormConfigInterface * this configuration. The data can only be modified then by * binding the form. * - * @param Boolean $locked Whether to lock the default data. + * @param Boolean $locked Whether to lock the default data. * * @return self The configuration object. */ diff --git a/src/Symfony/Component/Form/FormConfigInterface.php b/src/Symfony/Component/Form/FormConfigInterface.php index b5d914f6d3..0a27c2a7fb 100644 --- a/src/Symfony/Component/Form/FormConfigInterface.php +++ b/src/Symfony/Component/Form/FormConfigInterface.php @@ -35,7 +35,7 @@ interface FormConfigInterface /** * Returns the property path that the form should be mapped to. * - * @return null|Util\PropertyPathInterface The property path. + * @return null|\Symfony\Component\PropertyAccess\PropertyPathInterface The property path. */ public function getPropertyPath(); diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php index d217a07dd1..94f6b3e29d 100644 --- a/src/Symfony/Component/Form/FormInterface.php +++ b/src/Symfony/Component/Form/FormInterface.php @@ -166,7 +166,7 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable /** * Returns the property path that the form is mapped to. * - * @return Util\PropertyPathInterface The property path. + * @return \Symfony\Component\PropertyAccess\PropertyPathInterface The property path. */ public function getPropertyPath(); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php index ff449610a5..b7487377e6 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/ChoiceList/ObjectChoiceListTest.php @@ -39,6 +39,9 @@ class ObjectChoiceListTest extends \PHPUnit_Framework_TestCase private $obj4; + /** + * @var ObjectChoiceList + */ private $list; protected function setUp() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php index 05d2fe1577..8af2fd5f07 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php @@ -11,10 +11,8 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataMapper; -use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormConfigInterface; -use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase @@ -29,14 +27,24 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase */ private $dispatcher; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $propertyAccessor; + protected function setUp() { if (!class_exists('Symfony\Component\EventDispatcher\Event')) { $this->markTestSkipped('The "EventDispatcher" component is not available'); } + if (!class_exists('Symfony\Component\PropertyAccess\PropertyAccess')) { + $this->markTestSkipped('The "PropertyAccess" component is not available'); + } + $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); - $this->mapper = new PropertyPathMapper(); + $this->propertyAccessor = $this->getMock('Symfony\Component\PropertyAccess\PropertyAccessorInterface'); + $this->mapper = new PropertyPathMapper($this->propertyAccessor); } /** @@ -45,7 +53,7 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase */ private function getPropertyPath($path) { - return $this->getMockBuilder('Symfony\Component\Form\Util\PropertyPath') + return $this->getMockBuilder('Symfony\Component\PropertyAccess\PropertyPath') ->setConstructorArgs(array($path)) ->setMethods(array('getValue', 'setValue')) ->getMock(); @@ -84,9 +92,9 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->once()) + $this->propertyAccessor->expects($this->once()) ->method('getValue') - ->with($car) + ->with($car, $propertyPath) ->will($this->returnValue($engine)); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -107,9 +115,9 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->once()) + $this->propertyAccessor->expects($this->once()) ->method('getValue') - ->with($car) + ->with($car, $propertyPath) ->will($this->returnValue($engine)); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -143,7 +151,7 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $car = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->never()) + $this->propertyAccessor->expects($this->never()) ->method('getValue'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -161,7 +169,7 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase { $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->never()) + $this->propertyAccessor->expects($this->never()) ->method('getValue'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -180,9 +188,9 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->once()) + $this->propertyAccessor->expects($this->once()) ->method('getValue') - ->with($car) + ->with($car, $propertyPath) ->will($this->returnValue($engine)); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -211,9 +219,9 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->once()) + $this->propertyAccessor->expects($this->once()) ->method('setValue') - ->with($car, $engine); + ->with($car, $propertyPath, $engine); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(false); @@ -230,9 +238,9 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->once()) + $this->propertyAccessor->expects($this->once()) ->method('setValue') - ->with($car, $engine); + ->with($car, $propertyPath, $engine); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); @@ -250,12 +258,12 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $propertyPath = $this->getPropertyPath('engine'); // $car already contains the reference of $engine - $propertyPath->expects($this->once()) + $this->propertyAccessor->expects($this->once()) ->method('getValue') - ->with($car) + ->with($car, $propertyPath) ->will($this->returnValue($engine)); - $propertyPath->expects($this->never()) + $this->propertyAccessor->expects($this->never()) ->method('setValue'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -273,7 +281,7 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->never()) + $this->propertyAccessor->expects($this->never()) ->method('setValue'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -291,7 +299,7 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $car = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->never()) + $this->propertyAccessor->expects($this->never()) ->method('setValue'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -309,7 +317,7 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->never()) + $this->propertyAccessor->expects($this->never()) ->method('setValue'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -327,7 +335,7 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $engine = new \stdClass(); $propertyPath = $this->getPropertyPath('engine'); - $propertyPath->expects($this->never()) + $this->propertyAccessor->expects($this->never()) ->method('setValue'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); @@ -347,14 +355,14 @@ class PropertyPathMapperTest extends \PHPUnit_Framework_TestCase $parentPath = $this->getPropertyPath('name'); $childPath = $this->getPropertyPath('engine'); - $parentPath->expects($this->never()) - ->method('getValue'); - $parentPath->expects($this->never()) - ->method('setValue'); + // getValue() and setValue() must never be invoked for $parentPath - $childPath->expects($this->once()) + $this->propertyAccessor->expects($this->once()) + ->method('getValue') + ->with($car, $childPath); + $this->propertyAccessor->expects($this->once()) ->method('setValue') - ->with($car, $engine); + ->with($car, $childPath, $engine); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setPropertyPath($parentPath); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 61ce5e7c58..3b32ab38e8 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; -use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList; - use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList; use Symfony\Component\Form\Extension\Core\View\ChoiceView; diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 65c7b68693..fae4ae3e5b 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; -use Symfony\Component\Form\Util\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\Form\Form; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Tests\Fixtures\Author; diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php index d9555e13e1..77420ebb9f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; -use Symfony\Component\Form\Util\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener; use Symfony\Component\Validator\ConstraintViolation; diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php index 2f41a99101..ac529b213f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php @@ -17,7 +17,7 @@ use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormError; -use Symfony\Component\Form\Util\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\Validator\ConstraintViolation; /** diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 0d72df3acb..102c973fd4 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Form\Tests; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; -use Symfony\Component\Form\Util\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormError; use Symfony\Component\Form\Exception\TransformationFailedException; diff --git a/src/Symfony/Component/Form/Tests/Util/PropertyPathTest.php b/src/Symfony/Component/Form/Tests/Util/PropertyPathTest.php deleted file mode 100644 index e9be1445e6..0000000000 --- a/src/Symfony/Component/Form/Tests/Util/PropertyPathTest.php +++ /dev/null @@ -1,557 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Tests\Util; - -use Symfony\Component\Form\Util\PropertyPath; -use Symfony\Component\Form\Tests\Fixtures\Author; -use Symfony\Component\Form\Tests\Fixtures\Magician; - -class PropertyPathTest extends \PHPUnit_Framework_TestCase -{ - public function testGetValueReadsArray() - { - $array = array('firstName' => 'Bernhard'); - - $path = new PropertyPath('[firstName]'); - - $this->assertEquals('Bernhard', $path->getValue($array)); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyException - */ - public function testGetValueThrowsExceptionIfIndexNotationExpected() - { - $array = array('firstName' => 'Bernhard'); - - $path = new PropertyPath('firstName'); - - $path->getValue($array); - } - - public function testGetValueReadsZeroIndex() - { - $array = array('Bernhard'); - - $path = new PropertyPath('[0]'); - - $this->assertEquals('Bernhard', $path->getValue($array)); - } - - public function testGetValueReadsIndexWithSpecialChars() - { - $array = array('%!@$§.' => 'Bernhard'); - - $path = new PropertyPath('[%!@$§.]'); - - $this->assertEquals('Bernhard', $path->getValue($array)); - } - - public function testGetValueReadsNestedIndexWithSpecialChars() - { - $array = array('root' => array('%!@$§.' => 'Bernhard')); - - $path = new PropertyPath('[root][%!@$§.]'); - - $this->assertEquals('Bernhard', $path->getValue($array)); - } - - public function testGetValueReadsArrayWithCustomPropertyPath() - { - $array = array('child' => array('index' => array('firstName' => 'Bernhard'))); - - $path = new PropertyPath('[child][index][firstName]'); - - $this->assertEquals('Bernhard', $path->getValue($array)); - } - - public function testGetValueReadsArrayWithMissingIndexForCustomPropertyPath() - { - $array = array('child' => array('index' => array())); - - $path = new PropertyPath('[child][index][firstName]'); - - $this->assertNull($path->getValue($array)); - } - - public function testGetValueReadsProperty() - { - $object = new Author(); - $object->firstName = 'Bernhard'; - - $path = new PropertyPath('firstName'); - - $this->assertEquals('Bernhard', $path->getValue($object)); - } - - public function testGetValueIgnoresSingular() - { - $this->markTestSkipped('This feature is temporarily disabled as of 2.1'); - - $object = (object) array('children' => 'Many'); - - $path = new PropertyPath('children|child'); - - $this->assertEquals('Many', $path->getValue($object)); - } - - public function testGetValueReadsPropertyWithSpecialCharsExceptDot() - { - $array = (object) array('%!@$§' => 'Bernhard'); - - $path = new PropertyPath('%!@$§'); - - $this->assertEquals('Bernhard', $path->getValue($array)); - } - - public function testGetValueReadsPropertyWithCustomPropertyPath() - { - $object = new Author(); - $object->child = array(); - $object->child['index'] = new Author(); - $object->child['index']->firstName = 'Bernhard'; - - $path = new PropertyPath('child[index].firstName'); - - $this->assertEquals('Bernhard', $path->getValue($object)); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\PropertyAccessDeniedException - */ - public function testGetValueThrowsExceptionIfPropertyIsNotPublic() - { - $path = new PropertyPath('privateProperty'); - - $path->getValue(new Author()); - } - - public function testGetValueReadsGetters() - { - $path = new PropertyPath('lastName'); - - $object = new Author(); - $object->setLastName('Schussek'); - - $this->assertEquals('Schussek', $path->getValue($object)); - } - - public function testGetValueCamelizesGetterNames() - { - $path = new PropertyPath('last_name'); - - $object = new Author(); - $object->setLastName('Schussek'); - - $this->assertEquals('Schussek', $path->getValue($object)); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\PropertyAccessDeniedException - */ - public function testGetValueThrowsExceptionIfGetterIsNotPublic() - { - $path = new PropertyPath('privateGetter'); - - $path->getValue(new Author()); - } - - public function testGetValueReadsIssers() - { - $path = new PropertyPath('australian'); - - $object = new Author(); - $object->setAustralian(false); - - $this->assertFalse($path->getValue($object)); - } - - public function testGetValueReadHassers() - { - $path = new PropertyPath('read_permissions'); - - $object = new Author(); - $object->setReadPermissions(true); - - $this->assertTrue($path->getValue($object)); - } - - public function testGetValueReadsMagicGet() - { - $path = new PropertyPath('magicProperty'); - - $object = new Magician(); - $object->__set('magicProperty', 'foobar'); - - $this->assertSame('foobar', $path->getValue($object)); - } - - /* - * https://github.com/symfony/symfony/pull/4450 - */ - public function testGetValueReadsMagicGetThatReturnsConstant() - { - $path = new PropertyPath('magicProperty'); - - $object = new Magician(); - - $this->assertNull($path->getValue($object)); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\PropertyAccessDeniedException - */ - public function testGetValueThrowsExceptionIfIsserIsNotPublic() - { - $path = new PropertyPath('privateIsser'); - - $path->getValue(new Author()); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyException - */ - public function testGetValueThrowsExceptionIfPropertyDoesNotExist() - { - $path = new PropertyPath('foobar'); - - $path->getValue(new Author()); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testGetValueThrowsExceptionIfNotObjectOrArray() - { - $path = new PropertyPath('foobar'); - - $path->getValue('baz'); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testGetValueThrowsExceptionIfNull() - { - $path = new PropertyPath('foobar'); - - $path->getValue(null); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testGetValueThrowsExceptionIfEmpty() - { - $path = new PropertyPath('foobar'); - - $path->getValue(''); - } - - public function testSetValueUpdatesArrays() - { - $array = array(); - - $path = new PropertyPath('[firstName]'); - $path->setValue($array, 'Bernhard'); - - $this->assertEquals(array('firstName' => 'Bernhard'), $array); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyException - */ - public function testSetValueThrowsExceptionIfIndexNotationExpected() - { - $array = array(); - - $path = new PropertyPath('firstName'); - $path->setValue($array, 'Bernhard'); - } - - public function testSetValueUpdatesArraysWithCustomPropertyPath() - { - $array = array(); - - $path = new PropertyPath('[child][index][firstName]'); - $path->setValue($array, 'Bernhard'); - - $this->assertEquals(array('child' => array('index' => array('firstName' => 'Bernhard'))), $array); - } - - public function testSetValueUpdatesProperties() - { - $object = new Author(); - - $path = new PropertyPath('firstName'); - $path->setValue($object, 'Bernhard'); - - $this->assertEquals('Bernhard', $object->firstName); - } - - public function testSetValueUpdatesPropertiesWithCustomPropertyPath() - { - $object = new Author(); - $object->child = array(); - $object->child['index'] = new Author(); - - $path = new PropertyPath('child[index].firstName'); - $path->setValue($object, 'Bernhard'); - - $this->assertEquals('Bernhard', $object->child['index']->firstName); - } - - public function testSetValueUpdateMagicSet() - { - $object = new Magician(); - - $path = new PropertyPath('magicProperty'); - $path->setValue($object, 'foobar'); - - $this->assertEquals('foobar', $object->__get('magicProperty')); - } - - public function testSetValueUpdatesSetters() - { - $object = new Author(); - - $path = new PropertyPath('lastName'); - $path->setValue($object, 'Schussek'); - - $this->assertEquals('Schussek', $object->getLastName()); - } - - public function testSetValueCamelizesSetterNames() - { - $object = new Author(); - - $path = new PropertyPath('last_name'); - $path->setValue($object, 'Schussek'); - - $this->assertEquals('Schussek', $object->getLastName()); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\PropertyAccessDeniedException - */ - public function testSetValueThrowsExceptionIfGetterIsNotPublic() - { - $path = new PropertyPath('privateSetter'); - - $path->setValue(new Author(), 'foobar'); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testSetValueThrowsExceptionIfNotObjectOrArray() - { - $path = new PropertyPath('foobar'); - $value = 'baz'; - - $path->setValue($value, 'bam'); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testSetValueThrowsExceptionIfNull() - { - $path = new PropertyPath('foobar'); - $value = null; - - $path->setValue($value, 'bam'); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testSetValueThrowsExceptionIfEmpty() - { - $path = new PropertyPath('foobar'); - $value = ''; - - $path->setValue($value, 'bam'); - } - - public function testToString() - { - $path = new PropertyPath('reference.traversable[index].property'); - - $this->assertEquals('reference.traversable[index].property', $path->__toString()); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyPathException - */ - public function testInvalidPropertyPath_noDotBeforeProperty() - { - new PropertyPath('[index]property'); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyPathException - */ - public function testInvalidPropertyPath_dotAtTheBeginning() - { - new PropertyPath('.property'); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyPathException - */ - public function testInvalidPropertyPath_unexpectedCharacters() - { - new PropertyPath('property.$form'); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyPathException - */ - public function testInvalidPropertyPath_empty() - { - new PropertyPath(''); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testInvalidPropertyPath_null() - { - new PropertyPath(null); - } - - /** - * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException - */ - public function testInvalidPropertyPath_false() - { - new PropertyPath(false); - } - - public function testValidPropertyPath_zero() - { - new PropertyPath('0'); - } - - public function testGetParent_dot() - { - $propertyPath = new PropertyPath('grandpa.parent.child'); - - $this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent()); - } - - public function testGetParent_index() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent()); - } - - public function testGetParent_noParent() - { - $propertyPath = new PropertyPath('path'); - - $this->assertNull($propertyPath->getParent()); - } - - public function testCopyConstructor() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - $copy = new PropertyPath($propertyPath); - - $this->assertEquals($propertyPath, $copy); - } - - public function testGetElement() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $this->assertEquals('child', $propertyPath->getElement(2)); - } - - /** - * @expectedException \OutOfBoundsException - */ - public function testGetElementDoesNotAcceptInvalidIndices() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $propertyPath->getElement(3); - } - - /** - * @expectedException \OutOfBoundsException - */ - public function testGetElementDoesNotAcceptNegativeIndices() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $propertyPath->getElement(-1); - } - - public function testIsProperty() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $this->assertTrue($propertyPath->isProperty(1)); - $this->assertFalse($propertyPath->isProperty(2)); - } - - /** - * @expectedException \OutOfBoundsException - */ - public function testIsPropertyDoesNotAcceptInvalidIndices() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $propertyPath->isProperty(3); - } - - /** - * @expectedException \OutOfBoundsException - */ - public function testIsPropertyDoesNotAcceptNegativeIndices() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $propertyPath->isProperty(-1); - } - - public function testIsIndex() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $this->assertFalse($propertyPath->isIndex(1)); - $this->assertTrue($propertyPath->isIndex(2)); - } - - /** - * @expectedException \OutOfBoundsException - */ - public function testIsIndexDoesNotAcceptInvalidIndices() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $propertyPath->isIndex(3); - } - - /** - * @expectedException \OutOfBoundsException - */ - public function testIsIndexDoesNotAcceptNegativeIndices() - { - $propertyPath = new PropertyPath('grandpa.parent[child]'); - - $propertyPath->isIndex(-1); - } -} diff --git a/src/Symfony/Component/Form/Util/FormUtil.php b/src/Symfony/Component/Form/Util/FormUtil.php index 797028bd19..481f6a5080 100644 --- a/src/Symfony/Component/Form/Util/FormUtil.php +++ b/src/Symfony/Component/Form/Util/FormUtil.php @@ -11,181 +11,29 @@ namespace Symfony\Component\Form\Util; +use Symfony\Component\PropertyAccess\StringUtil; + /** * @author Bernhard Schussek */ class FormUtil { - /** - * Map english plural to singular suffixes - * - * @var array - * - * @see http://english-zone.com/spelling/plurals.html - * @see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English - */ - private static $pluralMap = array( - // First entry: plural suffix, reversed - // Second entry: length of plural suffix - // Third entry: Whether the suffix may succeed a vocal - // Fourth entry: Whether the suffix may succeed a consonant - // Fifth entry: singular suffix, normal - - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - array('a', 1, true, true, array('on', 'um')), - - // nebulae (nebula) - array('ea', 2, true, true, 'a'), - - // mice (mouse), lice (louse) - array('eci', 3, false, true, 'ouse'), - - // geese (goose) - array('esee', 4, false, true, 'oose'), - - // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) - array('i', 1, true, true, 'us'), - - // men (man), women (woman) - array('nem', 3, true, true, 'man'), - - // children (child) - array('nerdlihc', 8, true, true, 'child'), - - // oxen (ox) - array('nexo', 4, false, false, 'ox'), - - // indices (index), appendices (appendix), prices (price) - array('seci', 4, false, true, array('ex', 'ix', 'ice')), - - // babies (baby) - array('sei', 3, false, true, 'y'), - - // analyses (analysis), ellipses (ellipsis), funguses (fungus), - // neuroses (neurosis), theses (thesis), emphases (emphasis), - // oases (oasis), crises (crisis), houses (house), bases (base), - // atlases (atlas), kisses (kiss) - array('ses', 3, true, true, array('s', 'se', 'sis')), - - // lives (life), wives (wife) - array('sevi', 4, false, true, 'ife'), - - // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) - array('sev', 3, true, true, 'f'), - - // axes (axis), axes (ax), axes (axe) - array('sexa', 4, false, false, array('ax', 'axe', 'axis')), - - // indexes (index), matrixes (matrix) - array('sex', 3, true, false, 'x'), - - // quizzes (quiz) - array('sezz', 4, true, false, 'z'), - - // bureaus (bureau) - array('suae', 4, false, true, 'eau'), - - // roses (rose), garages (garage), cassettes (cassette), - // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), - // shoes (shoe) - array('se', 2, true, true, array('', 'e')), - - // tags (tag) - array('s', 1, true, true, ''), - - // chateaux (chateau) - array('xuae', 4, false, true, 'eau'), - ); - /** * This class should not be instantiated */ private function __construct() {} /** - * Returns the singular form of a word + * Alias for {@link StringUtil::singularify()} * - * If the method can't determine the form with certainty, an array of the - * possible singulars is returned. - * - * @param string $plural A word in plural form - * @return string|array The singular form or an array of possible singular - * forms + * @deprecated Deprecated since version 2.2, to be removed in 2.3. Use + * {@link StringUtil::singularify()} instead. */ public static function singularify($plural) { - $pluralRev = strrev($plural); - $lowerPluralRev = strtolower($pluralRev); - $pluralLength = strlen($lowerPluralRev); + trigger_error('\Symfony\Component\Form\Util\FormUtil::singularify() is deprecated since version 2.2 and will be removed in 2.3. Use \Symfony\Component\PropertyAccess\StringUtil::singularify() in the PropertyAccess component instead.', E_USER_DEPRECATED); - // The outer loop iterates over the entries of the plural table - // The inner loop $j iterates over the characters of the plural suffix - // in the plural table to compare them with the characters of the actual - // given plural suffix - foreach (self::$pluralMap as $map) { - $suffix = $map[0]; - $suffixLength = $map[1]; - $j = 0; - - // Compare characters in the plural table and of the suffix of the - // given plural one by one - while ($suffix[$j] === $lowerPluralRev[$j]) { - // Let $j point to the next character - ++$j; - - // Successfully compared the last character - // Add an entry with the singular suffix to the singular array - if ($j === $suffixLength) { - // Is there any character preceding the suffix in the plural string? - if ($j < $pluralLength) { - $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]); - - if (!$map[2] && $nextIsVocal) { - // suffix may not succeed a vocal but next char is one - break; - } - - if (!$map[3] && !$nextIsVocal) { - // suffix may not succeed a consonant but next char is one - break; - } - } - - $newBase = substr($plural, 0, $pluralLength - $suffixLength); - $newSuffix = $map[4]; - - // Check whether the first character in the plural suffix - // is uppercased. If yes, uppercase the first character in - // the singular suffix too - $firstUpper = ctype_upper($pluralRev[$j - 1]); - - if (is_array($newSuffix)) { - $singulars = array(); - - foreach ($newSuffix as $newSuffixEntry) { - $singulars[] = $newBase . ($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); - } - - return $singulars; - } - - return $newBase . ($firstUpper ? ucFirst($newSuffix) : $newSuffix); - } - - // Suffix is longer than word - if ($j === $pluralLength) { - break; - } - } - } - - // Convert teeth to tooth, feet to foot - if (false !== ($pos = strpos($plural, 'ee'))) { - return substr_replace($plural, 'oo', $pos, 2); - } - - // Assume that plural and singular is identical - return $plural; + return StringUtil::singularify($plural); } /** diff --git a/src/Symfony/Component/Form/Util/PropertyPath.php b/src/Symfony/Component/Form/Util/PropertyPath.php index a5cf13befe..445fae81d5 100644 --- a/src/Symfony/Component/Form/Util/PropertyPath.php +++ b/src/Symfony/Component/Form/Util/PropertyPath.php @@ -11,619 +11,47 @@ namespace Symfony\Component\Form\Util; -use Traversable; -use ReflectionClass; -use Symfony\Component\Form\Exception\InvalidPropertyPathException; -use Symfony\Component\Form\Exception\InvalidPropertyException; -use Symfony\Component\Form\Exception\PropertyAccessDeniedException; -use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\PropertyAccess\PropertyPath as BasePropertyPath; +use Symfony\Component\PropertyAccess\PropertyAccess; /** - * Allows easy traversing of a property path + * Alias for {@link \Symfony\Component\PropertyAccess\PropertyPath}. * * @author Bernhard Schussek + * + * @deprecated deprecated since version 2.2, to be removed in 2.3. Use + * {@link \Symfony\Component\PropertyAccess\PropertyPath} + * instead. */ -class PropertyPath implements \IteratorAggregate, PropertyPathInterface +class PropertyPath extends BasePropertyPath { /** - * Character used for separating between plural and singular of an element. - * @var string - */ - const SINGULAR_SEPARATOR = '|'; - - const VALUE = 0; - const IS_REF = 1; - - /** - * The elements of the property path - * @var array - */ - private $elements = array(); - - /** - * The singular forms of the elements in the property path. - * @var array - */ - private $singulars = array(); - - /** - * The number of elements in the property path - * @var integer - */ - private $length; - - /** - * Contains a Boolean for each property in $elements denoting whether this - * element is an index. It is a property otherwise. - * @var array - */ - private $isIndex = array(); - - /** - * String representation of the path - * @var string - */ - private $pathAsString; - - /** - * Constructs a property path from a string. - * - * @param PropertyPath|string $propertyPath The property path as string or instance. - * - * @throws UnexpectedTypeException If the given path is not a string. - * @throws InvalidPropertyPathException If the syntax of the property path is not valid. + * {@inheritdoc} */ public function __construct($propertyPath) { - // Can be used as copy constructor - if ($propertyPath instanceof PropertyPath) { - /* @var PropertyPath $propertyPath */ - $this->elements = $propertyPath->elements; - $this->singulars = $propertyPath->singulars; - $this->length = $propertyPath->length; - $this->isIndex = $propertyPath->isIndex; - $this->pathAsString = $propertyPath->pathAsString; + parent::__construct($propertyPath); - return; - } - if (!is_string($propertyPath)) { - throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\Form\Util\PropertyPath'); - } - - if ('' === $propertyPath) { - throw new InvalidPropertyPathException('The property path should not be empty.'); - } - - $this->pathAsString = $propertyPath; - $position = 0; - $remaining = $propertyPath; - - // first element is evaluated differently - no leading dot for properties - $pattern = '/^(([^\.\[]+)|\[([^\]]+)\])(.*)/'; - - while (preg_match($pattern, $remaining, $matches)) { - if ('' !== $matches[2]) { - $element = $matches[2]; - $this->isIndex[] = false; - } else { - $element = $matches[3]; - $this->isIndex[] = true; - } - // Disabled this behaviour as the syntax is not yet final - //$pos = strpos($element, self::SINGULAR_SEPARATOR); - $pos = false; - $singular = null; - - if (false !== $pos) { - $singular = substr($element, $pos + 1); - $element = substr($element, 0, $pos); - } - - $this->elements[] = $element; - $this->singulars[] = $singular; - - $position += strlen($matches[1]); - $remaining = $matches[4]; - $pattern = '/^(\.(\w+)|\[([^\]]+)\])(.*)/'; - } - - if ('' !== $remaining) { - throw new InvalidPropertyPathException(sprintf( - 'Could not parse property path "%s". Unexpected token "%s" at position %d', - $propertyPath, - $remaining{0}, - $position - )); - } - - $this->length = count($this->elements); + trigger_error('\Symfony\Component\Form\Util\PropertyPath is deprecated since version 2.2 and will be removed in 2.3. Use \Symfony\Component\PropertyAccess\PropertyPath instead.', E_USER_DEPRECATED); } /** - * {@inheritdoc} - */ - public function __toString() - { - return $this->pathAsString; - } - - /** - * {@inheritdoc} - */ - public function getLength() - { - return $this->length; - } - - /** - * {@inheritdoc} - */ - public function getParent() - { - if ($this->length <= 1) { - return null; - } - - $parent = clone $this; - - --$parent->length; - $parent->pathAsString = substr($parent->pathAsString, 0, max(strrpos($parent->pathAsString, '.'), strrpos($parent->pathAsString, '['))); - array_pop($parent->elements); - array_pop($parent->singulars); - array_pop($parent->isIndex); - - return $parent; - } - - /** - * Returns a new iterator for this path - * - * @return PropertyPathIteratorInterface - */ - public function getIterator() - { - return new PropertyPathIterator($this); - } - - /** - * {@inheritdoc} - */ - public function getElements() - { - return $this->elements; - } - - /** - * {@inheritdoc} - */ - public function getElement($index) - { - if (!isset($this->elements[$index])) { - throw new \OutOfBoundsException('The index ' . $index . ' is not within the property path'); - } - - return $this->elements[$index]; - } - - /** - * {@inheritdoc} - */ - public function isProperty($index) - { - if (!isset($this->isIndex[$index])) { - throw new \OutOfBoundsException('The index ' . $index . ' is not within the property path'); - } - - return !$this->isIndex[$index]; - } - - /** - * {@inheritdoc} - */ - public function isIndex($index) - { - if (!isset($this->isIndex[$index])) { - throw new \OutOfBoundsException('The index ' . $index . ' is not within the property path'); - } - - return $this->isIndex[$index]; - } - - /** - * Returns the value at the end of the property path of the object - * - * Example: - * - * $path = new PropertyPath('child.name'); - * - * echo $path->getValue($object); - * // equals echo $object->getChild()->getName(); - * - * - * This method first tries to find a public getter for each property in the - * path. The name of the getter must be the camel-cased property name - * prefixed with "get", "is", or "has". - * - * If the getter does not exist, this method tries to find a public - * property. The value of the property is then returned. - * - * If none of them are found, an exception is thrown. - * - * @param object|array $objectOrArray The object or array to traverse - * - * @return mixed The value at the end of the property path - * - * @throws InvalidPropertyException If the property/getter does not exist - * @throws PropertyAccessDeniedException If the property/getter exists but is not public + * Alias for {@link PropertyAccessor::getValue()} */ public function getValue($objectOrArray) { - $propertyValues =& $this->readPropertiesUntil($objectOrArray, $this->length - 1); + $propertyAccessor = PropertyAccess::getPropertyAccessor(); - return $propertyValues[count($propertyValues) - 1][self::VALUE]; + return $propertyAccessor->getValue($objectOrArray, $this); } /** - * Sets the value at the end of the property path of the object - * - * Example: - * - * $path = new PropertyPath('child.name'); - * - * echo $path->setValue($object, 'Fabien'); - * // equals echo $object->getChild()->setName('Fabien'); - * - * - * This method first tries to find a public setter for each property in the - * path. The name of the setter must be the camel-cased property name - * prefixed with "set". - * - * If the setter does not exist, this method tries to find a public - * property. The value of the property is then changed. - * - * If neither is found, an exception is thrown. - * - * @param object|array $objectOrArray The object or array to modify. - * @param mixed $value The value to set at the end of the property path. - * - * @throws InvalidPropertyException If a property does not exist. - * @throws PropertyAccessDeniedException If a property cannot be accessed due to - * access restrictions (private or protected). - * @throws UnexpectedTypeException If a value within the path is neither object - * nor array. + * Alias for {@link PropertyAccessor::setValue()} */ - public function setValue(&$objectOrArray, $value) + public function setValue($objectOrArray, $value) { - $propertyValues =& $this->readPropertiesUntil($objectOrArray, $this->length - 2); - $overwrite = true; + $propertyAccessor = PropertyAccess::getPropertyAccessor(); - // Add the root object to the list - array_unshift($propertyValues, array( - self::VALUE => &$objectOrArray, - self::IS_REF => true, - )); - - for ($i = count($propertyValues) - 1; $i >= 0; --$i) { - $objectOrArray =& $propertyValues[$i][self::VALUE]; - - if ($overwrite) { - if (!is_object($objectOrArray) && !is_array($objectOrArray)) { - throw new UnexpectedTypeException($objectOrArray, 'object or array'); - } - - $property = $this->elements[$i]; - $singular = $this->singulars[$i]; - $isIndex = $this->isIndex[$i]; - - $this->writeProperty($objectOrArray, $property, $singular, $isIndex, $value); - } - - $value =& $objectOrArray; - $overwrite = !$propertyValues[$i][self::IS_REF]; - } - } - - /** - * Reads the path from an object up to a given path index. - * - * @param object|array $objectOrArray The object or array to read from. - * @param integer $lastIndex The integer up to which should be read. - * - * @return array The values read in the path. - * - * @throws UnexpectedTypeException If a value within the path is neither object nor array. - */ - private function &readPropertiesUntil(&$objectOrArray, $lastIndex) - { - $propertyValues = array(); - - for ($i = 0; $i <= $lastIndex; ++$i) { - if (!is_object($objectOrArray) && !is_array($objectOrArray)) { - throw new UnexpectedTypeException($objectOrArray, 'object or array'); - } - - $property = $this->elements[$i]; - $isIndex = $this->isIndex[$i]; - $isArrayAccess = is_array($objectOrArray) || $objectOrArray instanceof \ArrayAccess; - - // Create missing nested arrays on demand - if ($isIndex && $isArrayAccess && !isset($objectOrArray[$property])) { - $objectOrArray[$property] = $i + 1 < $this->length ? array() : null; - } - - $propertyValue =& $this->readProperty($objectOrArray, $property, $isIndex); - $objectOrArray =& $propertyValue[self::VALUE]; - - $propertyValues[] =& $propertyValue; - } - - return $propertyValues; - } - - /** - * Reads the a property from an object or array. - * - * @param object|array $objectOrArray The object or array to read from. - * @param string $property The property to read. - * @param Boolean $isIndex Whether to interpret the property as index. - * - * @return mixed The value of the read property - * - * @throws InvalidPropertyException If the property does not exist. - * @throws PropertyAccessDeniedException If the property cannot be accessed due to - * access restrictions (private or protected). - */ - private function &readProperty(&$objectOrArray, $property, $isIndex) - { - // Use an array instead of an object since performance is - // very crucial here - $result = array( - self::VALUE => null, - self::IS_REF => false - ); - - if ($isIndex) { - if (!$objectOrArray instanceof \ArrayAccess && !is_array($objectOrArray)) { - throw new InvalidPropertyException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $property, get_class($objectOrArray))); - } - - if (isset($objectOrArray[$property])) { - if (is_array($objectOrArray)) { - $result[self::VALUE] =& $objectOrArray[$property]; - $result[self::IS_REF] = true; - } else { - $result[self::VALUE] = $objectOrArray[$property]; - } - } - } elseif (is_object($objectOrArray)) { - $camelProp = $this->camelize($property); - $reflClass = new ReflectionClass($objectOrArray); - $getter = 'get'.$camelProp; - $isser = 'is'.$camelProp; - $hasser = 'has'.$camelProp; - - if ($reflClass->hasMethod($getter)) { - if (!$reflClass->getMethod($getter)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $getter, $reflClass->name)); - } - - $result[self::VALUE] = $objectOrArray->$getter(); - } elseif ($reflClass->hasMethod($isser)) { - if (!$reflClass->getMethod($isser)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $isser, $reflClass->name)); - } - - $result[self::VALUE] = $objectOrArray->$isser(); - } elseif ($reflClass->hasMethod($hasser)) { - if (!$reflClass->getMethod($hasser)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $hasser, $reflClass->name)); - } - - $result[self::VALUE] = $objectOrArray->$hasser(); - } elseif ($reflClass->hasMethod('__get')) { - // needed to support magic method __get - $result[self::VALUE] = $objectOrArray->$property; - } elseif ($reflClass->hasProperty($property)) { - if (!$reflClass->getProperty($property)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s". Maybe you should create the method "%s()" or "%s()" or "%s()"?', $property, $reflClass->name, $getter, $isser, $hasser)); - } - - $result[self::VALUE] =& $objectOrArray->$property; - $result[self::IS_REF] = true; - } elseif (property_exists($objectOrArray, $property)) { - // needed to support \stdClass instances - $result[self::VALUE] =& $objectOrArray->$property; - $result[self::IS_REF] = true; - } else { - throw new InvalidPropertyException(sprintf('Neither property "%s" nor method "%s()" nor method "%s()" exists in class "%s"', $property, $getter, $isser, $reflClass->name)); - } - } else { - throw new InvalidPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); - } - - // Objects are always passed around by reference - if (is_object($result[self::VALUE])) { - $result[self::IS_REF] = true; - } - - return $result; - } - - /** - * Sets the value of the property at the given index in the path - * - * @param object|array $objectOrArray The object or array to write to. - * @param string $property The property to write. - * @param string|null $singular The singular form of the property name or null. - * @param Boolean $isIndex Whether to interpret the property as index. - * @param mixed $value The value to write. - * - * @throws InvalidPropertyException If the property does not exist. - * @throws PropertyAccessDeniedException If the property cannot be accessed due to - * access restrictions (private or protected). - */ - private function writeProperty(&$objectOrArray, $property, $singular, $isIndex, $value) - { - $adderRemoverError = null; - - if ($isIndex) { - if (!$objectOrArray instanceof \ArrayAccess && !is_array($objectOrArray)) { - throw new InvalidPropertyException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $property, get_class($objectOrArray))); - } - - $objectOrArray[$property] = $value; - } elseif (is_object($objectOrArray)) { - $reflClass = new ReflectionClass($objectOrArray); - - // The plural form is the last element of the property path - $plural = $this->camelize($this->elements[$this->length - 1]); - - // Any of the two methods is required, but not yet known - $singulars = null !== $singular ? array($singular) : (array) FormUtil::singularify($plural); - - if (is_array($value) || $value instanceof Traversable) { - $methods = $this->findAdderAndRemover($reflClass, $singulars); - if (null !== $methods) { - // At this point the add and remove methods have been found - // Use iterator_to_array() instead of clone in order to prevent side effects - // see https://github.com/symfony/symfony/issues/4670 - $itemsToAdd = is_object($value) ? iterator_to_array($value) : $value; - $itemToRemove = array(); - $propertyValue = $this->readProperty($objectOrArray, $property, $isIndex); - $previousValue = $propertyValue[self::VALUE]; - - if (is_array($previousValue) || $previousValue instanceof Traversable) { - foreach ($previousValue as $previousItem) { - foreach ($value as $key => $item) { - if ($item === $previousItem) { - // Item found, don't add - unset($itemsToAdd[$key]); - - // Next $previousItem - continue 2; - } - } - - // Item not found, add to remove list - $itemToRemove[] = $previousItem; - } - } - - foreach ($itemToRemove as $item) { - call_user_func(array($objectOrArray, $methods[1]), $item); - } - - foreach ($itemsToAdd as $item) { - call_user_func(array($objectOrArray, $methods[0]), $item); - } - - return; - } else { - $adderRemoverError = ', nor could adders and removers be found based on the '; - if (null === $singular) { - // $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars).' (provide a singular by suffixing the property path with "|{singular}" to override the guesser)'; - $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars); - } else { - $adderRemoverError .= 'passed singular: '.$singular; - } - } - } - - $setter = 'set'.$this->camelize($property); - if ($reflClass->hasMethod($setter)) { - if (!$reflClass->getMethod($setter)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $setter, $reflClass->name)); - } - - $objectOrArray->$setter($value); - } elseif ($reflClass->hasMethod('__set')) { - // needed to support magic method __set - $objectOrArray->$property = $value; - } elseif ($reflClass->hasProperty($property)) { - if (!$reflClass->getProperty($property)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s"%s. Maybe you should create the method "%s()"?', $property, $reflClass->name, $adderRemoverError, $setter)); - } - - $objectOrArray->$property = $value; - } elseif (property_exists($objectOrArray, $property)) { - // needed to support \stdClass instances - $objectOrArray->$property = $value; - } else { - throw new InvalidPropertyException(sprintf('Neither element "%s" nor method "%s()" exists in class "%s"%s', $property, $setter, $reflClass->name, $adderRemoverError)); - } - } else { - throw new InvalidPropertyException(sprintf('Cannot write property "%s" in an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); - } - } - - /** - * Camelizes a given string. - * - * @param string $string Some string. - * - * @return string The camelized version of the string. - */ - private function camelize($string) - { - return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $string); - } - - /** - * Searches for add and remove methods. - * - * @param \ReflectionClass $reflClass The reflection class for the given object - * @param array $singulars The singular form of the property name or null. - * - * @return array|null An array containing the adder and remover when found, null otherwise. - * - * @throws InvalidPropertyException If the property does not exist. - */ - private function findAdderAndRemover(\ReflectionClass $reflClass, array $singulars) - { - foreach ($singulars as $singular) { - $addMethod = 'add' . $singular; - $removeMethod = 'remove' . $singular; - - $addMethodFound = $this->isAccessible($reflClass, $addMethod, 1); - $removeMethodFound = $this->isAccessible($reflClass, $removeMethod, 1); - - if ($addMethodFound && $removeMethodFound) { - return array($addMethod, $removeMethod); - } - - if ($addMethodFound xor $removeMethodFound) { - throw new InvalidPropertyException(sprintf( - 'Found the public method "%s", but did not find a public "%s" on class %s', - $addMethodFound ? $addMethod : $removeMethod, - $addMethodFound ? $removeMethod : $addMethod, - $reflClass->name - )); - } - } - - return null; - } - - /** - * Returns whether a method is public and has a specific number of required parameters. - * - * @param \ReflectionClass $class The class of the method. - * @param string $methodName The method name. - * @param integer $parameters The number of parameters. - * - * @return Boolean Whether the method is public and has $parameters - * required parameters. - */ - private function isAccessible(ReflectionClass $class, $methodName, $parameters) - { - if ($class->hasMethod($methodName)) { - $method = $class->getMethod($methodName); - - if ($method->isPublic() && $method->getNumberOfRequiredParameters() === $parameters) { - return true; - } - } - - return false; + return $propertyAccessor->getValue($objectOrArray, $this, $value); } } diff --git a/src/Symfony/Component/Form/Util/PropertyPathBuilder.php b/src/Symfony/Component/Form/Util/PropertyPathBuilder.php index f17c8b2258..31836b63bd 100644 --- a/src/Symfony/Component/Form/Util/PropertyPathBuilder.php +++ b/src/Symfony/Component/Form/Util/PropertyPathBuilder.php @@ -11,284 +11,26 @@ namespace Symfony\Component\Form\Util; +use Symfony\Component\PropertyAccess\PropertyPathBuilder as BasePropertyPathBuilder; + /** + * Alias for {@link \Symfony\Component\PropertyAccess\PropertyPathBuilder}. + * * @author Bernhard Schussek + * + * @deprecated deprecated since version 2.2, to be removed in 2.3. Use + * {@link \Symfony\Component\PropertyAccess\PropertyPathBuilder} + * instead. */ -class PropertyPathBuilder +class PropertyPathBuilder extends BasePropertyPathBuilder { /** - * @var array + * {@inheritdoc} */ - private $elements = array(); - - /** - * @var array - */ - private $isIndex = array(); - - /** - * Creates a new property path builder. - * - * @param null|PropertyPathInterface $path The path to initially store - * in the builder. Optional. - */ - public function __construct(PropertyPathInterface $path = null) + public function __construct($propertyPath) { - if (null !== $path) { - $this->append($path); - } - } + parent::__construct($propertyPath); - /** - * Appends a (sub-) path to the current path. - * - * @param PropertyPathInterface $path The path to append. - * @param integer $offset The offset where the appended piece - * starts in $path. - * @param integer $length The length of the appended piece. - * If 0, the full path is appended. - */ - public function append(PropertyPathInterface $path, $offset = 0, $length = 0) - { - if (0 === $length) { - $end = $path->getLength(); - } else { - $end = $offset + $length; - } - - for (; $offset < $end; ++$offset) { - $this->elements[] = $path->getElement($offset); - $this->isIndex[] = $path->isIndex($offset); - } - } - - /** - * Appends an index element to the current path. - * - * @param string $name The name of the appended index. - */ - public function appendIndex($name) - { - $this->elements[] = $name; - $this->isIndex[] = true; - } - - /** - * Appends a property element to the current path. - * - * @param string $name The name of the appended property. - */ - public function appendProperty($name) - { - $this->elements[] = $name; - $this->isIndex[] = false; - } - - /** - * Removes elements from the current path. - * - * @param integer $offset The offset at which to remove. - * @param integer $length The length of the removed piece. - * - * @throws \OutOfBoundsException if offset is invalid - */ - public function remove($offset, $length = 1) - { - if (!isset($this->elements[$offset])) { - throw new \OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); - } - - $this->resize($offset, $length, 0); - } - - /** - * Replaces a sub-path by a different (sub-) path. - * - * @param integer $offset The offset at which to replace. - * @param integer $length The length of the piece to replace. - * @param PropertyPathInterface $path The path to insert. - * @param integer $pathOffset The offset where the inserted piece - * starts in $path. - * @param integer $pathLength The length of the inserted piece. - * If 0, the full path is inserted. - * - * @throws \OutOfBoundsException If the offset is invalid. - */ - public function replace($offset, $length, PropertyPathInterface $path, $pathOffset = 0, $pathLength = 0) - { - if (!isset($this->elements[$offset])) { - throw new \OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); - } - - if (0 === $pathLength) { - $pathLength = $path->getLength() - $pathOffset; - } - - $this->resize($offset, $length, $pathLength); - - for ($i = 0; $i < $pathLength; ++$i) { - $this->elements[$offset + $i] = $path->getElement($pathOffset + $i); - $this->isIndex[$offset + $i] = $path->isIndex($pathOffset + $i); - } - } - - /** - * Replaces a property element by an index element. - * - * @param integer $offset The offset at which to replace. - * @param string $name The new name of the element. Optional. - * - * @throws \OutOfBoundsException If the offset is invalid. - */ - public function replaceByIndex($offset, $name = null) - { - if (!isset($this->elements[$offset])) { - throw new \OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); - } - - if (null !== $name) { - $this->elements[$offset] = $name; - } - - $this->isIndex[$offset] = true; - } - - /** - * Replaces an index element by a property element. - * - * @param integer $offset The offset at which to replace. - * @param string $name The new name of the element. Optional. - * - * @throws \OutOfBoundsException If the offset is invalid. - */ - public function replaceByProperty($offset, $name = null) - { - if (!isset($this->elements[$offset])) { - throw new \OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); - } - - if (null !== $name) { - $this->elements[$offset] = $name; - } - - $this->isIndex[$offset] = false; - } - - /** - * Returns the length of the current path. - * - * @return integer The path length. - */ - public function getLength() - { - return count($this->elements); - } - - /** - * Returns the current property path. - * - * @return PropertyPathInterface The constructed property path. - */ - public function getPropertyPath() - { - $pathAsString = $this->__toString(); - - return '' !== $pathAsString ? new PropertyPath($pathAsString) : null; - } - - /** - * Returns the current property path as string. - * - * @return string The property path as string. - */ - public function __toString() - { - $string = ''; - - foreach ($this->elements as $offset => $element) { - if ($this->isIndex[$offset]) { - $element = '[' . $element . ']'; - } elseif ('' !== $string) { - $string .= '.'; - } - - $string .= $element; - } - - return $string; - } - - /** - * Resizes the path so that a chunk of length $cutLength is - * removed at $offset and another chunk of length $insertionLength - * can be inserted. - * - * @param integer $offset The offset where the removed chunk starts. - * @param integer $cutLength The length of the removed chunk. - * @param integer $insertionLength The length of the inserted chunk. - */ - private function resize($offset, $cutLength, $insertionLength) - { - // Nothing else to do in this case - if ($insertionLength === $cutLength) { - return; - } - - $length = count($this->elements); - - if ($cutLength > $insertionLength) { - // More elements should be removed than inserted - $diff = $cutLength - $insertionLength; - $newLength = $length - $diff; - - // Shift elements to the left (left-to-right until the new end) - // Max allowed offset to be shifted is such that - // $offset + $diff < $length (otherwise invalid index access) - // i.e. $offset < $length - $diff = $newLength - for ($i = $offset; $i < $newLength; ++$i) { - $this->elements[$i] = $this->elements[$i + $diff]; - $this->isIndex[$i] = $this->isIndex[$i + $diff]; - } - - // All remaining elements should be removed - for (; $i < $length; ++$i) { - unset($this->elements[$i]); - unset($this->isIndex[$i]); - } - } else { - $diff = $insertionLength - $cutLength; - - $newLength = $length + $diff; - $indexAfterInsertion = $offset + $insertionLength; - - // $diff <= $insertionLength - // $indexAfterInsertion >= $insertionLength - // => $diff <= $indexAfterInsertion - - // In each of the following loops, $i >= $diff must hold, - // otherwise ($i - $diff) becomes negative. - - // Shift old elements to the right to make up space for the - // inserted elements. This needs to be done left-to-right in - // order to preserve an ascending array index order - // Since $i = max($length, $indexAfterInsertion) and $indexAfterInsertion >= $diff, - // $i >= $diff is guaranteed. - for ($i = max($length, $indexAfterInsertion); $i < $newLength; ++$i) { - $this->elements[$i] = $this->elements[$i - $diff]; - $this->isIndex[$i] = $this->isIndex[$i - $diff]; - } - - // Shift remaining elements to the right. Do this right-to-left - // so we don't overwrite elements before copying them - // The last written index is the immediate index after the inserted - // string, because the indices before that will be overwritten - // anyway. - // Since $i >= $indexAfterInsertion and $indexAfterInsertion >= $diff, - // $i >= $diff is guaranteed. - for ($i = $length - 1; $i >= $indexAfterInsertion; --$i) { - $this->elements[$i] = $this->elements[$i - $diff]; - $this->isIndex[$i] = $this->isIndex[$i - $diff]; - } - } + trigger_error('\Symfony\Component\Form\Util\PropertyPathBuilder is deprecated since version 2.2 and will be removed in 2.3. Use \Symfony\Component\PropertyAccess\PropertyPathBuilder instead.', E_USER_DEPRECATED); } } diff --git a/src/Symfony/Component/Form/Util/PropertyPathInterface.php b/src/Symfony/Component/Form/Util/PropertyPathInterface.php index bceca29d90..ec2d5e9efb 100644 --- a/src/Symfony/Component/Form/Util/PropertyPathInterface.php +++ b/src/Symfony/Component/Form/Util/PropertyPathInterface.php @@ -11,74 +11,17 @@ namespace Symfony\Component\Form\Util; +use Symfony\Component\PropertyAccess\PropertyPathInterface as BasePropertyPathInterface; + /** + * Alias for {@link \Symfony\Component\PropertyAccess\PropertyPathInterface}. + * * @author Bernhard Schussek + * + * @deprecated deprecated since version 2.2, to be removed in 2.3. Use + * {@link \Symfony\Component\PropertyAccess\PropertyPathInterface} + * instead. */ -interface PropertyPathInterface extends \Traversable +interface PropertyPathInterface extends BasePropertyPathInterface { - /** - * Returns the string representation of the property path - * - * @return string The path as string. - */ - public function __toString(); - - /** - * Returns the length of the property path, i.e. the number of elements. - * - * @return integer The path length. - */ - public function getLength(); - - /** - * Returns the parent property path. - * - * The parent property path is the one that contains the same items as - * this one except for the last one. - * - * If this property path only contains one item, null is returned. - * - * @return PropertyPath The parent path or null. - */ - public function getParent(); - - /** - * Returns the elements of the property path as array - * - * @return array An array of property/index names - */ - public function getElements(); - - /** - * Returns the element at the given index in the property path - * - * @param integer $index The index key - * - * @return string A property or index name - * - * @throws \OutOfBoundsException If the offset is invalid. - */ - public function getElement($index); - - /** - * Returns whether the element at the given index is a property - * - * @param integer $index The index in the property path - * - * @return Boolean Whether the element at this index is a property - * - * @throws \OutOfBoundsException If the offset is invalid. - */ - public function isProperty($index); - - /** - * Returns whether the element at the given index is an array index - * - * @param integer $index The index in the property path - * - * @return Boolean Whether the element at this index is an array index - * - * @throws \OutOfBoundsException If the offset is invalid. - */ - public function isIndex($index); } diff --git a/src/Symfony/Component/Form/Util/PropertyPathIterator.php b/src/Symfony/Component/Form/Util/PropertyPathIterator.php index c165d0854e..024ed6a653 100644 --- a/src/Symfony/Component/Form/Util/PropertyPathIterator.php +++ b/src/Symfony/Component/Form/Util/PropertyPathIterator.php @@ -11,45 +11,26 @@ namespace Symfony\Component\Form\Util; +use Symfony\Component\PropertyAccess\PropertyPathIterator as BasePropertyPathIterator; + /** - * Traverses a property path and provides additional methods to find out - * information about the current element + * Alias for {@link \Symfony\Component\PropertyAccess\PropertyPathIterator}. * * @author Bernhard Schussek + * + * @deprecated deprecated since version 2.2, to be removed in 2.3. Use + * {@link \Symfony\Component\PropertyAccess\PropertyPathIterator} + * instead. */ -class PropertyPathIterator extends \ArrayIterator implements PropertyPathIteratorInterface +class PropertyPathIterator extends BasePropertyPathIterator { - /** - * The traversed property path - * @var PropertyPathInterface - */ - protected $path; - - /** - * Constructor. - * - * @param PropertyPathInterface $path The property path to traverse - */ - public function __construct(PropertyPathInterface $path) - { - parent::__construct($path->getElements()); - - $this->path = $path; - } - /** * {@inheritdoc} */ - public function isIndex() + public function __construct($propertyPath) { - return $this->path->isIndex($this->key()); - } + parent::__construct($propertyPath); - /** - * {@inheritdoc} - */ - public function isProperty() - { - return $this->path->isProperty($this->key()); + trigger_error('\Symfony\Component\Form\Util\PropertyPathIterator is deprecated since version 2.2 and will be removed in 2.3. Use \Symfony\Component\PropertyAccess\PropertyPathIterator instead.', E_USER_DEPRECATED); } } diff --git a/src/Symfony/Component/Form/Util/PropertyPathIteratorInterface.php b/src/Symfony/Component/Form/Util/PropertyPathIteratorInterface.php index 35fb11ad73..3540639530 100644 --- a/src/Symfony/Component/Form/Util/PropertyPathIteratorInterface.php +++ b/src/Symfony/Component/Form/Util/PropertyPathIteratorInterface.php @@ -11,24 +11,17 @@ namespace Symfony\Component\Form\Util; -/** - * @author Bernhard Schussek - */ -interface PropertyPathIteratorInterface extends \Iterator, \SeekableIterator -{ - /** - * Returns whether the current element in the property path is an array - * index. - * - * @return Boolean - */ - public function isIndex(); +use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface as BasePropertyPathIteratorInterface; - /** - * Returns whether the current element in the property path is a property - * name. - * - * @return Boolean - */ - public function isProperty(); +/** + * Alias for {@link \Symfony\Component\PropertyAccess\PropertyPathIteratorInterface}. + * + * @author Bernhard Schussek + * + * @deprecated deprecated since version 2.2, to be removed in 2.3. Use + * {@link \Symfony\Component\PropertyAccess\PropertyPathIterator} + * instead. + */ +interface PropertyPathIteratorInterface extends BasePropertyPathIteratorInterface +{ } diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 1e69cb140d..51afa67c3a 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -19,7 +19,8 @@ "php": ">=5.3.3", "symfony/event-dispatcher": "2.2.*", "symfony/locale": "2.2.*", - "symfony/options-resolver": "2.2.*" + "symfony/options-resolver": "2.2.*", + "symfony/property-access": "2.2.*" }, "require-dev": { "symfony/validator": "2.2.*", diff --git a/src/Symfony/Component/PropertyAccess/.gitattributes b/src/Symfony/Component/PropertyAccess/.gitattributes new file mode 100644 index 0000000000..80481513cf --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/.gitattributes @@ -0,0 +1,2 @@ +/Tests export-ignore +phpunit.xml.dist export-ignore diff --git a/src/Symfony/Component/PropertyAccess/.gitignore b/src/Symfony/Component/PropertyAccess/.gitignore new file mode 100644 index 0000000000..44de97a36a --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/.gitignore @@ -0,0 +1,4 @@ +vendor/ +composer.lock +phpunit.xml + diff --git a/src/Symfony/Component/Form/Exception/InvalidPropertyException.php b/src/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php similarity index 54% rename from src/Symfony/Component/Form/Exception/InvalidPropertyException.php rename to src/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php index 48185d55fd..d1fcdac942 100644 --- a/src/Symfony/Component/Form/Exception/InvalidPropertyException.php +++ b/src/Symfony/Component/PropertyAccess/Exception/ExceptionInterface.php @@ -9,8 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Exception; +namespace Symfony\Component\PropertyAccess\Exception; -class InvalidPropertyException extends Exception +/** + * Marker interface for the PropertyAccess component. + * + * @author Bernhard Schussek + */ +interface ExceptionInterface { } diff --git a/src/Symfony/Component/Form/Exception/PropertyAccessDeniedException.php b/src/Symfony/Component/PropertyAccess/Exception/InvalidPropertyPathException.php similarity index 52% rename from src/Symfony/Component/Form/Exception/PropertyAccessDeniedException.php rename to src/Symfony/Component/PropertyAccess/Exception/InvalidPropertyPathException.php index 4905da9ea2..69de31cee4 100644 --- a/src/Symfony/Component/Form/Exception/PropertyAccessDeniedException.php +++ b/src/Symfony/Component/PropertyAccess/Exception/InvalidPropertyPathException.php @@ -9,8 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Exception; +namespace Symfony\Component\PropertyAccess\Exception; -class PropertyAccessDeniedException extends Exception +/** + * Thrown when a property path is malformed. + * + * @author Bernhard Schussek + */ +class InvalidPropertyPathException extends RuntimeException { } diff --git a/src/Symfony/Component/Form/Exception/InvalidPropertyPathException.php b/src/Symfony/Component/PropertyAccess/Exception/NoSuchPropertyException.php similarity index 53% rename from src/Symfony/Component/Form/Exception/InvalidPropertyPathException.php rename to src/Symfony/Component/PropertyAccess/Exception/NoSuchPropertyException.php index c8bd3ad71b..ebaa5a3079 100644 --- a/src/Symfony/Component/Form/Exception/InvalidPropertyPathException.php +++ b/src/Symfony/Component/PropertyAccess/Exception/NoSuchPropertyException.php @@ -9,8 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Exception; +namespace Symfony\Component\PropertyAccess\Exception; -class InvalidPropertyPathException extends Exception +/** + * Thrown when a property cannot be found. + * + * @author Bernhard Schussek + */ +class NoSuchPropertyException extends RuntimeException { } diff --git a/src/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php b/src/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php new file mode 100644 index 0000000000..a3c45597da --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Exception/OutOfBoundsException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Base OutOfBoundsException for the PropertyAccess component. + * + * @author Bernhard Schussek + */ +class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/PropertyAccess/Exception/PropertyAccessDeniedException.php b/src/Symfony/Component/PropertyAccess/Exception/PropertyAccessDeniedException.php new file mode 100644 index 0000000000..b36e5f088d --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Exception/PropertyAccessDeniedException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Thrown when a property cannot be accessed because it is not public. + * + * @author Bernhard Schussek + */ +class PropertyAccessDeniedException extends RuntimeException +{ +} diff --git a/src/Symfony/Component/PropertyAccess/Exception/RuntimeException.php b/src/Symfony/Component/PropertyAccess/Exception/RuntimeException.php new file mode 100644 index 0000000000..9fe843e309 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Exception/RuntimeException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Base RuntimeException for the PropertyAccess component. + * + * @author Bernhard Schussek + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php b/src/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php new file mode 100644 index 0000000000..029d48c22a --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Exception/UnexpectedTypeException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Exception; + +/** + * Thrown when a value does not match an expected type. + * + * @author Bernhard Schussek + */ +class UnexpectedTypeException extends RuntimeException +{ + public function __construct($value, $expectedType) + { + parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value))); + } +} diff --git a/src/Symfony/Component/PropertyAccess/LICENSE b/src/Symfony/Component/PropertyAccess/LICENSE new file mode 100644 index 0000000000..88a57f8d8d --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2013 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccess.php b/src/Symfony/Component/PropertyAccess/PropertyAccess.php new file mode 100644 index 0000000000..6fb747578f --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyAccess.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Entry point of the PropertyAccess component. + * + * @author Bernhard Schussek + */ +final class PropertyAccess +{ + /** + * Creates a property accessor with the default configuration. + * + * @return PropertyAccessor The new property accessor. + */ + public static function getPropertyAccessor() + { + return new PropertyAccessor(); + } + + /** + * This class cannot be instantiated. + */ + private function __construct() + { + } +} diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php new file mode 100644 index 0000000000..229627aa53 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -0,0 +1,399 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; +use Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException; +use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; + +/** + * Default implementation of {@link PropertyAccessorInterface}. + * + * @author Bernhard Schussek + */ +class PropertyAccessor implements PropertyAccessorInterface +{ + const VALUE = 0; + const IS_REF = 1; + + /** + * Should not be used by application code. Use + * {@link PropertyAccess::getPropertyAccessor()} instead. + */ + public function __construct() + { + } + + /** + * {@inheritdoc} + */ + public function getValue($objectOrArray, $propertyPath) + { + if (is_string($propertyPath)) { + $propertyPath = new PropertyPath($propertyPath); + } elseif (!$propertyPath instanceof PropertyPathInterface) { + throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface'); + } + + $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 1); + + return $propertyValues[count($propertyValues) - 1][self::VALUE]; + } + + /** + * {@inheritdoc} + */ + public function setValue(&$objectOrArray, $propertyPath, $value) + { + if (is_string($propertyPath)) { + $propertyPath = new PropertyPath($propertyPath); + } elseif (!$propertyPath instanceof PropertyPathInterface) { + throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface'); + } + + $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 2); + $overwrite = true; + + // Add the root object to the list + array_unshift($propertyValues, array( + self::VALUE => &$objectOrArray, + self::IS_REF => true, + )); + + for ($i = count($propertyValues) - 1; $i >= 0; --$i) { + $objectOrArray =& $propertyValues[$i][self::VALUE]; + + if ($overwrite) { + if (!is_object($objectOrArray) && !is_array($objectOrArray)) { + throw new UnexpectedTypeException($objectOrArray, 'object or array'); + } + + $property = $propertyPath->getElement($i); + //$singular = $propertyPath->singulars[$i]; + $singular = null; + $isIndex = $propertyPath->isIndex($i); + + $this->writeProperty($objectOrArray, $propertyPath, $property, $singular, $isIndex, $value); + } + + $value =& $objectOrArray; + $overwrite = !$propertyValues[$i][self::IS_REF]; + } + } + + /** + * Reads the path from an object up to a given path index. + * + * @param object|array $objectOrArray The object or array to read from. + * @param PropertyPathInterface $propertyPath The property path to read. + * @param integer $lastIndex The integer up to which should be read. + * + * @return array The values read in the path. + * + * @throws UnexpectedTypeException If a value within the path is neither object nor array. + */ + private function &readPropertiesUntil(&$objectOrArray, PropertyPathInterface $propertyPath, $lastIndex) + { + $propertyValues = array(); + + for ($i = 0; $i <= $lastIndex; ++$i) { + if (!is_object($objectOrArray) && !is_array($objectOrArray)) { + throw new UnexpectedTypeException($objectOrArray, 'object or array'); + } + + $property = $propertyPath->getElement($i); + $isIndex = $propertyPath->isIndex($i); + $isArrayAccess = is_array($objectOrArray) || $objectOrArray instanceof \ArrayAccess; + + // Create missing nested arrays on demand + if ($isIndex && $isArrayAccess && !isset($objectOrArray[$property])) { + $objectOrArray[$property] = $i + 1 < $propertyPath->getLength() ? array() : null; + } + + $propertyValue =& $this->readProperty($objectOrArray, $propertyPath, $property, $isIndex); + $objectOrArray =& $propertyValue[self::VALUE]; + + $propertyValues[] =& $propertyValue; + } + + return $propertyValues; + } + + /** + * Reads the a property from an object or array. + * + * @param object|array $objectOrArray The object or array to read from. + * @param PropertyPathInterface $propertyPath The property path to read. + * @param string $property The property to read. + * @param Boolean $isIndex Whether to interpret the property as index. + * + * @return mixed The value of the read property + * + * @throws NoSuchPropertyException If the property does not exist. + * @throws PropertyAccessDeniedException If the property cannot be accessed due to + * access restrictions (private or protected). + */ + private function &readProperty(&$objectOrArray, PropertyPathInterface $propertyPath, $property, $isIndex) + { + // Use an array instead of an object since performance is + // very crucial here + $result = array( + self::VALUE => null, + self::IS_REF => false + ); + + if ($isIndex) { + if (!$objectOrArray instanceof \ArrayAccess && !is_array($objectOrArray)) { + throw new NoSuchPropertyException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $property, get_class($objectOrArray))); + } + + if (isset($objectOrArray[$property])) { + if (is_array($objectOrArray)) { + $result[self::VALUE] =& $objectOrArray[$property]; + $result[self::IS_REF] = true; + } else { + $result[self::VALUE] = $objectOrArray[$property]; + } + } + } elseif (is_object($objectOrArray)) { + $camelProp = $this->camelize($property); + $reflClass = new \ReflectionClass($objectOrArray); + $getter = 'get'.$camelProp; + $isser = 'is'.$camelProp; + $hasser = 'has'.$camelProp; + + if ($reflClass->hasMethod($getter)) { + if (!$reflClass->getMethod($getter)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $getter, $reflClass->name)); + } + + $result[self::VALUE] = $objectOrArray->$getter(); + } elseif ($reflClass->hasMethod($isser)) { + if (!$reflClass->getMethod($isser)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $isser, $reflClass->name)); + } + + $result[self::VALUE] = $objectOrArray->$isser(); + } elseif ($reflClass->hasMethod($hasser)) { + if (!$reflClass->getMethod($hasser)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $hasser, $reflClass->name)); + } + + $result[self::VALUE] = $objectOrArray->$hasser(); + } elseif ($reflClass->hasMethod('__get')) { + // needed to support magic method __get + $result[self::VALUE] = $objectOrArray->$property; + } elseif ($reflClass->hasProperty($property)) { + if (!$reflClass->getProperty($property)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s". Maybe you should create the method "%s()" or "%s()" or "%s()"?', $property, $reflClass->name, $getter, $isser, $hasser)); + } + + $result[self::VALUE] =& $objectOrArray->$property; + $result[self::IS_REF] = true; + } elseif (property_exists($objectOrArray, $property)) { + // needed to support \stdClass instances + $result[self::VALUE] =& $objectOrArray->$property; + $result[self::IS_REF] = true; + } else { + throw new NoSuchPropertyException(sprintf('Neither property "%s" nor method "%s()" nor method "%s()" exists in class "%s"', $property, $getter, $isser, $reflClass->name)); + } + } else { + throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); + } + + // Objects are always passed around by reference + if (is_object($result[self::VALUE])) { + $result[self::IS_REF] = true; + } + + return $result; + } + + /** + * Sets the value of the property at the given index in the path + * + * @param object|array $objectOrArray The object or array to write to. + * @param PropertyPathInterface $propertyPath The property path to write. + * @param string $property The property to write. + * @param string|null $singular The singular form of the property name or null. + * @param Boolean $isIndex Whether to interpret the property as index. + * @param mixed $value The value to write. + * + * @throws NoSuchPropertyException If the property does not exist. + * @throws PropertyAccessDeniedException If the property cannot be accessed due to + * access restrictions (private or protected). + */ + private function writeProperty(&$objectOrArray, PropertyPathInterface $propertyPath, $property, $singular, $isIndex, $value) + { + $adderRemoverError = null; + + if ($isIndex) { + if (!$objectOrArray instanceof \ArrayAccess && !is_array($objectOrArray)) { + throw new NoSuchPropertyException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $property, get_class($objectOrArray))); + } + + $objectOrArray[$property] = $value; + } elseif (is_object($objectOrArray)) { + $reflClass = new \ReflectionClass($objectOrArray); + + // The plural form is the last element of the property path + $plural = $this->camelize($propertyPath->getElement($propertyPath->getLength() - 1)); + + // Any of the two methods is required, but not yet known + $singulars = null !== $singular ? array($singular) : (array) StringUtil::singularify($plural); + + if (is_array($value) || $value instanceof \Traversable) { + $methods = $this->findAdderAndRemover($reflClass, $singulars); + if (null !== $methods) { + // At this point the add and remove methods have been found + // Use iterator_to_array() instead of clone in order to prevent side effects + // see https://github.com/symfony/symfony/issues/4670 + $itemsToAdd = is_object($value) ? iterator_to_array($value) : $value; + $itemToRemove = array(); + $propertyValue = $this->readProperty($objectOrArray, $propertyPath, $property, $isIndex); + $previousValue = $propertyValue[self::VALUE]; + + if (is_array($previousValue) || $previousValue instanceof \Traversable) { + foreach ($previousValue as $previousItem) { + foreach ($value as $key => $item) { + if ($item === $previousItem) { + // Item found, don't add + unset($itemsToAdd[$key]); + + // Next $previousItem + continue 2; + } + } + + // Item not found, add to remove list + $itemToRemove[] = $previousItem; + } + } + + foreach ($itemToRemove as $item) { + call_user_func(array($objectOrArray, $methods[1]), $item); + } + + foreach ($itemsToAdd as $item) { + call_user_func(array($objectOrArray, $methods[0]), $item); + } + + return; + } else { + $adderRemoverError = ', nor could adders and removers be found based on the '; + if (null === $singular) { + // $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars).' (provide a singular by suffixing the property path with "|{singular}" to override the guesser)'; + $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars); + } else { + $adderRemoverError .= 'passed singular: '.$singular; + } + } + } + + $setter = 'set'.$this->camelize($property); + if ($reflClass->hasMethod($setter)) { + if (!$reflClass->getMethod($setter)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $setter, $reflClass->name)); + } + + $objectOrArray->$setter($value); + } elseif ($reflClass->hasMethod('__set')) { + // needed to support magic method __set + $objectOrArray->$property = $value; + } elseif ($reflClass->hasProperty($property)) { + if (!$reflClass->getProperty($property)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s"%s. Maybe you should create the method "%s()"?', $property, $reflClass->name, $adderRemoverError, $setter)); + } + + $objectOrArray->$property = $value; + } elseif (property_exists($objectOrArray, $property)) { + // needed to support \stdClass instances + $objectOrArray->$property = $value; + } else { + throw new NoSuchPropertyException(sprintf('Neither element "%s" nor method "%s()" exists in class "%s"%s', $property, $setter, $reflClass->name, $adderRemoverError)); + } + } else { + throw new NoSuchPropertyException(sprintf('Cannot write property "%s" in an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); + } + } + + /** + * Camelizes a given string. + * + * @param string $string Some string. + * + * @return string The camelized version of the string. + */ + private function camelize($string) + { + return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $string); + } + + /** + * Searches for add and remove methods. + * + * @param \ReflectionClass $reflClass The reflection class for the given object + * @param array $singulars The singular form of the property name or null. + * + * @return array|null An array containing the adder and remover when found, null otherwise. + * + * @throws NoSuchPropertyException If the property does not exist. + */ + private function findAdderAndRemover(\ReflectionClass $reflClass, array $singulars) + { + foreach ($singulars as $singular) { + $addMethod = 'add' . $singular; + $removeMethod = 'remove' . $singular; + + $addMethodFound = $this->isAccessible($reflClass, $addMethod, 1); + $removeMethodFound = $this->isAccessible($reflClass, $removeMethod, 1); + + if ($addMethodFound && $removeMethodFound) { + return array($addMethod, $removeMethod); + } + + if ($addMethodFound xor $removeMethodFound) { + throw new NoSuchPropertyException(sprintf( + 'Found the public method "%s", but did not find a public "%s" on class %s', + $addMethodFound ? $addMethod : $removeMethod, + $addMethodFound ? $removeMethod : $addMethod, + $reflClass->name + )); + } + } + + return null; + } + + /** + * Returns whether a method is public and has a specific number of required parameters. + * + * @param \ReflectionClass $class The class of the method. + * @param string $methodName The method name. + * @param integer $parameters The number of parameters. + * + * @return Boolean Whether the method is public and has $parameters + * required parameters. + */ + private function isAccessible(\ReflectionClass $class, $methodName, $parameters) + { + if ($class->hasMethod($methodName)) { + $method = $class->getMethod($methodName); + + if ($method->isPublic() && $method->getNumberOfRequiredParameters() === $parameters) { + return true; + } + } + + return false; + } +} diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php b/src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php new file mode 100644 index 0000000000..058806c6ae --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessorInterface.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Writes and reads values to/from an object/array graph. + * + * @author Bernhard Schussek + */ +interface PropertyAccessorInterface +{ + /** + * Sets the value at the end of the property path of the object + * + * Example: + * + * use Symfony\Component\PropertyAccess\PropertyAccess; + * + * $propertyAccessor = PropertyAccess::getPropertyAccessor(); + * + * echo $propertyAccessor->setValue($object, 'child.name', 'Fabien'); + * // equals echo $object->getChild()->setName('Fabien'); + * + * This method first tries to find a public setter for each property in the + * path. The name of the setter must be the camel-cased property name + * prefixed with "set". + * + * If the setter does not exist, this method tries to find a public + * property. The value of the property is then changed. + * + * If neither is found, an exception is thrown. + * + * @param object|array $objectOrArray The object or array to modify. + * @param string|PropertyPathInterface $propertyPath The property path to modify. + * @param mixed $value The value to set at the end of the property path. + * + * @throws Exception\NoSuchPropertyException If a property does not exist. + * @throws Exception\PropertyAccessDeniedException If a property cannot be accessed due to + * access restrictions (private or protected). + * @throws Exception\UnexpectedTypeException If a value within the path is neither object + * nor array. + */ + public function setValue(&$objectOrArray, $propertyPath, $value); + + /** + * Returns the value at the end of the property path of the object + * + * Example: + * + * use Symfony\Component\PropertyAccess\PropertyAccess; + * + * $propertyAccessor = PropertyAccess::getPropertyAccessor(); + * + * echo $propertyAccessor->getValue($object, 'child.name); + * // equals echo $object->getChild()->getName(); + * + * This method first tries to find a public getter for each property in the + * path. The name of the getter must be the camel-cased property name + * prefixed with "get", "is", or "has". + * + * If the getter does not exist, this method tries to find a public + * property. The value of the property is then returned. + * + * If none of them are found, an exception is thrown. + * + * @param object|array $objectOrArray The object or array to traverse + * @param string|PropertyPathInterface $propertyPath The property path to modify. + * + * @return mixed The value at the end of the property path + * + * @throws Exception\NoSuchPropertyException If the property/getter does not exist + * @throws Exception\PropertyAccessDeniedException If the property/getter exists but is not public + */ + public function getValue($objectOrArray, $propertyPath); +} diff --git a/src/Symfony/Component/PropertyAccess/PropertyPath.php b/src/Symfony/Component/PropertyAccess/PropertyPath.php new file mode 100644 index 0000000000..5fc4ac635b --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyPath.php @@ -0,0 +1,225 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +use Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException; +use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException; +use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; + +/** + * Default implementation of {@link PropertyPathInterface}. + * + * @author Bernhard Schussek + */ +class PropertyPath implements \IteratorAggregate, PropertyPathInterface +{ + /** + * Character used for separating between plural and singular of an element. + * @var string + */ + const SINGULAR_SEPARATOR = '|'; + + /** + * The elements of the property path + * @var array + */ + private $elements = array(); + + /** + * The singular forms of the elements in the property path. + * @var array + */ + private $singulars = array(); + + /** + * The number of elements in the property path + * @var integer + */ + private $length; + + /** + * Contains a Boolean for each property in $elements denoting whether this + * element is an index. It is a property otherwise. + * @var array + */ + private $isIndex = array(); + + /** + * String representation of the path + * @var string + */ + private $pathAsString; + + /** + * Constructs a property path from a string. + * + * @param PropertyPath|string $propertyPath The property path as string or instance. + * + * @throws UnexpectedTypeException If the given path is not a string. + * @throws InvalidPropertyPathException If the syntax of the property path is not valid. + */ + public function __construct($propertyPath) + { + // Can be used as copy constructor + if ($propertyPath instanceof PropertyPath) { + /* @var PropertyPath $propertyPath */ + $this->elements = $propertyPath->elements; + $this->singulars = $propertyPath->singulars; + $this->length = $propertyPath->length; + $this->isIndex = $propertyPath->isIndex; + $this->pathAsString = $propertyPath->pathAsString; + + return; + } + if (!is_string($propertyPath)) { + throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPath'); + } + + if ('' === $propertyPath) { + throw new InvalidPropertyPathException('The property path should not be empty.'); + } + + $this->pathAsString = $propertyPath; + $position = 0; + $remaining = $propertyPath; + + // first element is evaluated differently - no leading dot for properties + $pattern = '/^(([^\.\[]+)|\[([^\]]+)\])(.*)/'; + + while (preg_match($pattern, $remaining, $matches)) { + if ('' !== $matches[2]) { + $element = $matches[2]; + $this->isIndex[] = false; + } else { + $element = $matches[3]; + $this->isIndex[] = true; + } + // Disabled this behaviour as the syntax is not yet final + //$pos = strpos($element, self::SINGULAR_SEPARATOR); + $pos = false; + $singular = null; + + if (false !== $pos) { + $singular = substr($element, $pos + 1); + $element = substr($element, 0, $pos); + } + + $this->elements[] = $element; + $this->singulars[] = $singular; + + $position += strlen($matches[1]); + $remaining = $matches[4]; + $pattern = '/^(\.(\w+)|\[([^\]]+)\])(.*)/'; + } + + if ('' !== $remaining) { + throw new InvalidPropertyPathException(sprintf( + 'Could not parse property path "%s". Unexpected token "%s" at position %d', + $propertyPath, + $remaining{0}, + $position + )); + } + + $this->length = count($this->elements); + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return $this->pathAsString; + } + + /** + * {@inheritdoc} + */ + public function getLength() + { + return $this->length; + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + if ($this->length <= 1) { + return null; + } + + $parent = clone $this; + + --$parent->length; + $parent->pathAsString = substr($parent->pathAsString, 0, max(strrpos($parent->pathAsString, '.'), strrpos($parent->pathAsString, '['))); + array_pop($parent->elements); + array_pop($parent->singulars); + array_pop($parent->isIndex); + + return $parent; + } + + /** + * Returns a new iterator for this path + * + * @return PropertyPathIteratorInterface + */ + public function getIterator() + { + return new PropertyPathIterator($this); + } + + /** + * {@inheritdoc} + */ + public function getElements() + { + return $this->elements; + } + + /** + * {@inheritdoc} + */ + public function getElement($index) + { + if (!isset($this->elements[$index])) { + throw new OutOfBoundsException('The index ' . $index . ' is not within the property path'); + } + + return $this->elements[$index]; + } + + /** + * {@inheritdoc} + */ + public function isProperty($index) + { + if (!isset($this->isIndex[$index])) { + throw new OutOfBoundsException('The index ' . $index . ' is not within the property path'); + } + + return !$this->isIndex[$index]; + } + + /** + * {@inheritdoc} + */ + public function isIndex($index) + { + if (!isset($this->isIndex[$index])) { + throw new OutOfBoundsException('The index ' . $index . ' is not within the property path'); + } + + return $this->isIndex[$index]; + } +} diff --git a/src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php b/src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php new file mode 100644 index 0000000000..f169f2835b --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyPathBuilder.php @@ -0,0 +1,296 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +use Symfony\Component\PropertyAccess\Exception\OutOfBoundsException; + +/** + * @author Bernhard Schussek + */ +class PropertyPathBuilder +{ + /** + * @var array + */ + private $elements = array(); + + /** + * @var array + */ + private $isIndex = array(); + + /** + * Creates a new property path builder. + * + * @param null|PropertyPathInterface $path The path to initially store + * in the builder. Optional. + */ + public function __construct(PropertyPathInterface $path = null) + { + if (null !== $path) { + $this->append($path); + } + } + + /** + * Appends a (sub-) path to the current path. + * + * @param PropertyPathInterface $path The path to append. + * @param integer $offset The offset where the appended piece + * starts in $path. + * @param integer $length The length of the appended piece. + * If 0, the full path is appended. + */ + public function append(PropertyPathInterface $path, $offset = 0, $length = 0) + { + if (0 === $length) { + $end = $path->getLength(); + } else { + $end = $offset + $length; + } + + for (; $offset < $end; ++$offset) { + $this->elements[] = $path->getElement($offset); + $this->isIndex[] = $path->isIndex($offset); + } + } + + /** + * Appends an index element to the current path. + * + * @param string $name The name of the appended index. + */ + public function appendIndex($name) + { + $this->elements[] = $name; + $this->isIndex[] = true; + } + + /** + * Appends a property element to the current path. + * + * @param string $name The name of the appended property. + */ + public function appendProperty($name) + { + $this->elements[] = $name; + $this->isIndex[] = false; + } + + /** + * Removes elements from the current path. + * + * @param integer $offset The offset at which to remove. + * @param integer $length The length of the removed piece. + * + * @throws OutOfBoundsException if offset is invalid + */ + public function remove($offset, $length = 1) + { + if (!isset($this->elements[$offset])) { + throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); + } + + $this->resize($offset, $length, 0); + } + + /** + * Replaces a sub-path by a different (sub-) path. + * + * @param integer $offset The offset at which to replace. + * @param integer $length The length of the piece to replace. + * @param PropertyPathInterface $path The path to insert. + * @param integer $pathOffset The offset where the inserted piece + * starts in $path. + * @param integer $pathLength The length of the inserted piece. + * If 0, the full path is inserted. + * + * @throws OutOfBoundsException If the offset is invalid. + */ + public function replace($offset, $length, PropertyPathInterface $path, $pathOffset = 0, $pathLength = 0) + { + if (!isset($this->elements[$offset])) { + throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); + } + + if (0 === $pathLength) { + $pathLength = $path->getLength() - $pathOffset; + } + + $this->resize($offset, $length, $pathLength); + + for ($i = 0; $i < $pathLength; ++$i) { + $this->elements[$offset + $i] = $path->getElement($pathOffset + $i); + $this->isIndex[$offset + $i] = $path->isIndex($pathOffset + $i); + } + } + + /** + * Replaces a property element by an index element. + * + * @param integer $offset The offset at which to replace. + * @param string $name The new name of the element. Optional. + * + * @throws OutOfBoundsException If the offset is invalid. + */ + public function replaceByIndex($offset, $name = null) + { + if (!isset($this->elements[$offset])) { + throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); + } + + if (null !== $name) { + $this->elements[$offset] = $name; + } + + $this->isIndex[$offset] = true; + } + + /** + * Replaces an index element by a property element. + * + * @param integer $offset The offset at which to replace. + * @param string $name The new name of the element. Optional. + * + * @throws OutOfBoundsException If the offset is invalid. + */ + public function replaceByProperty($offset, $name = null) + { + if (!isset($this->elements[$offset])) { + throw new OutOfBoundsException('The offset ' . $offset . ' is not within the property path'); + } + + if (null !== $name) { + $this->elements[$offset] = $name; + } + + $this->isIndex[$offset] = false; + } + + /** + * Returns the length of the current path. + * + * @return integer The path length. + */ + public function getLength() + { + return count($this->elements); + } + + /** + * Returns the current property path. + * + * @return PropertyPathInterface The constructed property path. + */ + public function getPropertyPath() + { + $pathAsString = $this->__toString(); + + return '' !== $pathAsString ? new PropertyPath($pathAsString) : null; + } + + /** + * Returns the current property path as string. + * + * @return string The property path as string. + */ + public function __toString() + { + $string = ''; + + foreach ($this->elements as $offset => $element) { + if ($this->isIndex[$offset]) { + $element = '[' . $element . ']'; + } elseif ('' !== $string) { + $string .= '.'; + } + + $string .= $element; + } + + return $string; + } + + /** + * Resizes the path so that a chunk of length $cutLength is + * removed at $offset and another chunk of length $insertionLength + * can be inserted. + * + * @param integer $offset The offset where the removed chunk starts. + * @param integer $cutLength The length of the removed chunk. + * @param integer $insertionLength The length of the inserted chunk. + */ + private function resize($offset, $cutLength, $insertionLength) + { + // Nothing else to do in this case + if ($insertionLength === $cutLength) { + return; + } + + $length = count($this->elements); + + if ($cutLength > $insertionLength) { + // More elements should be removed than inserted + $diff = $cutLength - $insertionLength; + $newLength = $length - $diff; + + // Shift elements to the left (left-to-right until the new end) + // Max allowed offset to be shifted is such that + // $offset + $diff < $length (otherwise invalid index access) + // i.e. $offset < $length - $diff = $newLength + for ($i = $offset; $i < $newLength; ++$i) { + $this->elements[$i] = $this->elements[$i + $diff]; + $this->isIndex[$i] = $this->isIndex[$i + $diff]; + } + + // All remaining elements should be removed + for (; $i < $length; ++$i) { + unset($this->elements[$i]); + unset($this->isIndex[$i]); + } + } else { + $diff = $insertionLength - $cutLength; + + $newLength = $length + $diff; + $indexAfterInsertion = $offset + $insertionLength; + + // $diff <= $insertionLength + // $indexAfterInsertion >= $insertionLength + // => $diff <= $indexAfterInsertion + + // In each of the following loops, $i >= $diff must hold, + // otherwise ($i - $diff) becomes negative. + + // Shift old elements to the right to make up space for the + // inserted elements. This needs to be done left-to-right in + // order to preserve an ascending array index order + // Since $i = max($length, $indexAfterInsertion) and $indexAfterInsertion >= $diff, + // $i >= $diff is guaranteed. + for ($i = max($length, $indexAfterInsertion); $i < $newLength; ++$i) { + $this->elements[$i] = $this->elements[$i - $diff]; + $this->isIndex[$i] = $this->isIndex[$i - $diff]; + } + + // Shift remaining elements to the right. Do this right-to-left + // so we don't overwrite elements before copying them + // The last written index is the immediate index after the inserted + // string, because the indices before that will be overwritten + // anyway. + // Since $i >= $indexAfterInsertion and $indexAfterInsertion >= $diff, + // $i >= $diff is guaranteed. + for ($i = $length - 1; $i >= $indexAfterInsertion; --$i) { + $this->elements[$i] = $this->elements[$i - $diff]; + $this->isIndex[$i] = $this->isIndex[$i - $diff]; + } + } + } +} diff --git a/src/Symfony/Component/PropertyAccess/PropertyPathInterface.php b/src/Symfony/Component/PropertyAccess/PropertyPathInterface.php new file mode 100644 index 0000000000..fb95f1464d --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyPathInterface.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * A sequence of property names or array indices. + * + * @author Bernhard Schussek + */ +interface PropertyPathInterface extends \Traversable +{ + /** + * Returns the string representation of the property path + * + * @return string The path as string. + */ + public function __toString(); + + /** + * Returns the length of the property path, i.e. the number of elements. + * + * @return integer The path length. + */ + public function getLength(); + + /** + * Returns the parent property path. + * + * The parent property path is the one that contains the same items as + * this one except for the last one. + * + * If this property path only contains one item, null is returned. + * + * @return PropertyPath The parent path or null. + */ + public function getParent(); + + /** + * Returns the elements of the property path as array + * + * @return array An array of property/index names + */ + public function getElements(); + + /** + * Returns the element at the given index in the property path + * + * @param integer $index The index key + * + * @return string A property or index name + * + * @throws Exception\OutOfBoundsException If the offset is invalid. + */ + public function getElement($index); + + /** + * Returns whether the element at the given index is a property + * + * @param integer $index The index in the property path + * + * @return Boolean Whether the element at this index is a property + * + * @throws Exception\OutOfBoundsException If the offset is invalid. + */ + public function isProperty($index); + + /** + * Returns whether the element at the given index is an array index + * + * @param integer $index The index in the property path + * + * @return Boolean Whether the element at this index is an array index + * + * @throws Exception\OutOfBoundsException If the offset is invalid. + */ + public function isIndex($index); +} diff --git a/src/Symfony/Component/PropertyAccess/PropertyPathIterator.php b/src/Symfony/Component/PropertyAccess/PropertyPathIterator.php new file mode 100644 index 0000000000..d6cd49caa0 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyPathIterator.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Traverses a property path and provides additional methods to find out + * information about the current element + * + * @author Bernhard Schussek + */ +class PropertyPathIterator extends \ArrayIterator implements PropertyPathIteratorInterface +{ + /** + * The traversed property path + * @var PropertyPathInterface + */ + protected $path; + + /** + * Constructor. + * + * @param PropertyPathInterface $path The property path to traverse + */ + public function __construct(PropertyPathInterface $path) + { + parent::__construct($path->getElements()); + + $this->path = $path; + } + + /** + * {@inheritdoc} + */ + public function isIndex() + { + return $this->path->isIndex($this->key()); + } + + /** + * {@inheritdoc} + */ + public function isProperty() + { + return $this->path->isProperty($this->key()); + } +} diff --git a/src/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php b/src/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php new file mode 100644 index 0000000000..cb43f8d7ea --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/PropertyPathIteratorInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * @author Bernhard Schussek + */ +interface PropertyPathIteratorInterface extends \Iterator, \SeekableIterator +{ + /** + * Returns whether the current element in the property path is an array + * index. + * + * @return Boolean + */ + public function isIndex(); + + /** + * Returns whether the current element in the property path is a property + * name. + * + * @return Boolean + */ + public function isProperty(); +} diff --git a/src/Symfony/Component/PropertyAccess/README.md b/src/Symfony/Component/PropertyAccess/README.md new file mode 100644 index 0000000000..0ae94e0879 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/README.md @@ -0,0 +1,14 @@ +PropertyAccess Component +======================== + +PropertyAccess reads/writes values from/to object/array graphs using a simple +string notation. + +Resources +--------- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/PropertyAccess/ + $ composer.phar install --dev + $ phpunit diff --git a/src/Symfony/Component/PropertyAccess/StringUtil.php b/src/Symfony/Component/PropertyAccess/StringUtil.php new file mode 100644 index 0000000000..012ed8846b --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/StringUtil.php @@ -0,0 +1,192 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess; + +/** + * Creates singulars from plurals. + * + * @author Bernhard Schussek + */ +class StringUtil +{ + /** + * Map english plural to singular suffixes + * + * @var array + * + * @see http://english-zone.com/spelling/plurals.html + * @see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English + */ + private static $pluralMap = array( + // First entry: plural suffix, reversed + // Second entry: length of plural suffix + // Third entry: Whether the suffix may succeed a vocal + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: singular suffix, normal + + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + array('a', 1, true, true, array('on', 'um')), + + // nebulae (nebula) + array('ea', 2, true, true, 'a'), + + // mice (mouse), lice (louse) + array('eci', 3, false, true, 'ouse'), + + // geese (goose) + array('esee', 4, false, true, 'oose'), + + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + array('i', 1, true, true, 'us'), + + // men (man), women (woman) + array('nem', 3, true, true, 'man'), + + // children (child) + array('nerdlihc', 8, true, true, 'child'), + + // oxen (ox) + array('nexo', 4, false, false, 'ox'), + + // indices (index), appendices (appendix), prices (price) + array('seci', 4, false, true, array('ex', 'ix', 'ice')), + + // babies (baby) + array('sei', 3, false, true, 'y'), + + // analyses (analysis), ellipses (ellipsis), funguses (fungus), + // neuroses (neurosis), theses (thesis), emphases (emphasis), + // oases (oasis), crises (crisis), houses (house), bases (base), + // atlases (atlas), kisses (kiss) + array('ses', 3, true, true, array('s', 'se', 'sis')), + + // lives (life), wives (wife) + array('sevi', 4, false, true, 'ife'), + + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + array('sev', 3, true, true, 'f'), + + // axes (axis), axes (ax), axes (axe) + array('sexa', 4, false, false, array('ax', 'axe', 'axis')), + + // indexes (index), matrixes (matrix) + array('sex', 3, true, false, 'x'), + + // quizzes (quiz) + array('sezz', 4, true, false, 'z'), + + // bureaus (bureau) + array('suae', 4, false, true, 'eau'), + + // roses (rose), garages (garage), cassettes (cassette), + // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), + // shoes (shoe) + array('se', 2, true, true, array('', 'e')), + + // tags (tag) + array('s', 1, true, true, ''), + + // chateaux (chateau) + array('xuae', 4, false, true, 'eau'), + ); + + /** + * This class should not be instantiated + */ + private function __construct() {} + + /** + * Returns the singular form of a word + * + * If the method can't determine the form with certainty, an array of the + * possible singulars is returned. + * + * @param string $plural A word in plural form + * @return string|array The singular form or an array of possible singular + * forms + */ + public static function singularify($plural) + { + $pluralRev = strrev($plural); + $lowerPluralRev = strtolower($pluralRev); + $pluralLength = strlen($lowerPluralRev); + + // The outer loop iterates over the entries of the plural table + // The inner loop $j iterates over the characters of the plural suffix + // in the plural table to compare them with the characters of the actual + // given plural suffix + foreach (self::$pluralMap as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + + // Compare characters in the plural table and of the suffix of the + // given plural one by one + while ($suffix[$j] === $lowerPluralRev[$j]) { + // Let $j point to the next character + ++$j; + + // Successfully compared the last character + // Add an entry with the singular suffix to the singular array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $pluralLength) { + $nextIsVocal = false !== strpos('aeiou', $lowerPluralRev[$j]); + + if (!$map[2] && $nextIsVocal) { + // suffix may not succeed a vocal but next char is one + break; + } + + if (!$map[3] && !$nextIsVocal) { + // suffix may not succeed a consonant but next char is one + break; + } + } + + $newBase = substr($plural, 0, $pluralLength - $suffixLength); + $newSuffix = $map[4]; + + // Check whether the first character in the plural suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = ctype_upper($pluralRev[$j - 1]); + + if (is_array($newSuffix)) { + $singulars = array(); + + foreach ($newSuffix as $newSuffixEntry) { + $singulars[] = $newBase . ($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); + } + + return $singulars; + } + + return $newBase . ($firstUpper ? ucFirst($newSuffix) : $newSuffix); + } + + // Suffix is longer than word + if ($j === $pluralLength) { + break; + } + } + } + + // Convert teeth to tooth, feet to foot + if (false !== ($pos = strpos($plural, 'ee'))) { + return substr_replace($plural, 'oo', $pos, 2); + } + + // Assume that plural and singular is identical + return $plural; + } +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/Author.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/Author.php new file mode 100644 index 0000000000..ed2331bab0 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/Author.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; + +class Author +{ + public $firstName; + private $lastName; + private $australian; + public $child; + private $readPermissions; + + private $privateProperty; + + public function setLastName($lastName) + { + $this->lastName = $lastName; + } + + public function getLastName() + { + return $this->lastName; + } + + private function getPrivateGetter() + { + return 'foobar'; + } + + public function setAustralian($australian) + { + $this->australian = $australian; + } + + public function isAustralian() + { + return $this->australian; + } + + public function setReadPermissions($bool) + { + $this->readPermissions = $bool; + } + + public function hasReadPermissions() + { + return $this->readPermissions; + } + + private function isPrivateIsser() + { + return true; + } + + public function getPrivateSetter() + { + } + + private function setPrivateSetter($data) + { + } +} diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Magician.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/Magician.php similarity index 89% rename from src/Symfony/Component/Form/Tests/Fixtures/Magician.php rename to src/Symfony/Component/PropertyAccess/Tests/Fixtures/Magician.php index cd66f29d07..6faa5dbf7b 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Magician.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/Magician.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Tests\Fixtures; +namespace Symfony\Component\PropertyAccess\Tests\Fixtures; class Magician { diff --git a/src/Symfony/Component/Form/Tests/Util/PropertyPathArrayObjectTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayObjectTest.php similarity index 73% rename from src/Symfony/Component/Form/Tests/Util/PropertyPathArrayObjectTest.php rename to src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayObjectTest.php index 96ddc6d6f0..aaa86b3c25 100644 --- a/src/Symfony/Component/Form/Tests/Util/PropertyPathArrayObjectTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayObjectTest.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Tests\Util; +namespace Symfony\Component\PropertyAccess\Tests; -class PropertyPathArrayObjectTest extends PropertyPathCollectionTest +class PropertyAccessorArrayObjectTest extends PropertyAccessorCollectionTest { protected function getCollection(array $array) { diff --git a/src/Symfony/Component/Form/Tests/Util/PropertyPathArrayTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayTest.php similarity index 73% rename from src/Symfony/Component/Form/Tests/Util/PropertyPathArrayTest.php rename to src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayTest.php index ce726c80f8..5ab63c67cb 100644 --- a/src/Symfony/Component/Form/Tests/Util/PropertyPathArrayTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayTest.php @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Tests\Util; +namespace Symfony\Component\PropertyAccess\Tests; -class PropertyPathArrayTest extends PropertyPathCollectionTest +class PropertyAccessorArrayTest extends PropertyAccessorCollectionTest { protected function getCollection(array $array) { diff --git a/src/Symfony/Component/Form/Tests/Util/PropertyPathCollectionTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCollectionTest.php similarity index 73% rename from src/Symfony/Component/Form/Tests/Util/PropertyPathCollectionTest.php rename to src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCollectionTest.php index 2f7589663e..a91f1ddf5a 100644 --- a/src/Symfony/Component/Form/Tests/Util/PropertyPathCollectionTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCollectionTest.php @@ -9,12 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Tests\Util; +namespace Symfony\Component\PropertyAccess\Tests; -use Symfony\Component\Form\Util\PropertyPath; -use Symfony\Component\Form\Util\FormUtil; +use Symfony\Component\PropertyAccess\Exception\ExceptionInterface; +use Symfony\Component\PropertyAccess\PropertyAccessor; +use Symfony\Component\PropertyAccess\StringUtil; -class PropertyPathCollectionTest_Car +class PropertyAccessorCollectionTest_Car { private $axes; @@ -23,7 +24,7 @@ class PropertyPathCollectionTest_Car $this->axes = $axes; } - // In the test, use a name that FormUtil can't uniquely singularify + // In the test, use a name that StringUtil can't uniquely singularify public function addAxis($axis) { $this->axes[] = $axis; @@ -46,7 +47,7 @@ class PropertyPathCollectionTest_Car } } -class PropertyPathCollectionTest_CarCustomSingular +class PropertyAccessorCollectionTest_CarCustomSingular { public function addFoo($axis) {} @@ -55,44 +56,44 @@ class PropertyPathCollectionTest_CarCustomSingular public function getAxes() {} } -class PropertyPathCollectionTest_Engine +class PropertyAccessorCollectionTest_Engine { } -class PropertyPathCollectionTest_CarOnlyAdder +class PropertyAccessorCollectionTest_CarOnlyAdder { public function addAxis($axis) {} public function getAxes() {} } -class PropertyPathCollectionTest_CarOnlyRemover +class PropertyAccessorCollectionTest_CarOnlyRemover { public function removeAxis($axis) {} public function getAxes() {} } -class PropertyPathCollectionTest_CarNoAdderAndRemover +class PropertyAccessorCollectionTest_CarNoAdderAndRemover { public function getAxes() {} } -class PropertyPathCollectionTest_CarNoAdderAndRemoverWithProperty +class PropertyAccessorCollectionTest_CarNoAdderAndRemoverWithProperty { protected $axes = array(); public function getAxes() {} } -class PropertyPathCollectionTest_CompositeCar +class PropertyAccessorCollectionTest_CompositeCar { public function getStructure() {} public function setStructure($structure) {} } -class PropertyPathCollectionTest_CarStructure +class PropertyAccessorCollectionTest_CarStructure { public function addAxis($axis) {} @@ -101,44 +102,47 @@ class PropertyPathCollectionTest_CarStructure public function getAxes() {} } -abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase +abstract class PropertyAccessorCollectionTest extends \PHPUnit_Framework_TestCase { + /** + * @var PropertyAccessor + */ + private $propertyAccessor; + + protected function setUp() + { + $this->propertyAccessor = new PropertyAccessor(); + } + abstract protected function getCollection(array $array); public function testGetValueReadsArrayAccess() { $object = $this->getCollection(array('firstName' => 'Bernhard')); - $path = new PropertyPath('[firstName]'); - - $this->assertEquals('Bernhard', $path->getValue($object)); + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($object, '[firstName]')); } public function testGetValueReadsNestedArrayAccess() { $object = $this->getCollection(array('person' => array('firstName' => 'Bernhard'))); - $path = new PropertyPath('[person][firstName]'); - - $this->assertEquals('Bernhard', $path->getValue($object)); + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($object, '[person][firstName]')); } /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyException + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException */ public function testGetValueThrowsExceptionIfArrayAccessExpected() { - $path = new PropertyPath('[firstName]'); - - $path->getValue(new \stdClass()); + $this->propertyAccessor->getValue(new \stdClass(), '[firstName]'); } public function testSetValueUpdatesArrayAccess() { $object = $this->getCollection(array()); - $path = new PropertyPath('[firstName]'); - $path->setValue($object, 'Bernhard'); + $this->propertyAccessor->setValue($object, '[firstName]', 'Bernhard'); $this->assertEquals('Bernhard', $object['firstName']); } @@ -147,20 +151,17 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase { $object = $this->getCollection(array()); - $path = new PropertyPath('[person][firstName]'); - $path->setValue($object, 'Bernhard'); + $this->propertyAccessor->setValue($object, '[person][firstName]', 'Bernhard'); $this->assertEquals('Bernhard', $object['person']['firstName']); } /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyException + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException */ public function testSetValueThrowsExceptionIfArrayAccessExpected() { - $path = new PropertyPath('[firstName]'); - - $path->setValue(new \stdClass(), 'Bernhard'); + $this->propertyAccessor->setValue(new \stdClass(), '[firstName]', 'Bernhard'); } public function testSetValueCallsAdderAndRemoverForCollections() @@ -172,11 +173,9 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase // Don't use a mock in order to test whether the collections are // modified while iterating them - $car = new PropertyPathCollectionTest_Car($axesBefore); + $car = new PropertyAccessorCollectionTest_Car($axesBefore); - $path = new PropertyPath('axes'); - - $path->setValue($car, $axesMerged); + $this->propertyAccessor->setValue($car, 'axes', $axesMerged); $this->assertEquals($axesAfter, $car->getAxes()); @@ -191,8 +190,6 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase $axesBefore = $this->getCollection(array(1 => 'second', 3 => 'fourth')); $axesAfter = $this->getCollection(array(0 => 'first', 1 => 'second', 2 => 'third')); - $path = new PropertyPath('structure.axes'); - $car->expects($this->any()) ->method('getStructure') ->will($this->returnValue($structure)); @@ -210,7 +207,7 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase ->method('addAxis') ->with('third'); - $path->setValue($car, $axesAfter); + $this->propertyAccessor->setValue($car, 'structure.axes', $axesAfter); } public function testSetValueCallsCustomAdderAndRemover() @@ -221,8 +218,6 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase $axesBefore = $this->getCollection(array(1 => 'second', 3 => 'fourth')); $axesAfter = $this->getCollection(array(0 => 'first', 1 => 'second', 2 => 'third')); - $path = new PropertyPath('axes|foo'); - $car->expects($this->at(0)) ->method('getAxes') ->will($this->returnValue($axesBefore)); @@ -236,43 +231,39 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase ->method('addFoo') ->with('third'); - $path->setValue($car, $axesAfter); + $this->propertyAccessor->setValue($car, 'axes|foo', $axesAfter); } /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyException + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException */ - public function testMapFormToDataFailsIfOnlyAdderFound() + public function testSetValueFailsIfOnlyAdderFound() { $car = $this->getMock(__CLASS__ . '_CarOnlyAdder'); $axesBefore = $this->getCollection(array(1 => 'second', 3 => 'fourth')); $axesAfter = $this->getCollection(array(0 => 'first', 1 => 'second', 2 => 'third')); - $path = new PropertyPath('axes'); - $car->expects($this->any()) ->method('getAxes') ->will($this->returnValue($axesBefore)); - $path->setValue($car, $axesAfter); + $this->propertyAccessor->setValue($car, 'axes', $axesAfter); } /** - * @expectedException \Symfony\Component\Form\Exception\InvalidPropertyException + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException */ - public function testMapFormToDataFailsIfOnlyRemoverFound() + public function testSetValueFailsIfOnlyRemoverFound() { $car = $this->getMock(__CLASS__ . '_CarOnlyRemover'); $axesBefore = $this->getCollection(array(1 => 'second', 3 => 'fourth')); $axesAfter = $this->getCollection(array(0 => 'first', 1 => 'second', 2 => 'third')); - $path = new PropertyPath('axes'); - $car->expects($this->any()) ->method('getAxes') ->will($this->returnValue($axesBefore)); - $path->setValue($car, $axesAfter); + $this->propertyAccessor->setValue($car, 'axes', $axesAfter); } /** @@ -283,9 +274,9 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase $axes = $this->getCollection(array(0 => 'first', 1 => 'second', 2 => 'third')); try { - $path->setValue($car, $axes); + $this->propertyAccessor->setValue($car, $path, $axes); $this->fail('An expected exception was not thrown!'); - } catch (\Symfony\Component\Form\Exception\Exception $e) { + } catch (ExceptionInterface $e) { $this->assertEquals($message, $e->getMessage()); } } @@ -295,7 +286,7 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase $data = array(); $car = $this->getMock(__CLASS__ . '_CarNoAdderAndRemover'); - $propertyPath = new PropertyPath('axes'); + $propertyPath = 'axes'; $expectedMessage = sprintf( 'Neither element "axes" nor method "setAxes()" exists in class ' .'"%s", nor could adders and removers be found based on the ' @@ -304,7 +295,7 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase // .'property path with "|{singular}" to override the guesser)' , get_class($car), - implode(', ', (array) $singulars = FormUtil::singularify('Axes')) + implode(', ', (array) $singulars = StringUtil::singularify('Axes')) ); $data[] = array($car, $propertyPath, $expectedMessage); @@ -323,7 +314,7 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase */ $car = $this->getMock(__CLASS__ . '_CarNoAdderAndRemoverWithProperty'); - $propertyPath = new PropertyPath('axes'); + $propertyPath = 'axes'; $expectedMessage = sprintf( 'Property "axes" is not public in class "%s", nor could adders and ' .'removers be found based on the guessed singulars: %s' @@ -332,7 +323,7 @@ abstract class PropertyPathCollectionTest extends \PHPUnit_Framework_TestCase . '. Maybe you should ' .'create the method "setAxes()"?', get_class($car), - implode(', ', (array) $singulars = FormUtil::singularify('Axes')) + implode(', ', (array) $singulars = StringUtil::singularify('Axes')) ); $data[] = array($car, $propertyPath, $expectedMessage); diff --git a/src/Symfony/Component/Form/Tests/Util/PropertyPathCustomArrayObjectTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCustomArrayObjectTest.php similarity index 75% rename from src/Symfony/Component/Form/Tests/Util/PropertyPathCustomArrayObjectTest.php rename to src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCustomArrayObjectTest.php index a8c6476372..369614c70f 100644 --- a/src/Symfony/Component/Form/Tests/Util/PropertyPathCustomArrayObjectTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCustomArrayObjectTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Tests\Util; +namespace Symfony\Component\PropertyAccess\Tests; use Symfony\Component\Form\Tests\Fixtures\CustomArrayObject; -class PropertyPathCustomArrayObjectTest extends PropertyPathCollectionTest +class PropertyAccessorCustomArrayObjectTest extends PropertyAccessorCollectionTest { protected function getCollection(array $array) { diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php new file mode 100644 index 0000000000..f2d4bd7552 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -0,0 +1,334 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use Symfony\Component\PropertyAccess\PropertyAccessor; +use Symfony\Component\PropertyAccess\Tests\Fixtures\Author; +use Symfony\Component\PropertyAccess\Tests\Fixtures\Magician; + +class PropertyAccessorTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var PropertyAccessor + */ + private $propertyAccessor; + + protected function setUp() + { + $this->propertyAccessor = new PropertyAccessor(); + } + + public function testGetValueReadsArray() + { + $array = array('firstName' => 'Bernhard'); + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($array, '[firstName]')); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testGetValueThrowsExceptionIfIndexNotationExpected() + { + $array = array('firstName' => 'Bernhard'); + + $this->propertyAccessor->getValue($array, 'firstName'); + } + + public function testGetValueReadsZeroIndex() + { + $array = array('Bernhard'); + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($array, '[0]')); + } + + public function testGetValueReadsIndexWithSpecialChars() + { + $array = array('%!@$§.' => 'Bernhard'); + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($array, '[%!@$§.]')); + } + + public function testGetValueReadsNestedIndexWithSpecialChars() + { + $array = array('root' => array('%!@$§.' => 'Bernhard')); + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($array, '[root][%!@$§.]')); + } + + public function testGetValueReadsArrayWithCustomPropertyPath() + { + $array = array('child' => array('index' => array('firstName' => 'Bernhard'))); + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($array, '[child][index][firstName]')); + } + + public function testGetValueReadsArrayWithMissingIndexForCustomPropertyPath() + { + $array = array('child' => array('index' => array())); + + $this->assertNull($this->propertyAccessor->getValue($array, '[child][index][firstName]')); + } + + public function testGetValueReadsProperty() + { + $object = new Author(); + $object->firstName = 'Bernhard'; + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($object, 'firstName')); + } + + public function testGetValueIgnoresSingular() + { + $this->markTestSkipped('This feature is temporarily disabled as of 2.1'); + + $object = (object) array('children' => 'Many'); + + $this->assertEquals('Many', $this->propertyAccessor->getValue($object, 'children|child')); + } + + public function testGetValueReadsPropertyWithSpecialCharsExceptDot() + { + $array = (object) array('%!@$§' => 'Bernhard'); + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($array, '%!@$§')); + } + + public function testGetValueReadsPropertyWithCustomPropertyPath() + { + $object = new Author(); + $object->child = array(); + $object->child['index'] = new Author(); + $object->child['index']->firstName = 'Bernhard'; + + $this->assertEquals('Bernhard', $this->propertyAccessor->getValue($object, 'child[index].firstName')); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException + */ + public function testGetValueThrowsExceptionIfPropertyIsNotPublic() + { + $this->propertyAccessor->getValue(new Author(), 'privateProperty'); + } + + public function testGetValueReadsGetters() + { + $object = new Author(); + $object->setLastName('Schussek'); + + $this->assertEquals('Schussek', $this->propertyAccessor->getValue($object, 'lastName')); + } + + public function testGetValueCamelizesGetterNames() + { + $object = new Author(); + $object->setLastName('Schussek'); + + $this->assertEquals('Schussek', $this->propertyAccessor->getValue($object, 'last_name')); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException + */ + public function testGetValueThrowsExceptionIfGetterIsNotPublic() + { + $this->propertyAccessor->getValue(new Author(), 'privateGetter'); + } + + public function testGetValueReadsIssers() + { + $object = new Author(); + $object->setAustralian(false); + + $this->assertFalse($this->propertyAccessor->getValue($object, 'australian')); + } + + public function testGetValueReadHassers() + { + $object = new Author(); + $object->setReadPermissions(true); + + $this->assertTrue($this->propertyAccessor->getValue($object, 'read_permissions')); + } + + public function testGetValueReadsMagicGet() + { + $object = new Magician(); + $object->__set('magicProperty', 'foobar'); + + $this->assertSame('foobar', $this->propertyAccessor->getValue($object, 'magicProperty')); + } + + /* + * https://github.com/symfony/symfony/pull/4450 + */ + public function testGetValueReadsMagicGetThatReturnsConstant() + { + $object = new Magician(); + + $this->assertNull($this->propertyAccessor->getValue($object, 'magicProperty')); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException + */ + public function testGetValueThrowsExceptionIfIsserIsNotPublic() + { + $this->propertyAccessor->getValue(new Author(), 'privateIsser'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testGetValueThrowsExceptionIfPropertyDoesNotExist() + { + $this->propertyAccessor->getValue(new Author(), 'foobar'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testGetValueThrowsExceptionIfNotObjectOrArray() + { + $this->propertyAccessor->getValue('baz', 'foobar'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testGetValueThrowsExceptionIfNull() + { + $this->propertyAccessor->getValue(null, 'foobar'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testGetValueThrowsExceptionIfEmpty() + { + $this->propertyAccessor->getValue('', 'foobar'); + } + + public function testSetValueUpdatesArrays() + { + $array = array(); + + $this->propertyAccessor->setValue($array, '[firstName]', 'Bernhard'); + + $this->assertEquals(array('firstName' => 'Bernhard'), $array); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testSetValueThrowsExceptionIfIndexNotationExpected() + { + $array = array(); + + $this->propertyAccessor->setValue($array, 'firstName', 'Bernhard'); + } + + public function testSetValueUpdatesArraysWithCustomPropertyPath() + { + $array = array(); + + $this->propertyAccessor->setValue($array, '[child][index][firstName]', 'Bernhard'); + + $this->assertEquals(array('child' => array('index' => array('firstName' => 'Bernhard'))), $array); + } + + public function testSetValueUpdatesProperties() + { + $object = new Author(); + + $this->propertyAccessor->setValue($object, 'firstName', 'Bernhard'); + + $this->assertEquals('Bernhard', $object->firstName); + } + + public function testSetValueUpdatesPropertiesWithCustomPropertyPath() + { + $object = new Author(); + $object->child = array(); + $object->child['index'] = new Author(); + + $this->propertyAccessor->setValue($object, 'child[index].firstName', 'Bernhard'); + + $this->assertEquals('Bernhard', $object->child['index']->firstName); + } + + public function testSetValueUpdateMagicSet() + { + $object = new Magician(); + + $this->propertyAccessor->setValue($object, 'magicProperty', 'foobar'); + + $this->assertEquals('foobar', $object->__get('magicProperty')); + } + + public function testSetValueUpdatesSetters() + { + $object = new Author(); + + $this->propertyAccessor->setValue($object, 'lastName', 'Schussek'); + + $this->assertEquals('Schussek', $object->getLastName()); + } + + public function testSetValueCamelizesSetterNames() + { + $object = new Author(); + + $this->propertyAccessor->setValue($object, 'last_name', 'Schussek'); + + $this->assertEquals('Schussek', $object->getLastName()); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\PropertyAccessDeniedException + */ + public function testSetValueThrowsExceptionIfGetterIsNotPublic() + { + $this->propertyAccessor->setValue(new Author(), 'privateSetter', 'foobar'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testSetValueThrowsExceptionIfNotObjectOrArray() + { + $value = 'baz'; + + $this->propertyAccessor->setValue($value, 'foobar', 'bam'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testSetValueThrowsExceptionIfNull() + { + $value = null; + + $this->propertyAccessor->setValue($value, 'foobar', 'bam'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testSetValueThrowsExceptionIfEmpty() + { + $value = ''; + + $this->propertyAccessor->setValue($value, 'foobar', 'bam'); + } +} diff --git a/src/Symfony/Component/Form/Tests/Util/PropertyPathBuilderTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyPathBuilderTest.php similarity index 97% rename from src/Symfony/Component/Form/Tests/Util/PropertyPathBuilderTest.php rename to src/Symfony/Component/PropertyAccess/Tests/PropertyPathBuilderTest.php index 6649bdcdc9..ce8951daf0 100644 --- a/src/Symfony/Component/Form/Tests/Util/PropertyPathBuilderTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyPathBuilderTest.php @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Tests\Util; +namespace Symfony\Component\PropertyAccess\Tests; -use Symfony\Component\Form\Util\PropertyPath; -use Symfony\Component\Form\Util\PropertyPathBuilder; +use Symfony\Component\PropertyAccess\PropertyPath; +use Symfony\Component\PropertyAccess\PropertyPathBuilder; /** * @author Bernhard Schussek diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php new file mode 100644 index 0000000000..3548ad6ff0 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyPathTest.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +use Symfony\Component\PropertyAccess\PropertyPath; +use Symfony\Component\PropertyAccess\Tests\Fixtures\Author; +use Symfony\Component\PropertyAccess\Tests\Fixtures\Magician; + +class PropertyPathTest extends \PHPUnit_Framework_TestCase +{ + public function testToString() + { + $path = new PropertyPath('reference.traversable[index].property'); + + $this->assertEquals('reference.traversable[index].property', $path->__toString()); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testInvalidPropertyPath_noDotBeforeProperty() + { + new PropertyPath('[index]property'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testInvalidPropertyPath_dotAtTheBeginning() + { + new PropertyPath('.property'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testInvalidPropertyPath_unexpectedCharacters() + { + new PropertyPath('property.$foo'); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidPropertyPathException + */ + public function testInvalidPropertyPath_empty() + { + new PropertyPath(''); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testInvalidPropertyPath_null() + { + new PropertyPath(null); + } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException + */ + public function testInvalidPropertyPath_false() + { + new PropertyPath(false); + } + + public function testValidPropertyPath_zero() + { + new PropertyPath('0'); + } + + public function testGetParent_dot() + { + $propertyPath = new PropertyPath('grandpa.parent.child'); + + $this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent()); + } + + public function testGetParent_index() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertEquals(new PropertyPath('grandpa.parent'), $propertyPath->getParent()); + } + + public function testGetParent_noParent() + { + $propertyPath = new PropertyPath('path'); + + $this->assertNull($propertyPath->getParent()); + } + + public function testCopyConstructor() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + $copy = new PropertyPath($propertyPath); + + $this->assertEquals($propertyPath, $copy); + } + + public function testGetElement() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertEquals('child', $propertyPath->getElement(2)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testGetElementDoesNotAcceptInvalidIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->getElement(3); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testGetElementDoesNotAcceptNegativeIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->getElement(-1); + } + + public function testIsProperty() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertTrue($propertyPath->isProperty(1)); + $this->assertFalse($propertyPath->isProperty(2)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsPropertyDoesNotAcceptInvalidIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isProperty(3); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsPropertyDoesNotAcceptNegativeIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isProperty(-1); + } + + public function testIsIndex() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $this->assertFalse($propertyPath->isIndex(1)); + $this->assertTrue($propertyPath->isIndex(2)); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsIndexDoesNotAcceptInvalidIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isIndex(3); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testIsIndexDoesNotAcceptNegativeIndices() + { + $propertyPath = new PropertyPath('grandpa.parent[child]'); + + $propertyPath->isIndex(-1); + } +} diff --git a/src/Symfony/Component/Form/Tests/Util/FormUtilTest.php b/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php similarity index 95% rename from src/Symfony/Component/Form/Tests/Util/FormUtilTest.php rename to src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php index c70c0d6fcc..3c36f91a9b 100644 --- a/src/Symfony/Component/Form/Tests/Util/FormUtilTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php @@ -9,11 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Form\Tests\Util; +namespace Symfony\Component\PropertyAccess\Tests; -use Symfony\Component\Form\Util\FormUtil; +use Symfony\Component\PropertyAccess\StringUtil; -class FormUtilTest extends \PHPUnit_Framework_TestCase +class StringUtilTest extends \PHPUnit_Framework_TestCase { public function singularifyProvider() { @@ -130,6 +130,6 @@ class FormUtilTest extends \PHPUnit_Framework_TestCase */ public function testSingularify($plural, $singular) { - $this->assertEquals($singular, FormUtil::singularify($plural)); + $this->assertEquals($singular, StringUtil::singularify($plural)); } } diff --git a/src/Symfony/Component/PropertyAccess/composer.json b/src/Symfony/Component/PropertyAccess/composer.json new file mode 100644 index 0000000000..3b85c0308e --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/composer.json @@ -0,0 +1,31 @@ +{ + "name": "symfony/property-access", + "type": "library", + "description": "Symfony PropertyAccess Component", + "keywords": ["property", "index", "access", "object", "array", "extraction", "injection", "reflection", "property path"], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "autoload": { + "psr-0": { "Symfony\\Component\\PropertyAccess\\": "" } + }, + "target-dir": "Symfony/Component/PropertyAccess", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + } +} diff --git a/src/Symfony/Component/PropertyAccess/phpunit.xml.dist b/src/Symfony/Component/PropertyAccess/phpunit.xml.dist new file mode 100644 index 0000000000..8799eaccf5 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + + + + From 6b1652e5eec9e714f4da46436551f877801ff101 Mon Sep 17 00:00:00 2001 From: Yaroslav Kiliba Date: Tue, 31 Jul 2012 14:15:57 +0300 Subject: [PATCH 071/128] [PropertyAccess] Property path, small refactoring, read/writeProperty to read/write Property/Index. --- .../PropertyAccess/PropertyAccessor.php | 323 ++++++++++-------- 1 file changed, 181 insertions(+), 142 deletions(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 229627aa53..d318f1c0c5 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -44,7 +44,7 @@ class PropertyAccessor implements PropertyAccessorInterface throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface'); } - $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 1); + $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength()); return $propertyValues[count($propertyValues) - 1][self::VALUE]; } @@ -60,7 +60,7 @@ class PropertyAccessor implements PropertyAccessorInterface throw new UnexpectedTypeException($propertyPath, 'string or Symfony\Component\PropertyAccess\PropertyPathInterface'); } - $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 2); + $propertyValues =& $this->readPropertiesUntil($objectOrArray, $propertyPath, $propertyPath->getLength() - 1); $overwrite = true; // Add the root object to the list @@ -80,9 +80,12 @@ class PropertyAccessor implements PropertyAccessorInterface $property = $propertyPath->getElement($i); //$singular = $propertyPath->singulars[$i]; $singular = null; - $isIndex = $propertyPath->isIndex($i); - $this->writeProperty($objectOrArray, $propertyPath, $property, $singular, $isIndex, $value); + if ($propertyPath->isIndex($i)) { + $this->writeIndex($objectOrArray, $property, $value); + } else { + $this->writeProperty($objectOrArray, $property, $singular, $value); + } } $value =& $objectOrArray; @@ -105,7 +108,7 @@ class PropertyAccessor implements PropertyAccessorInterface { $propertyValues = array(); - for ($i = 0; $i <= $lastIndex; ++$i) { + for ($i = 0; $i < $lastIndex; ++$i) { if (!is_object($objectOrArray) && !is_array($objectOrArray)) { throw new UnexpectedTypeException($objectOrArray, 'object or array'); } @@ -119,7 +122,12 @@ class PropertyAccessor implements PropertyAccessorInterface $objectOrArray[$property] = $i + 1 < $propertyPath->getLength() ? array() : null; } - $propertyValue =& $this->readProperty($objectOrArray, $propertyPath, $property, $isIndex); + if ($isIndex) { + $propertyValue =& $this->readIndex($objectOrArray, $property); + } else { + $propertyValue =& $this->readProperty($objectOrArray, $property); + } + $objectOrArray =& $propertyValue[self::VALUE]; $propertyValues[] =& $propertyValue; @@ -128,13 +136,47 @@ class PropertyAccessor implements PropertyAccessorInterface return $propertyValues; } + /** + * Reads a key from an array-like structure. + * + * @param \ArrayAccess|array $array The array or \ArrayAccess object to read from. + * @param string|integer $index The key to read. + * + * @return mixed The value of the key + * + * @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array. + */ + private function &readIndex(&$array, $index) + { + if (!$array instanceof \ArrayAccess && !is_array($array)) { + throw new NoSuchPropertyException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array))); + } + + // Use an array instead of an object since performance is very crucial here + $result = array( + self::VALUE => null, + self::IS_REF => false + ); + + if (isset($array[$index])) { + if (is_array($array)) { + $result[self::VALUE] =& $array[$index]; + $result[self::IS_REF] = true; + } else { + $result[self::VALUE] = $array[$index]; + // Objects are always passed around by reference + $result[self::IS_REF] = is_object($array[$index]) ? true : false; + } + } + + return $result; + } + /** * Reads the a property from an object or array. * - * @param object|array $objectOrArray The object or array to read from. - * @param PropertyPathInterface $propertyPath The property path to read. - * @param string $property The property to read. - * @param Boolean $isIndex Whether to interpret the property as index. + * @param object $object The object to read from. + * @param string $property The property to read. * * @return mixed The value of the read property * @@ -142,7 +184,7 @@ class PropertyAccessor implements PropertyAccessorInterface * @throws PropertyAccessDeniedException If the property cannot be accessed due to * access restrictions (private or protected). */ - private function &readProperty(&$objectOrArray, PropertyPathInterface $propertyPath, $property, $isIndex) + private function &readProperty(&$object, $property) { // Use an array instead of an object since performance is // very crucial here @@ -151,65 +193,52 @@ class PropertyAccessor implements PropertyAccessorInterface self::IS_REF => false ); - if ($isIndex) { - if (!$objectOrArray instanceof \ArrayAccess && !is_array($objectOrArray)) { - throw new NoSuchPropertyException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $property, get_class($objectOrArray))); - } - - if (isset($objectOrArray[$property])) { - if (is_array($objectOrArray)) { - $result[self::VALUE] =& $objectOrArray[$property]; - $result[self::IS_REF] = true; - } else { - $result[self::VALUE] = $objectOrArray[$property]; - } - } - } elseif (is_object($objectOrArray)) { - $camelProp = $this->camelize($property); - $reflClass = new \ReflectionClass($objectOrArray); - $getter = 'get'.$camelProp; - $isser = 'is'.$camelProp; - $hasser = 'has'.$camelProp; - - if ($reflClass->hasMethod($getter)) { - if (!$reflClass->getMethod($getter)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $getter, $reflClass->name)); - } - - $result[self::VALUE] = $objectOrArray->$getter(); - } elseif ($reflClass->hasMethod($isser)) { - if (!$reflClass->getMethod($isser)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $isser, $reflClass->name)); - } - - $result[self::VALUE] = $objectOrArray->$isser(); - } elseif ($reflClass->hasMethod($hasser)) { - if (!$reflClass->getMethod($hasser)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $hasser, $reflClass->name)); - } - - $result[self::VALUE] = $objectOrArray->$hasser(); - } elseif ($reflClass->hasMethod('__get')) { - // needed to support magic method __get - $result[self::VALUE] = $objectOrArray->$property; - } elseif ($reflClass->hasProperty($property)) { - if (!$reflClass->getProperty($property)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s". Maybe you should create the method "%s()" or "%s()" or "%s()"?', $property, $reflClass->name, $getter, $isser, $hasser)); - } - - $result[self::VALUE] =& $objectOrArray->$property; - $result[self::IS_REF] = true; - } elseif (property_exists($objectOrArray, $property)) { - // needed to support \stdClass instances - $result[self::VALUE] =& $objectOrArray->$property; - $result[self::IS_REF] = true; - } else { - throw new NoSuchPropertyException(sprintf('Neither property "%s" nor method "%s()" nor method "%s()" exists in class "%s"', $property, $getter, $isser, $reflClass->name)); - } - } else { + if (!is_object($object)) { throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); } + $camelProp = $this->camelize($property); + $reflClass = new \ReflectionClass($object); + $getter = 'get'.$camelProp; + $isser = 'is'.$camelProp; + $hasser = 'has'.$camelProp; + + if ($reflClass->hasMethod($getter)) { + if (!$reflClass->getMethod($getter)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $getter, $reflClass->name)); + } + + $result[self::VALUE] = $object->$getter(); + } elseif ($reflClass->hasMethod($isser)) { + if (!$reflClass->getMethod($isser)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $isser, $reflClass->name)); + } + + $result[self::VALUE] = $object->$isser(); + } elseif ($reflClass->hasMethod($hasser)) { + if (!$reflClass->getMethod($hasser)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $hasser, $reflClass->name)); + } + + $result[self::VALUE] = $object->$hasser(); + } elseif ($reflClass->hasMethod('__get')) { + // needed to support magic method __get + $result[self::VALUE] = $object->$property; + } elseif ($reflClass->hasProperty($property)) { + if (!$reflClass->getProperty($property)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s". Maybe you should create the method "%s()" or "%s()" or "%s()"?', $property, $reflClass->name, $getter, $isser, $hasser)); + } + + $result[self::VALUE] =& $object->$property; + $result[self::IS_REF] = true; + } elseif (property_exists($object, $property)) { + // needed to support \stdClass instances + $result[self::VALUE] =& $object->$property; + $result[self::IS_REF] = true; + } else { + throw new NoSuchPropertyException(sprintf('Neither property "%s" nor method "%s()" nor method "%s()" exists in class "%s"', $property, $getter, $isser, $reflClass->name)); + } + // Objects are always passed around by reference if (is_object($result[self::VALUE])) { $result[self::IS_REF] = true; @@ -221,108 +250,118 @@ class PropertyAccessor implements PropertyAccessorInterface /** * Sets the value of the property at the given index in the path * - * @param object|array $objectOrArray The object or array to write to. - * @param PropertyPathInterface $propertyPath The property path to write. - * @param string $property The property to write. - * @param string|null $singular The singular form of the property name or null. - * @param Boolean $isIndex Whether to interpret the property as index. - * @param mixed $value The value to write. + * @param \ArrayAccess|array $array An array or \ArrayAccess object to write to. + * @param string|integer $index The index to write at. + * @param mixed $value The value to write. + * + * @throws NoSuchPropertyException If the array does not implement \ArrayAccess or it is not an array. + */ + private function writeIndex(&$array, $index, $value) + { + if (!$array instanceof \ArrayAccess && !is_array($array)) { + throw new NoSuchPropertyException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array))); + } + + $array[$index] = $value; + } + + /** + * Sets the value of the property at the given index in the path + * + * @param object|array $object The object or array to write to. + * @param string $property The property to write. + * @param string|null $singular The singular form of the property name or null. + * @param mixed $value The value to write. * * @throws NoSuchPropertyException If the property does not exist. * @throws PropertyAccessDeniedException If the property cannot be accessed due to * access restrictions (private or protected). */ - private function writeProperty(&$objectOrArray, PropertyPathInterface $propertyPath, $property, $singular, $isIndex, $value) + private function writeProperty(&$object, $property, $singular, $value) { $adderRemoverError = null; - if ($isIndex) { - if (!$objectOrArray instanceof \ArrayAccess && !is_array($objectOrArray)) { - throw new NoSuchPropertyException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $property, get_class($objectOrArray))); - } + if (!is_object($object)) { + throw new NoSuchPropertyException(sprintf('Cannot write property "%s" to an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); + } - $objectOrArray[$property] = $value; - } elseif (is_object($objectOrArray)) { - $reflClass = new \ReflectionClass($objectOrArray); + $reflClass = new \ReflectionClass($object); + $plural = $this->camelize($property); - // The plural form is the last element of the property path - $plural = $this->camelize($propertyPath->getElement($propertyPath->getLength() - 1)); + // Any of the two methods is required, but not yet known + $singulars = null !== $singular ? array($singular) : (array) StringUtil::singularify($plural); - // Any of the two methods is required, but not yet known - $singulars = null !== $singular ? array($singular) : (array) StringUtil::singularify($plural); + if (is_array($value) || $value instanceof \Traversable) { + $methods = $this->findAdderAndRemover($reflClass, $singulars); - if (is_array($value) || $value instanceof \Traversable) { - $methods = $this->findAdderAndRemover($reflClass, $singulars); - if (null !== $methods) { - // At this point the add and remove methods have been found - // Use iterator_to_array() instead of clone in order to prevent side effects - // see https://github.com/symfony/symfony/issues/4670 - $itemsToAdd = is_object($value) ? iterator_to_array($value) : $value; - $itemToRemove = array(); - $propertyValue = $this->readProperty($objectOrArray, $propertyPath, $property, $isIndex); - $previousValue = $propertyValue[self::VALUE]; + if (null !== $methods) { + // At this point the add and remove methods have been found + // Use iterator_to_array() instead of clone in order to prevent side effects + // see https://github.com/symfony/symfony/issues/4670 + $itemsToAdd = is_object($value) ? iterator_to_array($value) : $value; + $itemToRemove = array(); + $propertyValue = $this->readProperty($object, $property); + $previousValue = $propertyValue[self::VALUE]; - if (is_array($previousValue) || $previousValue instanceof \Traversable) { - foreach ($previousValue as $previousItem) { - foreach ($value as $key => $item) { - if ($item === $previousItem) { - // Item found, don't add - unset($itemsToAdd[$key]); + if (is_array($previousValue) || $previousValue instanceof \Traversable) { + foreach ($previousValue as $previousItem) { + foreach ($value as $key => $item) { + if ($item === $previousItem) { + // Item found, don't add + unset($itemsToAdd[$key]); - // Next $previousItem - continue 2; - } + // Next $previousItem + continue 2; } - - // Item not found, add to remove list - $itemToRemove[] = $previousItem; } - } - foreach ($itemToRemove as $item) { - call_user_func(array($objectOrArray, $methods[1]), $item); - } - - foreach ($itemsToAdd as $item) { - call_user_func(array($objectOrArray, $methods[0]), $item); - } - - return; - } else { - $adderRemoverError = ', nor could adders and removers be found based on the '; - if (null === $singular) { - // $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars).' (provide a singular by suffixing the property path with "|{singular}" to override the guesser)'; - $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars); - } else { - $adderRemoverError .= 'passed singular: '.$singular; + // Item not found, add to remove list + $itemToRemove[] = $previousItem; } } - } - $setter = 'set'.$this->camelize($property); - if ($reflClass->hasMethod($setter)) { - if (!$reflClass->getMethod($setter)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $setter, $reflClass->name)); + foreach ($itemToRemove as $item) { + call_user_func(array($object, $methods[1]), $item); } - $objectOrArray->$setter($value); - } elseif ($reflClass->hasMethod('__set')) { - // needed to support magic method __set - $objectOrArray->$property = $value; - } elseif ($reflClass->hasProperty($property)) { - if (!$reflClass->getProperty($property)->isPublic()) { - throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s"%s. Maybe you should create the method "%s()"?', $property, $reflClass->name, $adderRemoverError, $setter)); + foreach ($itemsToAdd as $item) { + call_user_func(array($object, $methods[0]), $item); } - $objectOrArray->$property = $value; - } elseif (property_exists($objectOrArray, $property)) { - // needed to support \stdClass instances - $objectOrArray->$property = $value; + return; } else { - throw new NoSuchPropertyException(sprintf('Neither element "%s" nor method "%s()" exists in class "%s"%s', $property, $setter, $reflClass->name, $adderRemoverError)); + $adderRemoverError = ', nor could adders and removers be found based on the '; + if (null === $singular) { + // $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars).' (provide a singular by suffixing the property path with "|{singular}" to override the guesser)'; + $adderRemoverError .= 'guessed singulars: '.implode(', ', $singulars); + } else { + $adderRemoverError .= 'passed singular: '.$singular; + } } + } + + $setter = 'set'.$this->camelize($property); + + if ($reflClass->hasMethod($setter)) { + if (!$reflClass->getMethod($setter)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Method "%s()" is not public in class "%s"', $setter, $reflClass->name)); + } + + $object->$setter($value); + } elseif ($reflClass->hasMethod('__set')) { + // needed to support magic method __set + $object->$property = $value; + } elseif ($reflClass->hasProperty($property)) { + if (!$reflClass->getProperty($property)->isPublic()) { + throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public in class "%s"%s. Maybe you should create the method "%s()"?', $property, $reflClass->name, $adderRemoverError, $setter)); + } + + $object->$property = $value; + } elseif (property_exists($object, $property)) { + // needed to support \stdClass instances + $object->$property = $value; } else { - throw new NoSuchPropertyException(sprintf('Cannot write property "%s" in an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); + throw new NoSuchPropertyException(sprintf('Neither element "%s" nor method "%s()" exists in class "%s"%s', $property, $setter, $reflClass->name, $adderRemoverError)); } } From ff5ba380c5811ac93fa4d58013f3a597e7424168 Mon Sep 17 00:00:00 2001 From: Rafael Dohms Date: Thu, 10 Jan 2013 06:03:36 -0800 Subject: [PATCH 072/128] Created PT_BR translation for Security Added the PT_BR strings for Security strings. --- .../Resources/translations/security.pt_BR.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.pt_BR.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.pt_BR.xlf b/src/Symfony/Component/Security/Resources/translations/security.pt_BR.xlf new file mode 100644 index 0000000000..846fd49e64 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.pt_BR.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Uma exceção ocorreu durante a autenticação. + + + Authentication credentials could not be found. + As credenciais de autenticação não foram encontradas. + + + Authentication request could not be processed due to a system problem. + A autenticação não pôde ser concluída devido a um problema no sistema. + + + Invalid credentials. + Credenciais inválidas. + + + Cookie has already been used by someone else. + Este cookie já esta em uso. + + + Not privileged to request the resource. + Não possui privilégios o bastante para requisitar este recurso. + + + Invalid CSRF token. + Token CSRF inválido. + + + Digest nonce has expired. + Digest nonce expirado. + + + No authentication provider found to support the authentication token. + Nenhum provedor de autenticação encontrado para suportar o token de autenticação. + + + No session available, it either timed out or cookies are not enabled. + Nenhuma sessão disponível, ela expirou ou cookies estão desativados. + + + No token could be found. + Nenhum token foi encontrado. + + + Username could not be found. + Nome de usuário não encontrado. + + + Account has expired. + A conta esta expirada. + + + Credentials have expired. + As credenciais estão expiradas. + + + Account is disabled. + Conta desativada. + + + Account is locked. + A conta esta travada. + + + + From e35998f7fb3e67ebe363c2b70565543d5e7f800b Mon Sep 17 00:00:00 2001 From: Florin Patan Date: Thu, 10 Jan 2013 16:16:00 +0200 Subject: [PATCH 073/128] Translated to Romanian --- .../Resources/translations/security.ro.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.ro.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.ro.xlf b/src/Symfony/Component/Security/Resources/translations/security.ro.xlf new file mode 100644 index 0000000000..440f110367 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.ro.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + A apărut o eroare de autentificare. + + + Authentication credentials could not be found. + Informațiile de autentificare nu au fost găsite. + + + Authentication request could not be processed due to a system problem. + Sistemul nu a putut procesa cererea de autentificare din cauza unei erori. + + + Invalid credentials. + Date de autentificare invalide. + + + Cookie has already been used by someone else. + Cookieul este folosit deja de altcineva. + + + Not privileged to request the resource. + Permisiuni insuficiente pentru resursa cerută. + + + Invalid CSRF token. + Tokenul CSRF este invalid. + + + Digest nonce has expired. + Tokenul temporar a expirat. + + + No authentication provider found to support the authentication token. + Nu a fost găsit nici un agent de autentificare pentru tokenul specificat. + + + No session available, it either timed out or cookies are not enabled. + Sesiunea nu mai este disponibilă, a expirat sau suportul pentru cookieuri nu este activat. + + + No token could be found. + Tokenul nu a putut fi găsit. + + + Username could not be found. + Numele de utilizator nu a fost găsit. + + + Account has expired. + Contul a expirat. + + + Credentials have expired. + Datele de autentificare au expirat. + + + Account is disabled. + Contul este dezactivat. + + + Account is locked. + Contul este blocat. + + + + From b194607e345db8a7ca977d1884ffd731f456e5c1 Mon Sep 17 00:00:00 2001 From: Diego Sapriza Date: Thu, 10 Jan 2013 12:17:16 -0200 Subject: [PATCH 074/128] spanish translation --- .../Resources/translations/security.es.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.es.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Resources/translations/security.es.xlf new file mode 100644 index 0000000000..525b954854 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.es.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Ha ocurrido una excepción de autenticación. + + + Authentication credentials could not be found. + No se encontraron las credenciales de autenticación. + + + Authentication request could not be processed due to a system problem. + El pedido de autenticación no se pudo procesar debido a un problema del sistema. + + + Invalid credentials. + Credenciales invalidas. + + + Cookie has already been used by someone else. + El Cookie ya ha sido usado por alguien más. + + + Not privileged to request the resource. + Sin privilegios para solicitar el recurso. + + + Invalid CSRF token. + Token CSRF inválido. + + + Digest nonce has expired. + El vector de inicialización (digest nonce) ha expirado. + + + No authentication provider found to support the authentication token. + No se encontro un proveedor de autenticación para soportar el token de autenticación. + + + No session available, it either timed out or cookies are not enabled. + No hay una sesión disponible, ha expirado o los cookies no están habilitados. + + + No token could be found. + No se encontró un token. + + + Username could not be found. + No se encontró el nombre de usuario. + + + Account has expired. + La cuenta ha expirado. + + + Credentials have expired. + Las credenciales han expirado. + + + Account is disabled. + La cuenta esta deshabilitada. + + + Account is locked. + La cuenta esta bloqueada. + + + + From 2f5196161a631109ae642892c0e84d41772e5995 Mon Sep 17 00:00:00 2001 From: Daniel Mecke Date: Thu, 10 Jan 2013 06:19:49 -0800 Subject: [PATCH 075/128] Created de translation for Security --- .../Resources/translations/security.de.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.de.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.de.xlf b/src/Symfony/Component/Security/Resources/translations/security.de.xlf new file mode 100644 index 0000000000..3142ffb15c --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.de.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Es ist ein Fehler bei der Authorisierung aufgetreten. + + + Authentication credentials could not be found. + Es konnten keine Zugangsdaten gefunden werden. + + + Authentication request could not be processed due to a system problem. + Die Authorisierung konnte wegen eines Systemproblems nicht bearbeitet werden. + + + Invalid credentials. + Fehlerhafte Zugangsdaten. + + + Cookie has already been used by someone else. + Cookie wurde bereits von jemand Anderem verwendet. + + + Not privileged to request the resource. + Keine Rechte, um die Resource anzufragen. + + + Invalid CSRF token. + Ungültiges CSRF Token. + + + Digest nonce has expired. + Digest nonce ist abgelaufen. + + + No authentication provider found to support the authentication token. + Es wurde kein Authentifizierungs-Provider gefunden, der das Authentifizierungs-Token unterstützt. + + + No session available, it either timed out or cookies are not enabled. + Keine Session verfügbar, entweder ist diese abgelaufen oder Cookies sind nicht aktiviert. + + + No token could be found. + Es wurde kein Token gefunden. + + + Username could not be found. + Der Username wurde nicht gefunden. + + + Account has expired. + Der Account ist abgelaufen. + + + Credentials have expired. + Die Zugangsdaten sind abgelaufen. + + + Account is disabled. + Der Account ist deaktiviert. + + + Account is locked. + Der Account ist gesperrt. + + + + From c3a6659856fe47073006f0b2830ebe55032f7b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Egyed?= <1ed@mailbox.hu> Date: Thu, 10 Jan 2013 06:23:20 -0800 Subject: [PATCH 076/128] [Security] added Hungarian translations for exception messages --- .../Resources/translations/ security.hu.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/ security.hu.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/ security.hu.xlf b/src/Symfony/Component/Security/Resources/translations/ security.hu.xlf new file mode 100644 index 0000000000..bd4939e705 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/ security.hu.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Hitelesítési hiba lépett fel. + + + Authentication credentials could not be found. + Nem találhatók hitelesítési információk. + + + Authentication request could not be processed due to a system problem. + A hitelesítési kérést rendszerhiba miatt nem lehet feldolgozni. + + + Invalid credentials. + Érvénytelen hitelesítési információk. + + + Cookie has already been used by someone else. + Ezt a sütit már valaki más használja. + + + Not privileged to request the resource. + Nem rendelkezik az erőforrás eléréséhez szükséges jogosultsággal. + + + Invalid CSRF token. + Érvénytelen CSRF token. + + + Digest nonce has expired. + A kivonat bélyege (nonce) lejárt. + + + No authentication provider found to support the authentication token. + Nem található a hitelesítési tokent támogató hitelesítési szolgáltatás. + + + No session available, it either timed out or cookies are not enabled. + Munkamenet nem áll rendelkezésre, túllépte az időkeretet vagy a sütik le vannak tiltva. + + + No token could be found. + Nem található token. + + + Username could not be found. + A felhasználónév nem található. + + + Account has expired. + A fiók lejárt. + + + Credentials have expired. + A hitelesítési információk lejártak. + + + Account is disabled. + Felfüggesztett fiók. + + + Account is locked. + Zárolt fiók. + + + + From 0b5177b8e8dada7acb026f44c7dfa2b18329f6ed Mon Sep 17 00:00:00 2001 From: matteo giachino Date: Thu, 10 Jan 2013 15:17:28 +0100 Subject: [PATCH 077/128] added italian translations --- .../Resources/translations/security.it.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.it.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.it.xlf b/src/Symfony/Component/Security/Resources/translations/security.it.xlf new file mode 100644 index 0000000000..25d82ef7c2 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.it.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Si è verificato un errore di autenticazione. + + + Authentication credentials could not be found. + Impossibile trovare le credenziali di autenticazione. + + + Authentication request could not be processed due to a system problem. + La richiesta di autenticazione non può essere processata a causa di un errore di sistema. + + + Invalid credentials. + Credenziali non valide. + + + Cookie has already been used by someone else. + Il cookie è già stato usato da qualcun'altro. + + + Not privileged to request the resource. + Non hai i privilegi per richiedere questa risorsa. + + + Invalid CSRF token. + CSRF token non valido. + + + Digest nonce has expired. + Il numero di autenticazione è scaduto. + + + No authentication provider found to support the authentication token. + Non è stato trovato un valido fornitore di autenticazione per supportare il token. + + + No session available, it either timed out or cookies are not enabled. + Nessuna sessione disponibile, può essere scaduta o i cookie non sono abilitati. + + + No token could be found. + Nessun token trovato. + + + Username could not be found. + Username non trovato. + + + Account has expired. + Account scaduto. + + + Credentials have expired. + Credenziali scadute. + + + Account is disabled. + L'account è disabilitato. + + + Account is locked. + L'account è bloccato. + + + + From 45c86826069e1e07aea3fcd29c8c49fa9ab66a9e Mon Sep 17 00:00:00 2001 From: Vincent AUBERT Date: Thu, 10 Jan 2013 15:19:52 +0100 Subject: [PATCH 078/128] [Security][Translation]Created fr translation for Security --- .../Resources/translations/security.fr.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.fr.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.fr.xlf b/src/Symfony/Component/Security/Resources/translations/security.fr.xlf new file mode 100644 index 0000000000..207929b7c3 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.fr.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Une exception d'authentification s'est produite. + + + Authentication credentials could not be found. + Les droits d'authentification n'ont pas pu être trouvés. + + + Authentication request could not be processed due to a system problem. + La requête d'authentification n'a pas pu être executée à cause d'un problème système. + + + Invalid credentials. + Droits invalides. + + + Cookie has already been used by someone else. + Le cookie a déjà été utilisé par quelqu'un d'autre. + + + Not privileged to request the resource. + Pas de privilèges pour accéder à la ressource. + + + Invalid CSRF token. + Jeton CSRF invalide. + + + Digest nonce has expired. + Le digest nonce a expiré. + + + No authentication provider found to support the authentication token. + Aucun fournisseur d'authentification n'a été trouvé pour supporter le jeton d'authentification. + + + No session available, it either timed out or cookies are not enabled. + Pas de session disponible, celle-ci à expiré ou les cookies ne sont pas activés. + + + No token could be found. + Aucun jeton n'a pu être trouvé. + + + Username could not be found. + Le nom d'utilisateur ne peut pas être trouvé. + + + Account has expired. + Le compte à expiré. + + + Credentials have expired. + Les droits ont expirés. + + + Account is disabled. + Le compte est désactivé. + + + Account is locked. + Le compte est bloqué. + + + + From 9b8428d44f50293ee9bdd3f2ed9c9eb1656b855d Mon Sep 17 00:00:00 2001 From: plebs Date: Thu, 10 Jan 2013 15:32:29 +0100 Subject: [PATCH 079/128] [security][tranlation]Fixed spanish translation --- .../Component/Security/Resources/translations/security.es.xlf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Resources/translations/security.es.xlf index 525b954854..c8bb6c7323 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es.xlf @@ -60,11 +60,11 @@ Account is disabled. - La cuenta esta deshabilitada. + La cuenta está deshabilitada. Account is locked. - La cuenta esta bloqueada. + La cuenta está bloqueada.
From 6ae8ca8042f9dbabce388553a5c16d2650d4c03d Mon Sep 17 00:00:00 2001 From: Victor Mateo Date: Thu, 10 Jan 2013 15:33:04 +0100 Subject: [PATCH 080/128] Update src/Symfony/Component/Security/Resources/translations/security.es.xlf --- .../Component/Security/Resources/translations/security.es.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Resources/translations/security.es.xlf index 525b954854..962e7995a7 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es.xlf @@ -36,7 +36,7 @@ No authentication provider found to support the authentication token. - No se encontro un proveedor de autenticación para soportar el token de autenticación. + No se encontró un proveedor de autenticación para soportar el token de autenticación. No session available, it either timed out or cookies are not enabled. From 3c4437c97513fa90bd6ddfacee46ef5e236648ed Mon Sep 17 00:00:00 2001 From: inspiran Date: Thu, 10 Jan 2013 15:34:58 +0100 Subject: [PATCH 081/128] Added Dutch translations --- .../Resources/translations/security.nl.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.nl.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf new file mode 100644 index 0000000000..f434944b75 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Een authenticatie probleem is is opgetreden. + + + Authentication credentials could not be found. + Authenticate rechten konden niet worden gevonden. + + + Authentication request could not be processed due to a system problem. + Authenticatie aanvraag kon niet worden verwerkt door een technisch probleem. + + + Invalid credentials. + Ongeldige rechten. + + + Cookie has already been used by someone else. + Cookie werd reeds door een ander persoon gebruikt. + + + Not privileged to request the resource. + Onvoldoende rechten om deze aanvraag te verwerken + + + Invalid CSRF token. + CSRF code is ongeldig. + + + Digest nonce has expired. + Server authenticatiesleutel (digest nonce) is verlopen. + + + No authentication provider found to support the authentication token. + Geen authenticaie provider gevonden die de authenticatie teken ondersteunt. + + + No session available, it either timed out or cookies are not enabled. + Geen sessie beschikbaar, deze kan verlopen zijn of cookies zijn niet geactiveerd. + + + No token could be found. + Er kon geen authenticatie code worden gevonden. + + + Username could not be found. + Gebruikersnaam werd niet gevonden. + + + Account has expired. + Account is verlopen. + + + Credentials have expired. + Rechten zijn verlopen. + + + Account is disabled. + Account is gedeactiveerd. + + + Account is locked. + Account is geblokkeerd. + + + + From e908a523d375eefd1c1642848bf8fe4e2063d1fa Mon Sep 17 00:00:00 2001 From: Ismael Ambrosi Date: Thu, 10 Jan 2013 12:36:30 -0200 Subject: [PATCH 082/128] Fixed spanish typos --- .../Security/Resources/translations/security.es.xlf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Resources/translations/security.es.xlf index 525b954854..3831ab2e5a 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es.xlf @@ -16,7 +16,7 @@ Invalid credentials. - Credenciales invalidas. + Credenciales inválidas. Cookie has already been used by someone else. @@ -36,7 +36,7 @@ No authentication provider found to support the authentication token. - No se encontro un proveedor de autenticación para soportar el token de autenticación. + No se encontró un proveedor de autenticación para soportar el token de autenticación. No session available, it either timed out or cookies are not enabled. @@ -60,11 +60,11 @@ Account is disabled. - La cuenta esta deshabilitada. + La cuenta está deshabilitada. Account is locked. - La cuenta esta bloqueada. + La cuenta está bloqueada. From 9db1515b31d42cd8803f1722d7e05aba16398152 Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Thu, 10 Jan 2013 14:44:10 +0000 Subject: [PATCH 083/128] [Security] Removed extra space --- .../Resources/translations/{ security.hu.xlf => security.hu.xlf} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Symfony/Component/Security/Resources/translations/{ security.hu.xlf => security.hu.xlf} (100%) diff --git a/src/Symfony/Component/Security/Resources/translations/ security.hu.xlf b/src/Symfony/Component/Security/Resources/translations/security.hu.xlf similarity index 100% rename from src/Symfony/Component/Security/Resources/translations/ security.hu.xlf rename to src/Symfony/Component/Security/Resources/translations/security.hu.xlf From c06e627e17ddd52d11bbe55213001a0d0f7824da Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 10 Jan 2013 15:54:27 +0100 Subject: [PATCH 084/128] Fixed some typos --- .../Resources/translations/security.es.xlf | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Resources/translations/security.es.xlf index 525b954854..e7987922a3 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es.xlf @@ -4,31 +4,31 @@ An authentication exception occurred. - Ha ocurrido una excepción de autenticación. + Ocurrió una error de autenticación. Authentication credentials could not be found. - No se encontraron las credenciales de autenticación. + No se encontraron los credenciales de autenticación. Authentication request could not be processed due to a system problem. - El pedido de autenticación no se pudo procesar debido a un problema del sistema. + La solicitud de autenticación no se pudo procesar debido a un problema del sistema. Invalid credentials. - Credenciales invalidas. + Credenciales no válidos. Cookie has already been used by someone else. - El Cookie ya ha sido usado por alguien más. + La cookie ya ha sido usada por otra persona. Not privileged to request the resource. - Sin privilegios para solicitar el recurso. + No tiene privilegios para solicitar el recurso. Invalid CSRF token. - Token CSRF inválido. + Token CSRF no válido. Digest nonce has expired. @@ -36,15 +36,15 @@ No authentication provider found to support the authentication token. - No se encontro un proveedor de autenticación para soportar el token de autenticación. + No se encontró un proveedor de autenticación que soporte el token de autenticación. No session available, it either timed out or cookies are not enabled. - No hay una sesión disponible, ha expirado o los cookies no están habilitados. + No hay ninguna sesión disponible, ha expirado o las cookies no están habilitados. No token could be found. - No se encontró un token. + No se encontró ningún token. Username could not be found. @@ -56,15 +56,15 @@ Credentials have expired. - Las credenciales han expirado. + Los credenciales han expirado. Account is disabled. - La cuenta esta deshabilitada. + La cuenta está deshabilitada. Account is locked. - La cuenta esta bloqueada. + La cuenta está bloqueada. From e84a8d0106942ccf6f5b9f591e8ca7376fb2ce11 Mon Sep 17 00:00:00 2001 From: Stefan Koopmanschap Date: Thu, 10 Jan 2013 16:22:58 +0100 Subject: [PATCH 085/128] fixed some small issues with grammar and used terminology --- .../Security/Resources/translations/security.nl.xlf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf index f434944b75..7a9fd719de 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf @@ -4,15 +4,15 @@ An authentication exception occurred. - Een authenticatie probleem is is opgetreden. + Er heeft zich een authenticatieprobleem voorgedaan. Authentication credentials could not be found. - Authenticate rechten konden niet worden gevonden. + Authenticatiegegevens konden niet worden gevonden. Authentication request could not be processed due to a system problem. - Authenticatie aanvraag kon niet worden verwerkt door een technisch probleem. + Authenticatie-aanvraag kon niet worden verwerkt door een technisch probleem. Invalid credentials. @@ -36,7 +36,7 @@ No authentication provider found to support the authentication token. - Geen authenticaie provider gevonden die de authenticatie teken ondersteunt. + Geen authenticatieprovider gevonden die het authenticatietoken ondersteunt. No session available, it either timed out or cookies are not enabled. @@ -44,7 +44,7 @@ No token could be found. - Er kon geen authenticatie code worden gevonden. + Er kon geen authenticatietoken worden gevonden. Username could not be found. @@ -56,7 +56,7 @@ Credentials have expired. - Rechten zijn verlopen. + Authenticatiegegevens zijn verlopen. Account is disabled. From f7da1f0eb83f549c2245a3d2d1036be0688c78c6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 10 Jan 2013 16:08:44 +0100 Subject: [PATCH 086/128] added some unit tests (and fixed some bugs) --- .../Extension/HttpKernelExtensionTest.php | 1 - .../Compiler/HttpRenderingStrategyPass.php | 10 +- .../FrameworkBundle/FrameworkBundle.php | 2 +- .../Resources/config/content_generator.xml | 3 +- .../FrameworkBundle/Resources/config/esi.xml | 2 +- .../HttpRenderingStrategyPassTest.php | 105 ++++++++++++++++ .../EventListener/ValidationListenerTest.php | 1 - .../Component/HttpFoundation/Request.php | 3 +- .../EventListener/RouterProxyListener.php | 5 +- .../HttpKernel/HttpContentRenderer.php | 2 + .../DefaultRenderingStrategy.php | 4 + .../EsiRenderingStrategy.php | 4 +- .../GeneratorAwareRenderingStrategy.php | 5 +- .../EventListener/RouterProxyListenerTest.php | 119 ++++++++++++++++++ .../Tests/HttpContentRendererTest.php | 75 +++++++++++ .../AbstractRenderingStrategyTest.php | 29 +++++ .../DefaultRenderingStrategyTest.php | 62 ++++++++- .../EsiRenderingStrategyTest.php | 68 ++++++++++ .../GeneratorAwareRenderingStrategyTest.php | 101 +++++++++++++++ .../HIncludeRenderingStrategyTest.php | 71 +++++++++++ .../HttpKernel/Tests/UriSignerTest.php | 37 ++++++ .../Component/HttpKernel/UriSigner.php | 9 +- 22 files changed, 697 insertions(+), 21 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/HttpRenderingStrategyPassTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/HttpContentRendererTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/AbstractRenderingStrategyTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/EsiRenderingStrategyTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/GeneratorAwareRenderingStrategyTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/HIncludeRenderingStrategyTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php index dd6030ea54..182c42d077 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -13,7 +13,6 @@ namespace Symfony\Bridge\Twig\Tests\Extension; use Symfony\Bridge\Twig\Extension\HttpKernelExtension; use Symfony\Bridge\Twig\Tests\TestCase; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpContentRenderer; class HttpKernelExtensionTest extends TestCase diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php index 3d31def579..3bb16f28c7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/HttpRenderingStrategyPass.php @@ -14,7 +14,6 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Exception\LogicException; /** * Adds services tagged kernel.content_renderer_strategy as HTTP content rendering strategies. @@ -31,6 +30,15 @@ class HttpRenderingStrategyPass implements CompilerPassInterface $definition = $container->getDefinition('http_content_renderer'); foreach (array_keys($container->findTaggedServiceIds('kernel.content_renderer_strategy')) as $id) { + // We must assume that the class value has been correctly filled, even if the service is created by a factory + $class = $container->getDefinition($id)->getClass(); + + $refClass = new \ReflectionClass($class); + $interface = 'Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface'; + if (!$refClass->implementsInterface($interface)) { + throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface)); + } + $definition->addMethodCall('addStrategy', array(new Reference($id))); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 3f18da7892..c4caaea4e9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -66,7 +66,7 @@ class FrameworkBundle extends Bundle $container->addCompilerPass(new AddCacheClearerPass()); $container->addCompilerPass(new TranslationExtractorPass()); $container->addCompilerPass(new TranslationDumperPass()); - $container->addCompilerPass(new HttpRenderingStrategyPass()); + $container->addCompilerPass(new HttpRenderingStrategyPass(), PassConfig::TYPE_AFTER_REMOVING); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml index 533e886fb6..332cf0de38 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/content_generator.xml @@ -19,13 +19,12 @@ %kernel.debug% - + - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml index 45e9265442..0c4a271863 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/esi.xml @@ -18,7 +18,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/HttpRenderingStrategyPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/HttpRenderingStrategyPassTest.php new file mode 100644 index 0000000000..4fe461fec4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/HttpRenderingStrategyPassTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\HttpRenderingStrategyPass; + +class HttpRenderingStrategyPassTest extends \PHPUnit_Framework_TestCase +{ + /** + * Tests that content rendering not implementing RenderingStrategyInterface + * trigger an exception. + * + * @expectedException \InvalidArgumentException + */ + public function testContentRendererWithoutInterface() + { + // one service, not implementing any interface + $services = array( + 'my_content_renderer' => array(), + ); + + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $definition->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue('stdClass')); + + $builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); + $builder->expects($this->any()) + ->method('hasDefinition') + ->will($this->returnValue(true)); + + // We don't test kernel.content_renderer_strategy here + $builder->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->returnValue($services)); + + $builder->expects($this->atLeastOnce()) + ->method('getDefinition') + ->will($this->returnValue($definition)); + + $pass = new HttpRenderingStrategyPass(); + $pass->process($builder); + } + + public function testValidContentRenderer() + { + $services = array( + 'my_content_renderer' => array(), + ); + + $renderer = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $renderer + ->expects($this->once()) + ->method('addMethodCall') + ->with('addStrategy', array(new Reference('my_content_renderer'))) + ; + + $definition = $this->getMock('Symfony\Component\DependencyInjection\Definition'); + $definition->expects($this->atLeastOnce()) + ->method('getClass') + ->will($this->returnValue('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\RenderingStrategyService')); + + $builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); + $builder->expects($this->any()) + ->method('hasDefinition') + ->will($this->returnValue(true)); + + // We don't test kernel.content_renderer_strategy here + $builder->expects($this->atLeastOnce()) + ->method('findTaggedServiceIds') + ->will($this->returnValue($services)); + + $builder->expects($this->atLeastOnce()) + ->method('getDefinition') + ->will($this->onConsecutiveCalls($renderer, $definition)); + + $pass = new HttpRenderingStrategyPass(); + $pass->process($builder); + } +} + +class RenderingStrategyService implements \Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface +{ + public function render($uri, Request $request = null, array $options = array()) + { + } + + public function getName() + { + return 'test'; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php index d9555e13e1..3a8f7f41f0 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php @@ -13,7 +13,6 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormBuilder; -use Symfony\Component\Form\FormError; use Symfony\Component\Form\Util\PropertyPath; use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener; diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 9a647c43fc..0bac66ada7 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -926,8 +926,7 @@ class Request */ public function getUri() { - $qs = $this->getQueryString(); - if (null !== $qs) { + if (null !== $qs = $this->getQueryString()) { $qs = '?'.$qs; } diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php index 05e8717fc0..b88350c20f 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterProxyListener.php @@ -55,7 +55,7 @@ class RouterProxyListener implements EventSubscriberInterface parse_str($request->query->get('path', ''), $attributes); $request->attributes->add($attributes); - $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params'), $attributes)); + $request->attributes->set('_route_params', array_replace($request->attributes->get('_route_params', array()), $attributes)); $request->query->remove('path'); } @@ -76,7 +76,8 @@ class RouterProxyListener implements EventSubscriberInterface } // is the Request signed? - if ($this->signer->check($request->getUri())) { + // we cannot use $request->getUri() here as we want to work with the original URI (no query string reordering) + if ($this->signer->check($request->getSchemeAndHttpHost().$request->getBaseUrl().$request->getPathInfo().(null !== ($qs = $request->server->get('QUERY_STRING')) ? '?'.$qs : ''))) { return; } diff --git a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php index 408dffc991..4849b8f6b5 100644 --- a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php +++ b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php @@ -90,6 +90,8 @@ class HttpContentRenderer implements EventSubscriberInterface * @param array $options An array of options * * @return string|null The Response content or null when the Response is streamed + * + * @throws \InvalidArgumentException when the strategy does not exist */ public function render($uri, $strategy = 'default', array $options = array()) { diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php index 5198c01ba9..c0820b8504 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/DefaultRenderingStrategy.php @@ -36,6 +36,10 @@ class DefaultRenderingStrategy extends GeneratorAwareRenderingStrategy /** * {@inheritdoc} + * + * Additional available options: + * + * * alt: an alternative URI to render in case of an error */ public function render($uri, Request $request = null, array $options = array()) { diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php index cf9f572079..f77669f484 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/EsiRenderingStrategy.php @@ -56,7 +56,7 @@ class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy */ public function render($uri, Request $request = null, array $options = array()) { - if (!$this->esi->hasSurrogateEsiCapability($request)) { + if (null === $request || !$this->esi->hasSurrogateEsiCapability($request)) { return $this->defaultStrategy->render($uri, $request, $options); } @@ -69,7 +69,7 @@ class EsiRenderingStrategy extends GeneratorAwareRenderingStrategy $alt = $this->generateProxyUri($alt, $request); } - return $this->esi->renderIncludeTag($uri, $alt, $options['ignore_errors'], isset($options['comment']) ? $options['comment'] : ''); + return $this->esi->renderIncludeTag($uri, $alt, isset($options['ignore_errors']) ? $options['ignore_errors'] : false, isset($options['comment']) ? $options['comment'] : ''); } /** diff --git a/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php index 408d682326..a5ba272f81 100644 --- a/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php +++ b/src/Symfony/Component/HttpKernel/RenderingStrategy/GeneratorAwareRenderingStrategy.php @@ -46,6 +46,9 @@ abstract class GeneratorAwareRenderingStrategy implements RenderingStrategyInter * @param Request $request A Request instance * * @return string A proxy URI + * + * @throws \LogicException when the _proxy route is not available + * @throws \LogicException when there is no registered route generator */ protected function generateProxyUri(ControllerReference $reference, Request $request = null) { @@ -63,7 +66,7 @@ abstract class GeneratorAwareRenderingStrategy implements RenderingStrategyInter } try { - $uri = $this->generator->generate('_proxy', array('_controller' => $reference->controller, '_format' => $format), true); + $uri = $this->generator->generate('_proxy', array('_controller' => $reference->controller, '_format' => $format), UrlGeneratorInterface::ABSOLUTE_URL); } catch (RouteNotFoundException $e) { throw new \LogicException('Unable to generate a proxy URL as the "_proxy" route is not registered.', 0, $e); } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php new file mode 100644 index 0000000000..32b750f9ce --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\EventListener; + +use Symfony\Component\HttpKernel\EventListener\RouterProxyListener; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\UriSigner; + +class RouterProxyListenerTest extends \PHPUnit_Framework_TestCase +{ + protected function setUp() + { + if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) { + $this->markTestSkipped('The "EventDispatcher" component is not available'); + } + } + + public function testOnlyTrigerredOnProxyRoute() + { + $request = Request::create('http://example.com/foo?path=foo%3D=bar'); + + $listener = new RouterProxyListener(new UriSigner('foo')); + $event = $this->createGetResponseEvent($request, 'foobar'); + + $expected = $request->attributes->all(); + + $listener->onKernelRequest($event); + + $this->assertEquals($expected, $request->attributes->all()); + $this->assertTrue($request->query->has('path')); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAccessDeniedWithNonSafeMethods() + { + $request = Request::create('http://example.com/foo', 'POST'); + + $listener = new RouterProxyListener(new UriSigner('foo')); + $event = $this->createGetResponseEvent($request); + + $listener->onKernelRequest($event); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAccessDeniedWithNonLocalIps() + { + $request = Request::create('http://example.com/foo', 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1')); + + $listener = new RouterProxyListener(new UriSigner('foo')); + $event = $this->createGetResponseEvent($request); + + $listener->onKernelRequest($event); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAccessDeniedWithWrongSignature() + { + $request = Request::create('http://example.com/foo', 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1')); + + $listener = new RouterProxyListener(new UriSigner('foo')); + $event = $this->createGetResponseEvent($request); + + $listener->onKernelRequest($event); + } + + public function testWithSignatureAndNoPath() + { + $signer = new UriSigner('foo'); + $request = Request::create($signer->sign('http://example.com/foo'), 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1')); + + $listener = new RouterProxyListener($signer); + $event = $this->createGetResponseEvent($request); + + $listener->onKernelRequest($event); + + $this->assertEquals(array('foo' => 'foo'), $request->attributes->get('_route_params')); + $this->assertFalse($request->query->has('path')); + } + + public function testWithSignatureAndPath() + { + $signer = new UriSigner('foo'); + $request = Request::create($signer->sign('http://example.com/foo?path=bar%3Dbar'), 'GET', array(), array(), array(), array('REMOTE_ADDR' => '10.0.0.1')); + + $listener = new RouterProxyListener($signer); + $event = $this->createGetResponseEvent($request); + + $listener->onKernelRequest($event); + + $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar'), $request->attributes->get('_route_params')); + $this->assertFalse($request->query->has('path')); + } + + private function createGetResponseEvent(Request $request, $route = '_proxy') + { + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + $request->attributes->set('_route', $route); + $request->attributes->set('_route_params', array('foo' => 'foo')); + + return new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpContentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpContentRendererTest.php new file mode 100644 index 0000000000..ff0d4cbdb0 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/HttpContentRendererTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests; + +use Symfony\Component\HttpKernel\HttpContentRenderer; + +class HttpContentRendererTest extends \PHPUnit_Framework_TestCase +{ + protected function setUp() + { + if (!class_exists('Symfony\Component\EventDispatcher\EventDispatcher')) { + $this->markTestSkipped('The "EventDispatcher" component is not available'); + } + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testRenderWhenStrategyDoesNotExist() + { + $renderer = new HttpContentRenderer(); + $renderer->render('/', 'foo'); + } + + public function testRender() + { + $strategy = $this->getMock('Symfony\Component\HttpKernel\RenderingStrategy\RenderingStrategyInterface'); + $strategy + ->expects($this->any()) + ->method('getName') + ->will($this->returnValue('foo')) + ; + $strategy + ->expects($this->any()) + ->method('render') + ->with('/', null, array('foo' => 'foo', 'ignore_errors' => true)) + ->will($this->returnValue('foo')) + ; + + $renderer = new HttpContentRenderer(); + $renderer->addStrategy($strategy); + + $this->assertEquals('foo', $renderer->render('/', 'foo', array('foo' => 'foo'))); + } + + /** + * @dataProvider getFixOptionsData + */ + public function testFixOptions($expected, $options) + { + $renderer = new HttpContentRenderer(); + + set_error_handler(function ($errorNumber, $message, $file, $line, $context) { return $errorNumber & E_USER_DEPRECATED; }); + $this->assertEquals($expected, $renderer->fixOptions($options)); + restore_error_handler(); + } + + public function getFixOptionsData() + { + return array( + array(array('strategy' => 'esi'), array('standalone' => true)), + array(array('strategy' => 'esi'), array('standalone' => 'esi')), + array(array('strategy' => 'hinclude'), array('standalone' => 'js')), + ); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/AbstractRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/AbstractRenderingStrategyTest.php new file mode 100644 index 0000000000..ae3a07f2cc --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/AbstractRenderingStrategyTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy; + +abstract class AbstractRenderingStrategyTest extends \PHPUnit_Framework_TestCase +{ + protected function getUrlGenerator() + { + $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface'); + $generator + ->expects($this->any()) + ->method('generate') + ->will($this->returnCallback(function ($name, $parameters, $referenceType) { + return '/'.$parameters['_controller'].'.'.$parameters['_format']; + })) + ; + + return $generator; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php index 48a5451470..3c55c5905c 100644 --- a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/DefaultRenderingStrategyTest.php @@ -9,16 +9,16 @@ * file that was distributed with this source code. */ - namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy; +namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy; -use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\EventDispatcher\EventDispatcher; -class DefaultRenderingStrategyTest extends \PHPUnit_Framework_TestCase +class DefaultRenderingStrategyTest extends AbstractRenderingStrategyTest { protected function setUp() { @@ -31,6 +31,60 @@ class DefaultRenderingStrategyTest extends \PHPUnit_Framework_TestCase } } + public function testRender() + { + $strategy = new DefaultRenderingStrategy($this->getKernel($this->returnValue(new Response('foo')))); + + $this->assertEquals('foo', $strategy->render('/')); + } + + public function testRenderWithControllerReference() + { + $strategy = new DefaultRenderingStrategy($this->getKernel($this->returnValue(new Response('foo')))); + $strategy->setUrlGenerator($this->getUrlGenerator()); + + $this->assertEquals('foo', $strategy->render(new ControllerReference('main_controller', array(), array()))); + } + + /** + * @expectedException \RuntimeException + */ + public function testRenderExceptionNoIgnoreErrors() + { + $strategy = new DefaultRenderingStrategy($this->getKernel($this->throwException(new \RuntimeException('foo')))); + + $this->assertEquals('foo', $strategy->render('/')); + } + + public function testRenderExceptionIgnoreErrors() + { + $strategy = new DefaultRenderingStrategy($this->getKernel($this->throwException(new \RuntimeException('foo')))); + + $this->assertNull($strategy->render('/', null, array('ignore_errors' => true))); + } + + public function testRenderExceptionIgnoreErrorsWithAlt() + { + $strategy = new DefaultRenderingStrategy($this->getKernel($this->onConsecutiveCalls( + $this->throwException(new \RuntimeException('foo')), + $this->returnValue(new Response('bar')) + ))); + + $this->assertEquals('bar', $strategy->render('/', null, array('ignore_errors' => true, 'alt' => '/foo'))); + } + + private function getKernel($returnValue) + { + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + $kernel + ->expects($this->any()) + ->method('handle') + ->will($returnValue) + ; + + return $kernel; + } + public function testExceptionInSubRequestsDoesNotMangleOutputBuffers() { $resolver = $this->getMock('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface'); diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/EsiRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/EsiRenderingStrategyTest.php new file mode 100644 index 0000000000..513e30039c --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/EsiRenderingStrategyTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy; + +use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\RenderingStrategy\EsiRenderingStrategy; +use Symfony\Component\HttpKernel\HttpCache\Esi; +use Symfony\Component\HttpFoundation\Request; + +class EsiRenderingStrategyTest extends AbstractRenderingStrategyTest +{ + protected function setUp() + { + if (!class_exists('Symfony\Component\HttpFoundation\Request')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) { + $this->markTestSkipped('The "Routing" component is not available'); + } + } + + public function testRenderFallbackToDefaultStrategyIfNoRequest() + { + $strategy = new EsiRenderingStrategy(new Esi(), $this->getDefaultStrategy(true)); + $strategy->render('/'); + } + + public function testRenderFallbackToDefaultStrategyIfEsiNotSupported() + { + $strategy = new EsiRenderingStrategy(new Esi(), $this->getDefaultStrategy(true)); + $strategy->render('/', Request::create('/')); + } + + public function testRender() + { + $strategy = new EsiRenderingStrategy(new Esi(), $this->getDefaultStrategy()); + $strategy->setUrlGenerator($this->getUrlGenerator()); + + $request = Request::create('/'); + $request->headers->set('Surrogate-Capability', 'ESI/1.0'); + + $this->assertEquals('', $strategy->render('/', $request)); + $this->assertEquals("\n", $strategy->render('/', $request, array('comment' => 'This is a comment'))); + $this->assertEquals('', $strategy->render('/', $request, array('alt' => 'foo'))); + $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', array(), array()), $request, array('alt' => new ControllerReference('alt_controller', array(), array())))); + } + + private function getDefaultStrategy($called = false) + { + $default = $this->getMockBuilder('Symfony\Component\HttpKernel\RenderingStrategy\DefaultRenderingStrategy')->disableOriginalConstructor()->getMock(); + + if ($called) { + $default->expects($this->once())->method('render'); + } + + return $default; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/GeneratorAwareRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/GeneratorAwareRenderingStrategyTest.php new file mode 100644 index 0000000000..387ab3e2a0 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/GeneratorAwareRenderingStrategyTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\RenderingStrategy\GeneratorAwareRenderingStrategy; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Routing\Exception\RouteNotFoundException; + +class GeneratorAwareRenderingStrategyTest extends AbstractRenderingStrategyTest +{ + protected function setUp() + { + if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) { + $this->markTestSkipped('The "Routing" component is not available'); + } + } + + /** + * @expectedException \LogicException + */ + public function testGenerateProxyUriWithNoGenerator() + { + $strategy = new Strategy(); + $strategy->doGenerateProxyUri(new ControllerReference('controller', array(), array())); + } + + /** + * @expectedException \LogicException + */ + public function testGenerateProxyUriWhenRouteNotFound() + { + $generator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface'); + $generator + ->expects($this->once()) + ->method('generate') + ->will($this->throwException(new RouteNotFoundException())) + ; + + $strategy = new Strategy(); + $strategy->setUrlGenerator($generator); + $strategy->doGenerateProxyUri(new ControllerReference('controller', array(), array())); + } + + /** + * @dataProvider getGeneratorProxyUriData + */ + public function testGenerateProxyUri($uri, $controller) + { + $this->assertEquals($uri, $this->getStrategy()->doGenerateProxyUri($controller)); + } + + public function getGeneratorProxyUriData() + { + return array( + array('/controller.html', new ControllerReference('controller', array(), array())), + array('/controller.xml', new ControllerReference('controller', array('_format' => 'xml'), array())), + array('/controller.json?path=foo%3Dfoo', new ControllerReference('controller', array('foo' => 'foo', '_format' => 'json'), array())), + array('/controller.html?bar=bar&path=foo%3Dfoo', new ControllerReference('controller', array('foo' => 'foo'), array('bar' => 'bar'))), + array('/controller.html?foo=foo', new ControllerReference('controller', array(), array('foo' => 'foo'))), + ); + } + + public function testGenerateProxyUriWithARequest() + { + $request = Request::create('/'); + $request->attributes->set('_format', 'json'); + $controller = new ControllerReference('controller', array(), array()); + + $this->assertEquals('/controller.json', $this->getStrategy()->doGenerateProxyUri($controller, $request)); + } + + private function getStrategy() + { + $strategy = new Strategy(); + $strategy->setUrlGenerator($this->getUrlGenerator()); + + return $strategy; + } +} + +class Strategy extends GeneratorAwareRenderingStrategy +{ + public function render($uri, Request $request = null, array $options = array()) {} + public function getName() {} + + public function doGenerateProxyUri(ControllerReference $reference, Request $request = null) + { + return parent::generateProxyUri($reference, $request); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/HIncludeRenderingStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/HIncludeRenderingStrategyTest.php new file mode 100644 index 0000000000..ecc99665f8 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/RenderingStrategy/HIncludeRenderingStrategyTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\RenderingStrategy; + +use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\RenderingStrategy\HIncludeRenderingStrategy; +use Symfony\Component\HttpKernel\UriSigner; +use Symfony\Component\HttpFoundation\Request; + +class HIncludeRenderingStrategyTest extends AbstractRenderingStrategyTest +{ + protected function setUp() + { + if (!class_exists('Symfony\Component\HttpFoundation\Request')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + if (!interface_exists('Symfony\Component\Routing\Generator\UrlGeneratorInterface')) { + $this->markTestSkipped('The "Routing" component is not available'); + } + } + + /** + * @expectedException \LogicException + */ + public function testRenderExceptionWhenControllerAndNoSigner() + { + $strategy = new HIncludeRenderingStrategy(); + $strategy->render(new ControllerReference('main_controller', array(), array())); + } + + public function testRenderWithControllerAndSigner() + { + $strategy = new HIncludeRenderingStrategy(null, new UriSigner('foo')); + $strategy->setUrlGenerator($this->getUrlGenerator()); + $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', array(), array()))); + } + + public function testRenderWithUri() + { + $strategy = new HIncludeRenderingStrategy(); + $this->assertEquals('', $strategy->render('/foo')); + + $strategy = new HIncludeRenderingStrategy(null, new UriSigner('foo')); + $this->assertEquals('', $strategy->render('/foo')); + } + + public function testRenderWhithDefault() + { + // only default + $strategy = new HIncludeRenderingStrategy(); + $this->assertEquals('default', $strategy->render('/foo', null, array('default' => 'default'))); + + // only global default + $strategy = new HIncludeRenderingStrategy(null, null, 'global_default'); + $this->assertEquals('global_default', $strategy->render('/foo', null, array())); + + // global default and default + $strategy = new HIncludeRenderingStrategy(null, null, 'global_default'); + $this->assertEquals('default', $strategy->render('/foo', null, array('default' => 'default'))); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php b/src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php new file mode 100644 index 0000000000..8ffc2bfbbd --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/UriSignerTest.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests; + +use Symfony\Component\HttpKernel\UriSigner; + +class UriSignerTest extends \PHPUnit_Framework_TestCase +{ + public function testSign() + { + $signer = new UriSigner('foobar'); + + $this->assertContains('?_hash=', $signer->sign('http://example.com/foo')); + $this->assertContains('&_hash=', $signer->sign('http://example.com/foo?foo=bar')); + } + + public function testCheck() + { + $signer = new UriSigner('foobar'); + + $this->assertFalse($signer->check('http://example.com/foo?_hash=foo')); + $this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo')); + $this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo&bar=foo')); + + $this->assertTrue($signer->check($signer->sign('http://example.com/foo'))); + $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar'))); + } +} diff --git a/src/Symfony/Component/HttpKernel/UriSigner.php b/src/Symfony/Component/HttpKernel/UriSigner.php index 3530c31a77..45825fe246 100644 --- a/src/Symfony/Component/HttpKernel/UriSigner.php +++ b/src/Symfony/Component/HttpKernel/UriSigner.php @@ -48,19 +48,22 @@ class UriSigner /** * Checks that a URI contains the correct hash. * + * The _hash query string parameter must be the last one + * (as it is generated that way by the sign() method, it should + * never be a problem). + * * @param string $uri A signed URI * * @return Boolean True if the URI is signed correctly, false otherwise */ public function check($uri) { - if (!preg_match('/(\?|&)_hash=(.+?)(&|$)/', $uri, $matches, PREG_OFFSET_CAPTURE)) { + if (!preg_match('/(\?|&)_hash=(.+?)$/', $uri, $matches, PREG_OFFSET_CAPTURE)) { return false; } // the naked URI is the URI without the _hash parameter (we need to keep the ? if there is some other parameters after) - $offset = ('?' == $matches[1][0] && '&' != $matches[3][0]) ? 0 : 1; - $nakedUri = substr($uri, 0, $matches[0][1] + $offset).substr($uri, $matches[0][1] + strlen($matches[0][0])); + $nakedUri = substr($uri, 0, $matches[0][1]).substr($uri, $matches[0][1] + strlen($matches[0][0])); return $this->computeHash($nakedUri) === $matches[2][0]; } From d5825aac2f72e7c7e1dfeafe6e099652933088bd Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Jan 2013 16:29:45 +0100 Subject: [PATCH 087/128] slovenian translations of security component added --- .../Resources/translations/security.sl.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.sl.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.sl.xlf b/src/Symfony/Component/Security/Resources/translations/security.sl.xlf new file mode 100644 index 0000000000..ee70c9aaa4 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.sl.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Prišlo je do izjeme pri preverjanju avtentikacije. + + + Authentication credentials could not be found. + Poverilnic za avtentikacijo ni bilo mogoče najti. + + + Authentication request could not be processed due to a system problem. + Zahteve za avtentikacijo ni bilo mogoče izvesti zaradi sistemske težave. + + + Invalid credentials. + Neveljavne pravice. + + + Cookie has already been used by someone else. + Piškotek je uporabil že nekdo drug. + + + Not privileged to request the resource. + Nimate privilegijev za zahtevani vir. + + + Invalid CSRF token. + Neveljaven CSRF žeton. + + + Digest nonce has expired. + Začasni žeton je potekel. + + + No authentication provider found to support the authentication token. + Ponudnika avtentikacije za podporo prijavnega žetona ni bilo mogoče najti. + + + No session available, it either timed out or cookies are not enabled. + Seja ni na voljo, ali je potekla ali pa piškotki niso omogočeni. + + + No token could be found. + Žetona ni bilo mogoče najti. + + + Username could not be found. + Uporabniškega imena ni bilo mogoče najti. + + + Account has expired. + Račun je potekel. + + + Credentials have expired. + Poverilnice so potekle. + + + Account is disabled. + Račun je onemogočen. + + + Account is locked. + Račun je zaklenjen. + + + + From 0b75f67ae55ef5bd2929401aa78c56fcc1590c16 Mon Sep 17 00:00:00 2001 From: Tomasz Kowalczyk Date: Thu, 10 Jan 2013 16:50:43 +0100 Subject: [PATCH 088/128] Security component Polish message translations --- .../Resources/translations/security.pl.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.pl.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.pl.xlf b/src/Symfony/Component/Security/Resources/translations/security.pl.xlf new file mode 100644 index 0000000000..8d563d2120 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.pl.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Wystąpił błąd uwierzytelniania. + + + Authentication credentials could not be found. + Dane uwierzytelniania nie zostały znalezione. + + + Authentication request could not be processed due to a system problem. + Żądanie uwierzytelniania nie mogło zostać pomyślnie zakończone z powodu problemu z systemem. + + + Invalid credentials. + Nieprawidłowe dane. + + + Cookie has already been used by someone else. + To ciasteczko jest używane przez kogoś innego. + + + Not privileged to request the resource. + Brak uprawnień dla żądania wskazanego zasobu. + + + Invalid CSRF token. + Nieprawidłowy token CSRF. + + + Digest nonce has expired. + Kod dostępu wygasł. + + + No authentication provider found to support the authentication token. + Nie znaleziono mechanizmu uwierzytelniania zdolnego do obsługi przesłanego tokenu. + + + No session available, it either timed out or cookies are not enabled. + Brak danych sesji, sesja wygasła lub ciasteczka nie są włączone. + + + No token could be found. + Nie znaleziono tokenu. + + + Username could not be found. + Użytkownik o podanej nazwie nie istnieje. + + + Account has expired. + Konto wygasło. + + + Credentials have expired. + Dane uwierzytelniania wygasły. + + + Account is disabled. + Konto jest wyłączone. + + + Account is locked. + Konto jest zablokowane. + + + + From e848bc589bf75fbd17e37c3fa46d7b804afc21e4 Mon Sep 17 00:00:00 2001 From: Alex Demchenko Date: Thu, 10 Jan 2013 07:53:38 -0800 Subject: [PATCH 089/128] Add Russian translations --- .../Resources/translations/security.ru.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.ru.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.ru.xlf b/src/Symfony/Component/Security/Resources/translations/security.ru.xlf new file mode 100644 index 0000000000..b6c8d064af --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.ru.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Ошибка аутентификации. + + + Authentication credentials could not be found. + Полномочия не найдены. + + + Authentication request could not be processed due to a system problem. + Запрос аутентификации не может быть обработан из-за проблем в системе. + + + Invalid credentials. + Недействительные полномочия. + + + Cookie has already been used by someone else. + Cookie уже используются кем-то другим. + + + Not privileged to request the resource. + Нет привилегий для запроса ресурса. + + + Invalid CSRF token. + Недействительный CSRF token. + + + Digest nonce has expired. + Время дайджеста истекло. + + + No authentication provider found to support the authentication token. + Не найден провайдер аутентификации для поддержки токена аутентификации. + + + No session available, it either timed out or cookies are not enabled. + Сессия не найдена, в связи с таймаутом либо cookies не включены. + + + No token could be found. + Token не найден. + + + Username could not be found. + Username не найден. + + + Account has expired. + Время действия аккаунта истекло. + + + Credentials have expired. + Время действия полномочий истекли. + + + Account is disabled. + Аккаунт отключен. + + + Account is locked. + Аккаунт заблокирован. + + + + From d6f972bc1eb5687bf8276659971b123246b4bca7 Mon Sep 17 00:00:00 2001 From: Jakub Kucharovic Date: Thu, 10 Jan 2013 08:01:03 -0800 Subject: [PATCH 090/128] Created Slovak translation to Security --- .../Resources/translations/security.sk.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.sk.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.sk.xlf b/src/Symfony/Component/Security/Resources/translations/security.sk.xlf new file mode 100644 index 0000000000..e6552a6a09 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.sk.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Pri overovaní došlo k chybe. + + + Authentication credentials could not be found. + Overovacie údaje neboli nájdené. + + + Authentication request could not be processed due to a system problem. + Požiadavok na overenie nemohol byť spracovaný kvôli systémovej chybe. + + + Invalid credentials. + Neplatné prihlasovacie údaje. + + + Cookie has already been used by someone else. + Cookie už bolo použité niekým iným. + + + Not privileged to request the resource. + Nemáte oprávnenie pristupovať k prostriedku. + + + Invalid CSRF token. + Neplatný CSRF token. + + + Digest nonce has expired. + Platnosť inicializačného vektoru (digest nonce) skončila. + + + No authentication provider found to support the authentication token. + Poskytovateľ pre overovací token nebol nájdený. + + + No session available, it either timed out or cookies are not enabled. + Session nie je k dispozíci, vypršala jej platnosť, alebo sú zakázané cookies. + + + No token could be found. + Token nebol nájdený. + + + Username could not be found. + Prihlasovacie meno nebolo nájdené. + + + Account has expired. + Platnosť účtu skončila. + + + Credentials have expired. + Platnosť prihlasovacích údajov skončila. + + + Account is disabled. + Účet je zakázaný. + + + Account is locked. + Účet je zablokovaný. + + + + From 76fefe35375abc7b29ae1aa340a20138d863553f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 10 Jan 2013 16:47:11 +0100 Subject: [PATCH 091/128] updated CHANGELOG and UPGRADE files --- UPGRADE-2.2.md | 11 +++++++---- src/Symfony/Bridge/Twig/CHANGELOG.md | 6 ++++-- src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md | 13 +++++++++---- src/Symfony/Component/HttpFoundation/CHANGELOG.md | 2 ++ src/Symfony/Component/HttpFoundation/Request.php | 2 ++ src/Symfony/Component/HttpKernel/CHANGELOG.md | 5 +++++ 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md index c485bf6112..3b8583d908 100644 --- a/UPGRADE-2.2.md +++ b/UPGRADE-2.2.md @@ -14,11 +14,9 @@ After: ``` - {% render url('post_list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error' } %} + {% render controller('BlogBundle:Post:list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error' } %} ``` - where `post_list` is the route name for the `BlogBundle:Post:list` controller. - ### HttpFoundation * The MongoDbSessionHandler default field names and timestamp type have changed. @@ -409,7 +407,12 @@ render($view['router']->generate('post_list', array('limit' => 2)), array('alt' => 'BlogBundle:Post:error')) ?> ``` - where `post_list` is the route name for the `BlogBundle:Post:list` controller. + where `post_list` is the route name for the `BlogBundle:Post:list` + controller, or if you don't want to create a route: + + ``` + render(new ControllerReference('BlogBundle:Post:list', array('limit' => 2)), array('alt' => 'BlogBundle:Post:error')) ?> + ``` #### Configuration diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index 420a99b61f..343c7743a3 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -4,8 +4,10 @@ CHANGELOG 2.2.0 ----- - * [BC BREAK] restricted the `render` tag to only accept URIs as reference (the signature changed) - * added a render function to render a request + * added a `controller` function to help generating controller references + * added a `render_esi` and a `render_hinclude` function + * [BC BREAK] restricted the `render` tag to only accept URIs or ControllerReference instances (the signature changed) + * added a `render` function to render a request * The `app` global variable is now injected even when using the twig service directly. * Added an optional parameter to the `path` and `url` function which allows to generate relative paths (e.g. "../parent-file") and scheme-relative URLs (e.g. "//example.com/dir/file"). diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index af67c70ea2..5797f3f19f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,11 +4,16 @@ CHANGELOG 2.2.0 ----- - * [BC BREAK] restricted the `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` method to only accept URIs as reference + * added a new `uri_signer` service to help sign URIs + * deprecated `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` and `Symfony\Bundle\FrameworkBundle\HttpKernel::forward()` + * deprecated the `Symfony\Bundle\FrameworkBundle\HttpKernel` class in favor of `Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel` + * added support for adding new HTTP content rendering strategies (like ESI and Hinclude) + in the DIC via the `kernel.content_renderer_strategy` tag + * [BC BREAK] restricted the `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` method to only accept URIs or ControllerReference instances * `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` method signature changed and the first argument - must now be a URI (the `generateInternalUri()` method was removed) - * The internal routes have been removed (`Resources/config/routing/internal.xml`) - * The `render` method of the `actions` templating helper signature and arguments changed: + must now be a URI or a ControllerReference instance (the `generateInternalUri()` method was removed) + * The internal routes (`Resources/config/routing/internal.xml`) have been replaced with a new proxy route (`Resources/config/routing/proxy.xml`) + * The `render` method of the `actions` templating helper signature and arguments changed * replaced Symfony\Bundle\FrameworkBundle\Controller\TraceableControllerResolver by Symfony\Component\HttpKernel\Controller\TraceableControllerResolver * replaced Symfony\Component\HttpKernel\Debug\ContainerAwareTraceableEventDispatcher by Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher * added Client::enableProfiler() diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index c83695f747..1ec5492883 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 2.2.0 ----- + * added Request::getTrustedProxies() + * deprecated Request::isProxyTrusted() * added a IpUtils class to check if an IP belongs to a CIDR * added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method) * disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to enable it) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 0bac66ada7..96ade68f01 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -527,6 +527,8 @@ class Request * false otherwise. * * @return boolean + * + * @deprecated Deprecated since version 2.2, to be removed in 2.3. Use getTrustedProxies instead. */ public static function isProxyTrusted() { diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 75b5d9321a..15ddbf199d 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -4,6 +4,11 @@ CHANGELOG 2.2.0 ----- + * added Symfony\Component\HttpKernel\UriSigner + * added Symfony\Component\HttpKernel\HttpContentRenderer and rendering strategies (in Symfony\Component\HttpKernel\RenderingStrategy) + * added Symfony\Component\HttpKernel\EventListener\RouterProxyListener + * added Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel + * added ControllerReference to create reference of Controllers (used in the HttpContentRenderer class) * [BC BREAK] renamed TimeDataCollector::getTotalTime() to TimeDataCollector::getDuration() * updated the MemoryDataCollector to include the memory used in the From c6eb81938b7b52d5109f6e019c19b8d3edba1d2f Mon Sep 17 00:00:00 2001 From: Jakub Kucharovic Date: Thu, 10 Jan 2013 08:19:03 -0800 Subject: [PATCH 092/128] Created security.cs.xlf --- .../Resources/translations/security.cs.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.cs.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.cs.xlf b/src/Symfony/Component/Security/Resources/translations/security.cs.xlf new file mode 100644 index 0000000000..4757762b32 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.cs.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Při ověřování došlo k chybě. + + + Authentication credentials could not be found. + Ověřovací údaje nebyly nalezeny. + + + Authentication request could not be processed due to a system problem. + Požadavek na ověření nemohl být zpracován kvôli systémové chybě. + + + Invalid credentials. + Neplatné přihlašovací údaje. + + + Cookie has already been used by someone else. + Cookie již bylo použité někým jiným. + + + Not privileged to request the resource. + Nemáte oprávnění přistupovat k prostředku. + + + Invalid CSRF token. + Neplatný CSRF token. + + + Digest nonce has expired. + Platnost inicializačního vektoru (digest nonce) vypršela. + + + No authentication provider found to support the authentication token. + Poskytovatel pro ověřovací token nebyl nalezen. + + + No session available, it either timed out or cookies are not enabled. + Session není k dispozici, vypršela její platnost, nebo jsou zakázané cookies. + + + No token could be found. + Token nebyl nalezen. + + + Username could not be found. + Přihlašovací jméno nebylo nalezeno. + + + Account has expired. + Platnost účtu vypršela. + + + Credentials have expired. + Platnost přihlašovacích údajů vypršela. + + + Account is disabled. + Účet je zakázaný. + + + Account is locked. + Účet je zablokovaný. + + + + From b74c00f9a86606e0bf6856d4d8db90bfe265944a Mon Sep 17 00:00:00 2001 From: SPolischook Date: Thu, 10 Jan 2013 18:36:00 +0200 Subject: [PATCH 093/128] [security][translation] added ukrainian message translations --- .../Resources/translations/security.ua.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.ua.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.ua.xlf b/src/Symfony/Component/Security/Resources/translations/security.ua.xlf new file mode 100644 index 0000000000..7bd7250e13 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.ua.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Помилка аутентифікації + + + Authentication credentials could not be found. + Перевірка справжності облікових данних не знайдена + + + Authentication request could not be processed due to a system problem. + Запит на аутентифікацію не може бути опрацьований через проблеми в системі. + + + Invalid credentials. + Невірний логін або пароль. + + + Cookie has already been used by someone else. + Файли cookie вже були використані кимось іншим. + + + Not privileged to request the resource. + Недостатньо прав для доступу до ресурсу. + + + Invalid CSRF token. + Невірний CSRF токен. + + + Digest nonce has expired. + Закінчився строк дії криптографічного ключа (digest nonce). + + + No authentication provider found to support the authentication token. + Для підтримки токену не знайден провайдер аутентифікації. + + + No session available, it either timed out or cookies are not enabled. + Сесія недоступна - тайм-аут або файли cookies вимкнені. + + + No token could be found. + Токен не знайдено. + + + Username could not be found. + Ім’я користувача не знайдено. + + + Account has expired. + Закінчився строк дії облікового запису. + + + Credentials have expired. + Строк дії облікових данних вичерпаний. + + + Account is disabled. + Обліковий запис відключений. + + + Account is locked. + Обліковий запис заблокований. + + + + From d027f458338a1b75cf75abce423127f46fdbddae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20PY?= Date: Thu, 10 Jan 2013 17:46:24 +0100 Subject: [PATCH 094/128] [PROFILER][REDIS] Support database, auth on redis connection --- .../Profiler/RedisProfilerStorage.php | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Profiler/RedisProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/RedisProfilerStorage.php index 5c143129c0..047b8ac62e 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/RedisProfilerStorage.php +++ b/src/Symfony/Component/HttpKernel/Profiler/RedisProfilerStorage.php @@ -17,6 +17,7 @@ use Redis; * RedisProfilerStorage stores profiling information in Redis. * * @author Andrej Hudec + * @author Stephane PY */ class RedisProfilerStorage implements ProfilerStorageInterface { @@ -213,19 +214,26 @@ class RedisProfilerStorage implements ProfilerStorageInterface protected function getRedis() { if (null === $this->redis) { - if (!preg_match('#^redis://(?(?=\[.*\])\[(.*)\]|(.*)):(.*)$#', $this->dsn, $matches)) { - throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Redis with an invalid dsn "%s". The expected format is "redis://[host]:port".', $this->dsn)); - } + $data = parse_url($this->dsn); - $host = $matches[1] ?: $matches[2]; - $port = $matches[3]; + if (false === $data || !isset($data['scheme']) || $data['scheme'] !== 'redis' || !isset($data['host']) || !isset($data['port'])) { + throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Redis with an invalid dsn "%s". The minimal expected format is "redis://[host]:port".', $this->dsn)); + } if (!extension_loaded('redis')) { throw new \RuntimeException('RedisProfilerStorage requires that the redis extension is loaded.'); } $redis = new Redis; - $redis->connect($host, $port); + $redis->connect($data['host'], $data['port']); + + if (isset($data['path'])) { + $redis->select(substr($data['path'], 1)); + } + + if (isset($data['pass'])) { + $redis->auth($data['pass']); + } $redis->setOption(self::REDIS_OPT_PREFIX, self::TOKEN_PREFIX); From 9471a1ce5a4c8e9b600ce9e7190d87175464cae2 Mon Sep 17 00:00:00 2001 From: Michel Weimerskirch Date: Thu, 10 Jan 2013 17:51:56 +0100 Subject: [PATCH 095/128] Added Luxembourgish translation for security component --- .../Resources/translations/security.lb.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.lb.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.lb.xlf b/src/Symfony/Component/Security/Resources/translations/security.lb.xlf new file mode 100644 index 0000000000..3dc76d5486 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.lb.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Bei der Authentifikatioun ass e Feeler opgetrueden. + + + Authentication credentials could not be found. + Et konnte keng Zouganksdate fonnt ginn. + + + Authentication request could not be processed due to a system problem. + D'Ufro fir eng Authentifikatioun konnt wéinst engem Problem vum System net beaarbecht ginn. + + + Invalid credentials. + Ongëlteg Zouganksdaten. + + + Cookie has already been used by someone else. + De Cookie gouf scho vun engem anere benotzt. + + + Not privileged to request the resource. + Keng Rechter fir d'Ressource unzefroen. + + + Invalid CSRF token. + Ongëltegen CSRF-Token. + + + Digest nonce has expired. + Den eemolege Schlëssel ass ofgelaf. + + + No authentication provider found to support the authentication token. + Et gouf keen Authentifizéierungs-Provider fonnt deen den Authentifizéierungs-Token ënnerstëtzt. + + + No session available, it either timed out or cookies are not enabled. + Keng Sëtzung disponibel. Entweder ass se ofgelaf oder Cookies sinn net aktivéiert. + + + No token could be found. + Et konnt keen Token fonnt ginn. + + + Username could not be found. + De Benotzernumm konnt net fonnt ginn. + + + Account has expired. + Den Account ass ofgelaf. + + + Credentials have expired. + D'Zouganksdate sinn ofgelaf. + + + Account is disabled. + De Konto ass deaktivéiert. + + + Account is locked. + De Konto ass gespaart. + + + + From b92973ca3558b437fd454513af056d0411bf674a Mon Sep 17 00:00:00 2001 From: Michel Weimerskirch Date: Thu, 10 Jan 2013 18:09:49 +0100 Subject: [PATCH 096/128] Fixed German translations for security component authentication != authorisation + a few other minor things --- .../Security/Resources/translations/security.de.xlf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.de.xlf b/src/Symfony/Component/Security/Resources/translations/security.de.xlf index 3142ffb15c..e5946ed4aa 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.de.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.de.xlf @@ -4,7 +4,7 @@ An authentication exception occurred. - Es ist ein Fehler bei der Authorisierung aufgetreten. + Es ist ein Fehler bei der Authentifikation aufgetreten. Authentication credentials could not be found. @@ -12,7 +12,7 @@ Authentication request could not be processed due to a system problem. - Die Authorisierung konnte wegen eines Systemproblems nicht bearbeitet werden. + Die Authentifikation konnte wegen eines Systemproblems nicht bearbeitet werden. Invalid credentials. @@ -20,15 +20,15 @@ Cookie has already been used by someone else. - Cookie wurde bereits von jemand Anderem verwendet. + Cookie wurde bereits von jemand anderem verwendet. Not privileged to request the resource. - Keine Rechte, um die Resource anzufragen. + Keine Rechte, um die Ressource anzufragen. Invalid CSRF token. - Ungültiges CSRF Token. + Ungültiges CSRF-Token. Digest nonce has expired. @@ -48,7 +48,7 @@ Username could not be found. - Der Username wurde nicht gefunden. + Der Benutzername wurde nicht gefunden. Account has expired. From 1edf3026d7c42c38da71395e3df2ccffecc35f95 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 10 Jan 2013 18:12:39 +0100 Subject: [PATCH 097/128] Fixed some translation typos --- .../Security/Resources/translations/security.es.xlf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Resources/translations/security.es.xlf index e7987922a3..107be22616 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es.xlf @@ -8,7 +8,7 @@ Authentication credentials could not be found. - No se encontraron los credenciales de autenticación. + No se encontraron las credenciales de autenticación. Authentication request could not be processed due to a system problem. @@ -16,7 +16,7 @@ Invalid credentials. - Credenciales no válidos. + Credenciales no válidas. Cookie has already been used by someone else. @@ -56,7 +56,7 @@ Credentials have expired. - Los credenciales han expirado. + Las credenciales han expirado. Account is disabled. From 53c5d9bf66c4a31fb73f8f40a67ed763c3d23673 Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Thu, 10 Jan 2013 17:14:38 +0000 Subject: [PATCH 098/128] [Security] Missing trailing dot. --- .../Component/Security/Resources/translations/security.ua.xlf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.ua.xlf b/src/Symfony/Component/Security/Resources/translations/security.ua.xlf index 7bd7250e13..82b7834b14 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.ua.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.ua.xlf @@ -4,11 +4,11 @@ An authentication exception occurred. - Помилка аутентифікації + Помилка аутентифікації. Authentication credentials could not be found. - Перевірка справжності облікових данних не знайдена + Перевірка справжності облікових данних не знайдена. Authentication request could not be processed due to a system problem. From a1ef9d86f0581a4a668bbc4f59ca8f32408be89f Mon Sep 17 00:00:00 2001 From: Michel Weimerskirch Date: Thu, 10 Jan 2013 18:19:20 +0100 Subject: [PATCH 099/128] Fixed 2 typos in French translation --- .../Component/Security/Resources/translations/security.fr.xlf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.fr.xlf b/src/Symfony/Component/Security/Resources/translations/security.fr.xlf index 207929b7c3..f3965d3fb3 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.fr.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.fr.xlf @@ -40,7 +40,7 @@ No session available, it either timed out or cookies are not enabled. - Pas de session disponible, celle-ci à expiré ou les cookies ne sont pas activés. + Pas de session disponible, celle-ci a expiré ou les cookies ne sont pas activés. No token could be found. @@ -52,7 +52,7 @@ Account has expired. - Le compte à expiré. + Le compte a expiré. Credentials have expired. From d4bbb6b737c319c083b5167611523bdbc0afad54 Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Thu, 10 Jan 2013 17:33:44 +0000 Subject: [PATCH 100/128] [Security] Missing trailing dot. --- .../Component/Security/Resources/translations/security.nl.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf index 7a9fd719de..6f7d4da6fd 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf @@ -24,7 +24,7 @@ Not privileged to request the resource. - Onvoldoende rechten om deze aanvraag te verwerken + Onvoldoende rechten om deze aanvraag te verwerken. Invalid CSRF token. From 77545a2ee5b9cdd8a2c9216f188aa35a082c310a Mon Sep 17 00:00:00 2001 From: tkinast Date: Thu, 10 Jan 2013 15:37:47 -0200 Subject: [PATCH 101/128] Update src/Symfony/Component/Security/Resources/translations/security.es.xlf --- .../Security/Resources/translations/security.es.xlf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es.xlf b/src/Symfony/Component/Security/Resources/translations/security.es.xlf index e7987922a3..55801aed77 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es.xlf @@ -4,11 +4,11 @@ An authentication exception occurred. - Ocurrió una error de autenticación. + Ocurrió un error de autenticación. Authentication credentials could not be found. - No se encontraron los credenciales de autenticación. + No se encontraron las credenciales de autenticación. Authentication request could not be processed due to a system problem. @@ -16,7 +16,7 @@ Invalid credentials. - Credenciales no válidos. + Credenciales no válidas. Cookie has already been used by someone else. From 65bb3d20ae95417f4765aa97906c38b535446689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Sj=C3=B6sten?= Date: Thu, 10 Jan 2013 10:04:48 -0800 Subject: [PATCH 102/128] Added Swedish translation --- .../Resources/translations/security.sv.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.sv.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.sv.xlf b/src/Symfony/Component/Security/Resources/translations/security.sv.xlf new file mode 100644 index 0000000000..b5f6209236 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.sv.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Ett autentiseringsfel har inträffat. + + + Authentication credentials could not be found. + Uppgifterna för autentisering kunde inte hittas. + + + Authentication request could not be processed due to a system problem. + Autentiseringen kunde inte genomföras på grund av systemfel. + + + Invalid credentials. + Felaktiga uppgifter. + + + Cookie has already been used by someone else. + Cookien har redan använts av någon annan. + + + Not privileged to request the resource. + Saknar rättigheter för resursen. + + + Invalid CSRF token. + Ogiltig CSRF-token. + + + Digest nonce has expired. + Förfallen digest nonce. + + + No authentication provider found to support the authentication token. + Ingen leverantör för autentisering hittades för angiven autentiseringstoken. + + + No session available, it either timed out or cookies are not enabled. + Ingen session finns tillgänglig, antingen har den förfallit eller är cookies inte aktiverat. + + + No token could be found. + Ingen token kunde hittas. + + + Username could not be found. + Användarnamnet kunde inte hittas. + + + Account has expired. + Kontot har förfallit. + + + Credentials have expired. + Uppgifterna har förfallit. + + + Account is disabled. + Kontot är inaktiverat. + + + Account is locked. + Kontot är låst. + + + + From 08f9c7633e168832e43206df4b1a2c46775a47ef Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Thu, 10 Jan 2013 19:55:35 +0100 Subject: [PATCH 103/128] Update src/Symfony/Component/Security/Resources/translations/security.nl.xlf For the Dutch people under us. http://www.kiezelcommunicatie.nl/kiezelblog/woorden-die-niet-meer-mogen-aflevering-1/ Yes I'm picky ;) --- .../Component/Security/Resources/translations/security.nl.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf index 6f7d4da6fd..5261668949 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf @@ -20,7 +20,7 @@ Cookie has already been used by someone else. - Cookie werd reeds door een ander persoon gebruikt. + Cookie werd al door een ander persoon gebruikt. Not privileged to request the resource. From 0d6be2e81a2bb560a622b093301409087f1feec2 Mon Sep 17 00:00:00 2001 From: Tiago Brito Date: Thu, 10 Jan 2013 22:01:22 +0000 Subject: [PATCH 104/128] Added Portuguese (Portugal) translation to Security Added Portuguese from Portugal translation for Security component --- .../Resources/translations/security.pt_PT.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.pt_PT.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.pt_PT.xlf b/src/Symfony/Component/Security/Resources/translations/security.pt_PT.xlf new file mode 100644 index 0000000000..e661000148 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.pt_PT.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Ocorreu um excepção durante a autenticação. + + + Authentication credentials could not be found. + As credenciais de autenticação não foram encontradas. + + + Authentication request could not be processed due to a system problem. + O pedido de autenticação não foi concluído devido a um problema no sistema. + + + Invalid credentials. + Credenciais inválidas. + + + Cookie has already been used by someone else. + Este cookie já esta em uso. + + + Not privileged to request the resource. + Não possui privilégios para aceder a este recurso. + + + Invalid CSRF token. + Token CSRF inválido. + + + Digest nonce has expired. + Digest nonce expirado. + + + No authentication provider found to support the authentication token. + Nenhum fornecedor de autenticação encontrado para suportar o token de autenticação. + + + No session available, it either timed out or cookies are not enabled. + Não existe sessão disponível, esta expirou ou os cookies estão desativados. + + + No token could be found. + O token não foi encontrado. + + + Username could not be found. + Nome de utilizador não encontrado. + + + Account has expired. + A conta expirou. + + + Credentials have expired. + As credenciais expiraram. + + + Account is disabled. + Conta desativada. + + + Account is locked. + A conta esta trancada. + + + + From 69535cfe421c5f26e77f55cadb9a75a9246bc321 Mon Sep 17 00:00:00 2001 From: Jan Kramer Date: Fri, 11 Jan 2013 07:43:26 +0100 Subject: [PATCH 105/128] Fixed broken setter in Form/Util/PropertyPath --- src/Symfony/Component/Form/Util/PropertyPath.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Util/PropertyPath.php b/src/Symfony/Component/Form/Util/PropertyPath.php index 445fae81d5..41acf0d889 100644 --- a/src/Symfony/Component/Form/Util/PropertyPath.php +++ b/src/Symfony/Component/Form/Util/PropertyPath.php @@ -48,10 +48,10 @@ class PropertyPath extends BasePropertyPath /** * Alias for {@link PropertyAccessor::setValue()} */ - public function setValue($objectOrArray, $value) + public function setValue(&$objectOrArray, $value) { $propertyAccessor = PropertyAccess::getPropertyAccessor(); - return $propertyAccessor->getValue($objectOrArray, $this, $value); + return $propertyAccessor->setValue($objectOrArray, $this, $value); } } From 2d07a17cbd839b52e547cb80e148f810795c23a1 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 9 Jan 2013 11:27:45 +0100 Subject: [PATCH 106/128] Remove special handling of empty arrays, fixes #5506 --- .../Component/HttpFoundation/JsonResponse.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/JsonResponse.php b/src/Symfony/Component/HttpFoundation/JsonResponse.php index c131575f01..b6ac8017a3 100644 --- a/src/Symfony/Component/HttpFoundation/JsonResponse.php +++ b/src/Symfony/Component/HttpFoundation/JsonResponse.php @@ -28,17 +28,20 @@ class JsonResponse extends Response * @param integer $status The response status code * @param array $headers An array of response headers */ - public function __construct($data = array(), $status = 200, $headers = array()) + public function __construct($data = null, $status = 200, $headers = array()) { parent::__construct('', $status, $headers); + if (null === $data) { + $data = new \ArrayObject(); + } $this->setData($data); } /** * {@inheritDoc} */ - public static function create($data = array(), $status = 200, $headers = array()) + public static function create($data = null, $status = 200, $headers = array()) { return new static($data, $status, $headers); } @@ -79,11 +82,6 @@ class JsonResponse extends Response */ public function setData($data = array()) { - // root should be JSON object, not array - if (is_array($data) && 0 === count($data)) { - $data = new \ArrayObject(); - } - // Encode <, >, ', &, and " for RFC4627-compliant JSON, which may also be embedded into HTML. $this->data = json_encode($data, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT); From 2aba3aa4904385d09e8565c88961372196000c11 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 11 Jan 2013 08:05:42 +0100 Subject: [PATCH 107/128] [HttpFoundation] added missing info in CHANGELOG --- src/Symfony/Component/HttpFoundation/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index c83695f747..b81fe51fd4 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 2.2.0 ----- + * [BC BREAK] JsonResponse does not change a top level array to an object when the array is empty anymore in setData() * added a IpUtils class to check if an IP belongs to a CIDR * added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method) * disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to enable it) From a31a6531c7a96f8f3c0cce99c9ab9344df3f0b0e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 11 Jan 2013 09:12:57 +0100 Subject: [PATCH 108/128] [HttpKernel] fixed usage of false as a valid strategy (for BC) --- src/Symfony/Component/HttpKernel/HttpContentRenderer.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php index 4849b8f6b5..ca35cd711f 100644 --- a/src/Symfony/Component/HttpKernel/HttpContentRenderer.php +++ b/src/Symfony/Component/HttpKernel/HttpContentRenderer.php @@ -126,6 +126,10 @@ class HttpContentRenderer implements EventSubscriberInterface trigger_error('The "true" value for the "standalone" option is deprecated in version 2.2 and replaced with the "esi" value.', E_USER_DEPRECATED); $options['standalone'] = 'esi'; + } elseif (false === $options['standalone']) { + trigger_error('The "false" value for the "standalone" option is deprecated in version 2.2 and replaced with the "default" value.', E_USER_DEPRECATED); + + $options['standalone'] = 'default'; } elseif ('js' === $options['standalone']) { trigger_error('The "js" value for the "standalone" option is deprecated in version 2.2 and replaced with the "hinclude" value.', E_USER_DEPRECATED); From 8d06c571eda47bf7809bccaa71f7dd1990bd6464 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 11 Jan 2013 09:20:00 +0100 Subject: [PATCH 109/128] [HttpFoundation] Fix sentence and provide a hint at the solution for affected people --- src/Symfony/Component/HttpFoundation/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 252eac5e3f..e7d89364b3 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -6,7 +6,7 @@ CHANGELOG * added Request::getTrustedProxies() * deprecated Request::isProxyTrusted() - * [BC BREAK] JsonResponse does not change a top level array to an object when the array is empty anymore in setData() + * [BC BREAK] JsonResponse does not turn a top level empty array to an object anymore, use an ArrayObject to enforce objects * added a IpUtils class to check if an IP belongs to a CIDR * added Request::getRealMethod() to get the "real" HTTP method (getMethod() returns the "intended" HTTP method) * disabled _method request parameter support by default (call Request::enableHttpMethodParameterOverride() to enable it) From 2617cf64c3f939dfb5859ec30aedab877fd37366 Mon Sep 17 00:00:00 2001 From: Sinan Eldem Date: Fri, 11 Jan 2013 10:47:35 +0200 Subject: [PATCH 110/128] Added Turkish translation for security component --- .../Resources/translations/security.tr.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.tr.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.tr.xlf b/src/Symfony/Component/Security/Resources/translations/security.tr.xlf new file mode 100644 index 0000000000..fbf9b260b0 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.tr.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Bir yetkilendirme istisnası oluştu. + + + Authentication credentials could not be found. + Yetkilendirme girdileri bulunamadı. + + + Authentication request could not be processed due to a system problem. + Bir sistem hatası nedeniyle yetkilendirme isteği işleme alınamıyor. + + + Invalid credentials. + Geçersiz girdiler. + + + Cookie has already been used by someone else. + Çerez bir başkası tarafından zaten kullanılmıştı. + + + Not privileged to request the resource. + Kaynak talebi için imtiyaz bulunamadı. + + + Invalid CSRF token. + Geçersiz CSRF fişi. + + + Digest nonce has expired. + Derleme zaman aşımı gerçekleşti. + + + No authentication provider found to support the authentication token. + Yetkilendirme fişini destekleyecek yetkilendirme sağlayıcısı bulunamadı. + + + No session available, it either timed out or cookies are not enabled. + Oturum bulunamadı, zaman aşımına uğradı veya çerezler etkin değil. + + + No token could be found. + Bilet bulunamadı. + + + Username could not be found. + Kullanıcı adı bulunamadı. + + + Account has expired. + Hesap zaman aşımına uğradı. + + + Credentials have expired. + Girdiler zaman aşımına uğradı. + + + Account is disabled. + Hesap devre dışı bırakılmış. + + + Account is locked. + Hesap kilitlenmiş. + + + + From 6b669fbddfaffc96483bc93201ce7e12c3f95852 Mon Sep 17 00:00:00 2001 From: Bart van den Burg Date: Fri, 11 Jan 2013 10:49:55 +0100 Subject: [PATCH 111/128] Update src/Symfony/Component/Security/Resources/translations/security.nl.xlf see #6668 Some more minor tweaks --- .../Resources/translations/security.nl.xlf | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf index 5261668949..8969e9ef8c 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.nl.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.nl.xlf @@ -12,35 +12,35 @@ Authentication request could not be processed due to a system problem. - Authenticatie-aanvraag kon niet worden verwerkt door een technisch probleem. + Authenticatieaanvraag kon niet worden verwerkt door een technisch probleem. Invalid credentials. - Ongeldige rechten. + Ongeldige inloggegevens. Cookie has already been used by someone else. - Cookie werd al door een ander persoon gebruikt. + Cookie is al door een ander persoon gebruikt. Not privileged to request the resource. - Onvoldoende rechten om deze aanvraag te verwerken. + Onvoldoende rechten om de aanvraag te verwerken. Invalid CSRF token. - CSRF code is ongeldig. + CSRF-code is ongeldig. Digest nonce has expired. - Server authenticatiesleutel (digest nonce) is verlopen. + Serverauthenticatiesleutel (digest nonce) is verlopen. No authentication provider found to support the authentication token. - Geen authenticatieprovider gevonden die het authenticatietoken ondersteunt. + Geen authenticatieprovider gevonden die de authenticatietoken ondersteunt. No session available, it either timed out or cookies are not enabled. - Geen sessie beschikbaar, deze kan verlopen zijn of cookies zijn niet geactiveerd. + Geen sessie beschikbaar, mogelijk is deze verlopen of cookies zijn uitgeschakeld. No token could be found. @@ -48,7 +48,7 @@ Username could not be found. - Gebruikersnaam werd niet gevonden. + Gebruikersnaam kon niet worden gevonden. Account has expired. From eb0d2abb1be5a860339acc2fe816a32d10340e8b Mon Sep 17 00:00:00 2001 From: Joseph Bielawski Date: Fri, 11 Jan 2013 11:33:37 +0100 Subject: [PATCH 112/128] [HttpKernel] Remove conflicting `use` from `NullLogger` --- src/Symfony/Component/HttpKernel/Log/NullLogger.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Log/NullLogger.php b/src/Symfony/Component/HttpKernel/Log/NullLogger.php index b5aa2e3094..8c1dfaa3b3 100644 --- a/src/Symfony/Component/HttpKernel/Log/NullLogger.php +++ b/src/Symfony/Component/HttpKernel/Log/NullLogger.php @@ -11,7 +11,6 @@ namespace Symfony\Component\HttpKernel\Log; -use Psr\Log\LoggerInterface; use Psr\Log\NullLogger as PsrNullLogger; /** From f127781f2ea7341e242c9bd0d35cb741fa2bf3ca Mon Sep 17 00:00:00 2001 From: Alexander Miehe Date: Fri, 11 Jan 2013 13:33:14 +0100 Subject: [PATCH 113/128] Update src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add use HttpKernelInterface for refactored forward method --- src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php index 0196058642..5655595a68 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\DependencyInjection\ContainerAware; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormBuilder; From 83d04699d2a1d4dc950a4612b9cd7d4b815d8045 Mon Sep 17 00:00:00 2001 From: Cristobal Dabed Date: Fri, 11 Jan 2013 05:12:25 -0800 Subject: [PATCH 114/128] Create security.no.xlf Norwegian Translation --- .../Resources/translations/security.no.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.no.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.no.xlf b/src/Symfony/Component/Security/Resources/translations/security.no.xlf new file mode 100644 index 0000000000..3857ab4693 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.no.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + En autentiserings feil har skjedd. + + + Authentication credentials could not be found. + Påloggingsinformasjonen kunne ikke bli funnet. + + + Authentication request could not be processed due to a system problem. + Autentiserings forespørselen kunne ikke bli prosessert grunnet en system feil. + + + Invalid credentials. + Ugyldig påloggingsinformasjonen. + + + Cookie has already been used by someone else. + Cookie har allerede blitt brukt av noen andre. + + + Not privileged to request the resource. + Ingen tilgang til å be om gitt kilde. + + + Invalid CSRF token. + Ugyldig CSRF token. + + + Digest nonce has expired. + Digest nonce er utløpt. + + + No authentication provider found to support the authentication token. + Ingen autentiserings tilbyder funnet som støtter gitt autentiserings token. + + + No session available, it either timed out or cookies are not enabled. + Ingen sesjon tilgjengelig, sesjonen er enten utløpt eller cookies ikke skrudd på. + + + No token could be found. + Ingen token kunne bli funnet. + + + Username could not be found. + Brukernavn kunne ikke bli funnet. + + + Account has expired. + Brukerkonto har utgått. + + + Credentials have expired. + Påloggingsinformasjon har utløpt. + + + Account is disabled. + Brukerkonto er deaktivert. + + + Account is locked. + Brukerkonto er sperret. + + + + From 5ee65aa8bee76b6536314b175d64ec5467ebc74a Mon Sep 17 00:00:00 2001 From: Joan Cruz Date: Fri, 11 Jan 2013 13:21:39 +0100 Subject: [PATCH 115/128] Contribution to translation to Catalan of the security messages --- .../Resources/translations/security.es_CA.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf b/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf new file mode 100644 index 0000000000..3f106d8eb2 --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Ha succeït un error d'autenticació. + + + Authentication credentials could not be found. + No s'han trobat les credencials d'autenticació. + + + Authentication request could not be processed due to a system problem. + La solicitud d'autenticació no s'ha pogut processar per un problema del sistema. + + + Invalid credentials. + Credencials no vàlides. + + + Cookie has already been used by someone else. + La cookie ja ha estat utilitzada per una altra persona. + + + Not privileged to request the resource. + No te privilegis per solicitar el recurs. + + + Invalid CSRF token. + Token CSRF no vàlid. + + + Digest nonce has expired. + El vector d'iniciaització (digest nonce) ha expirat. + + + No authentication provider found to support the authentication token. + No s'ha trobat un proveidor d'autenticació que suporti el token d'autenticació. + + + No session available, it either timed out or cookies are not enabled. + No hi ha sessió disponible, ha expirat o les cookies no estan habilitades. + + + No token could be found. + No s'ha trobat cap token. + + + Username could not be found. + No s'ha trobat el nom d'usuari. + + + Account has expired. + El compte ha expirat. + + + Credentials have expired. + Les credencials han expirat. + + + Account is disabled. + El compte està deshabilitat. + + + Account is locked. + El compte està bloquejat. + + + + From 9d310647e93129d3d41433a9f136c145e4a2b983 Mon Sep 17 00:00:00 2001 From: jorgemartind Date: Fri, 11 Jan 2013 18:10:54 +0100 Subject: [PATCH 116/128] Update src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf [Security] update catalonian translation --- .../Security/Resources/translations/security.es_CA.xlf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf b/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf index 3f106d8eb2..3fb8987b40 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf @@ -24,7 +24,7 @@ Not privileged to request the resource. - No te privilegis per solicitar el recurs. + No té privilegis per solicitar el recurs. Invalid CSRF token. @@ -32,7 +32,7 @@ Digest nonce has expired. - El vector d'iniciaització (digest nonce) ha expirat. + El vector d'inicialització (digest nonce) ha expirat. No authentication provider found to support the authentication token. From 0a060cabebd85c19ad9b0114a72e61a7fd7ddc5e Mon Sep 17 00:00:00 2001 From: Dmitrii Chekaliuk Date: Fri, 11 Jan 2013 19:28:56 +0200 Subject: [PATCH 117/128] Fix Russian and Ukrainian translations for Security component --- .../Resources/translations/security.ru.xlf | 30 +++++++++---------- .../Resources/translations/security.ua.xlf | 28 ++++++++--------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.ru.xlf b/src/Symfony/Component/Security/Resources/translations/security.ru.xlf index b6c8d064af..1964f95e09 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.ru.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.ru.xlf @@ -8,63 +8,63 @@ Authentication credentials could not be found. - Полномочия не найдены. + Аутентификационные данные не найдены. Authentication request could not be processed due to a system problem. - Запрос аутентификации не может быть обработан из-за проблем в системе. + Запрос аутентификации не может быть обработан в связи с проблемой в системе. Invalid credentials. - Недействительные полномочия. + Недействительные аутентификационные данные. Cookie has already been used by someone else. - Cookie уже используются кем-то другим. + Cookie уже был использован кем-то другим. Not privileged to request the resource. - Нет привилегий для запроса ресурса. + Отсутствуют права на запрос этого ресурса. Invalid CSRF token. - Недействительный CSRF token. + Недействительный токен CSRF. Digest nonce has expired. - Время дайджеста истекло. + Время действия одноразового ключа дайджеста истекло. No authentication provider found to support the authentication token. - Не найден провайдер аутентификации для поддержки токена аутентификации. + Не найден провайдер аутентификации, поддерживающий токен аутентификации. No session available, it either timed out or cookies are not enabled. - Сессия не найдена, в связи с таймаутом либо cookies не включены. + Сессия не найдена, ее время истекло, либо cookies не включены. No token could be found. - Token не найден. + Токен не найден. Username could not be found. - Username не найден. + Имя пользователя не найдено. Account has expired. - Время действия аккаунта истекло. + Время действия учетной записи истекло. Credentials have expired. - Время действия полномочий истекли. + Время действия аутентификационных данных истекло. Account is disabled. - Аккаунт отключен. + Учетная запись отключена. Account is locked. - Аккаунт заблокирован. + Учетная запись заблокирована. diff --git a/src/Symfony/Component/Security/Resources/translations/security.ua.xlf b/src/Symfony/Component/Security/Resources/translations/security.ua.xlf index 82b7834b14..7972121206 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.ua.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.ua.xlf @@ -4,43 +4,43 @@ An authentication exception occurred. - Помилка аутентифікації. + Помилка автентифікації. Authentication credentials could not be found. - Перевірка справжності облікових данних не знайдена. + Автентифікаційні дані не знайдено. Authentication request could not be processed due to a system problem. - Запит на аутентифікацію не може бути опрацьований через проблеми в системі. + Запит на автентифікацію не може бути опрацьовано у зв’язку з проблемою в системі. Invalid credentials. - Невірний логін або пароль. + Невірні автентифікаційні дані. Cookie has already been used by someone else. - Файли cookie вже були використані кимось іншим. + Хтось інший вже використав цей сookie. Not privileged to request the resource. - Недостатньо прав для доступу до ресурсу. + Відсутні права на запит цього ресурсу. Invalid CSRF token. - Невірний CSRF токен. + Невірний токен CSRF. Digest nonce has expired. - Закінчився строк дії криптографічного ключа (digest nonce). + Закінчився термін дії одноразового ключа дайджесту. No authentication provider found to support the authentication token. - Для підтримки токену не знайден провайдер аутентифікації. + Не знайдено провайдера автентифікації, що підтримує токен автентифікаціії. No session available, it either timed out or cookies are not enabled. - Сесія недоступна - тайм-аут або файли cookies вимкнені. + Сесія недоступна, її час вийшов, або cookies вимкнено. No token could be found. @@ -52,19 +52,19 @@ Account has expired. - Закінчився строк дії облікового запису. + Термін дії облікового запису вичерпано. Credentials have expired. - Строк дії облікових данних вичерпаний. + Термін дії автентифікаційних даних вичерпано. Account is disabled. - Обліковий запис відключений. + Обліковий запис відключено. Account is locked. - Обліковий запис заблокований. + Обліковий запис заблоковано. From b1c68815f58e32e4b8ea9a55ca2fe84fe0a0e6d9 Mon Sep 17 00:00:00 2001 From: Pascal Borreli Date: Fri, 11 Jan 2013 17:38:19 +0000 Subject: [PATCH 118/128] Fixed PHPDoc --- src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php | 2 +- .../FrameworkBundle/Templating/Helper/ActionsHelper.php | 2 +- .../Component/DependencyInjection/Dumper/PhpDumper.php | 5 +++-- src/Symfony/Component/Finder/Shell/Command.php | 1 + src/Symfony/Component/Routing/RequestContext.php | 1 + src/Symfony/Component/Security/Http/HttpUtils.php | 2 +- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php index 2e406fc1d9..cb18b5f643 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php @@ -26,7 +26,7 @@ class HttpKernelExtension extends \Twig_Extension /** * Constructor. * - * @param HttpContentRenderer $kernel A HttpContentRenderer instance + * @param HttpContentRenderer $renderer A HttpContentRenderer instance */ public function __construct(HttpContentRenderer $renderer) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php index abce1d10bf..f07adb2ce2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/ActionsHelper.php @@ -27,7 +27,7 @@ class ActionsHelper extends Helper /** * Constructor. * - * @param HttpContentRenderer $kernel A HttpContentRenderer instance + * @param HttpContentRenderer $renderer A HttpContentRenderer instance */ public function __construct(HttpContentRenderer $renderer) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 22aabf2745..2a29b01c90 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -952,8 +952,9 @@ EOF; /** * Checks if a service id has a reference * - * @param string $id - * @param array $arguments + * @param string $id + * @param array $arguments + * @param Boolean $deep * * @return Boolean */ diff --git a/src/Symfony/Component/Finder/Shell/Command.php b/src/Symfony/Component/Finder/Shell/Command.php index 0c4a3118cf..1a060c8cae 100644 --- a/src/Symfony/Component/Finder/Shell/Command.php +++ b/src/Symfony/Component/Finder/Shell/Command.php @@ -251,6 +251,7 @@ class Command * Insert a string or a Command instance before the bit at given position $index (index starts from 0). * * @param string|Command $bit + * @param integer $index * * @return Command The current Command instance */ diff --git a/src/Symfony/Component/Routing/RequestContext.php b/src/Symfony/Component/Routing/RequestContext.php index 0286e842de..132ecc743c 100644 --- a/src/Symfony/Component/Routing/RequestContext.php +++ b/src/Symfony/Component/Routing/RequestContext.php @@ -44,6 +44,7 @@ class RequestContext * @param string $scheme The HTTP scheme * @param integer $httpPort The HTTP port * @param integer $httpsPort The HTTPS port + * @param string $path The path * * @api */ diff --git a/src/Symfony/Component/Security/Http/HttpUtils.php b/src/Symfony/Component/Security/Http/HttpUtils.php index a3c6f61bf8..eb7894cd8b 100644 --- a/src/Symfony/Component/Security/Http/HttpUtils.php +++ b/src/Symfony/Component/Security/Http/HttpUtils.php @@ -35,7 +35,7 @@ class HttpUtils * Constructor. * * @param UrlGeneratorInterface $urlGenerator A UrlGeneratorInterface instance - * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher + * @param UrlMatcherInterface|RequestMatcherInterface $urlMatcher The Url or Request matcher */ public function __construct(UrlGeneratorInterface $urlGenerator = null, $urlMatcher = null) { From fb52d941f4ac6fe560dabf32696dd60b61bf58c1 Mon Sep 17 00:00:00 2001 From: Alex Olmos Date: Fri, 11 Jan 2013 19:16:45 +0100 Subject: [PATCH 119/128] Update src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf --- .../Security/Resources/translations/security.es_CA.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf b/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf index 3f106d8eb2..3fb8212a8f 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf @@ -36,7 +36,7 @@ No authentication provider found to support the authentication token. - No s'ha trobat un proveidor d'autenticació que suporti el token d'autenticació. + No s'ha trobat un proveïdor d'autenticació que suporti el token d'autenticació. No session available, it either timed out or cookies are not enabled. From eeceafa45c927d3d2261f888e6c4ba36bb21f3e9 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Fri, 11 Jan 2013 19:36:08 +0100 Subject: [PATCH 120/128] [Security] Renamed catalonian translation file --- .../translations/{security.es_CA.xlf => security.ca.xlf} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Symfony/Component/Security/Resources/translations/{security.es_CA.xlf => security.ca.xlf} (100%) diff --git a/src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf b/src/Symfony/Component/Security/Resources/translations/security.ca.xlf similarity index 100% rename from src/Symfony/Component/Security/Resources/translations/security.es_CA.xlf rename to src/Symfony/Component/Security/Resources/translations/security.ca.xlf From 67f7ed535808ae4679a0be21d03761257ad43de7 Mon Sep 17 00:00:00 2001 From: umpirsky Date: Fri, 11 Jan 2013 19:40:23 +0100 Subject: [PATCH 121/128] Added Serbian Cyrillic tanslation for security component --- .../translations/security.sr_Cyrl.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.sr_Cyrl.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.sr_Cyrl.xlf b/src/Symfony/Component/Security/Resources/translations/security.sr_Cyrl.xlf new file mode 100644 index 0000000000..35e4ddf29b --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.sr_Cyrl.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Изузетак при аутентификацији. + + + Authentication credentials could not be found. + Аутентификациони подаци нису пронађени. + + + Authentication request could not be processed due to a system problem. + Захтев за аутентификацију не може бити обрађен због системских проблема. + + + Invalid credentials. + Невалидни подаци за аутентификацију. + + + Cookie has already been used by someone else. + Колачић је већ искоришћен од стране неког другог. + + + Not privileged to request the resource. + Немате права приступа овом ресурсу. + + + Invalid CSRF token. + Невалидан CSRF токен. + + + Digest nonce has expired. + Време криптографског кључа је истекло. + + + No authentication provider found to support the authentication token. + Аутентификациони провајдер за подршку токена није пронађен. + + + No session available, it either timed out or cookies are not enabled. + Сесија није доступна, истекла је или су колачићи искључени. + + + No token could be found. + Токен не може бити пронађен. + + + Username could not be found. + Корисничко име не може бити пронађено. + + + Account has expired. + Налог је истекао. + + + Credentials have expired. + Подаци за аутентификацију су истекли. + + + Account is disabled. + Налог је онемогућен. + + + Account is locked. + Налог је закључан. + + + + From f58213867a98cef6cb9c362cf0a4d10f3a314c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20F=C3=A1si?= Date: Sat, 12 Jan 2013 21:56:00 +0100 Subject: [PATCH 122/128] [Security] fix Hungarian translation --- .../Component/Security/Resources/translations/security.hu.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.hu.xlf b/src/Symfony/Component/Security/Resources/translations/security.hu.xlf index bd4939e705..724397038c 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.hu.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.hu.xlf @@ -20,7 +20,7 @@ Cookie has already been used by someone else. - Ezt a sütit már valaki más használja. + Ezt a sütit valaki más már felhasználta. Not privileged to request the resource. From c1d5f16c877fd8c09b1779ceba967e82157ea423 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Sun, 13 Jan 2013 12:48:31 +0100 Subject: [PATCH 123/128] Update src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php Just a typo fix --- .../HttpKernel/Tests/EventListener/RouterProxyListenerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php index 32b750f9ce..b0e091d504 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterProxyListenerTest.php @@ -26,7 +26,7 @@ class RouterProxyListenerTest extends \PHPUnit_Framework_TestCase } } - public function testOnlyTrigerredOnProxyRoute() + public function testOnlyTriggeredOnProxyRoute() { $request = Request::create('http://example.com/foo?path=foo%3D=bar'); From 309067a8973db98f61d7141520f0d177fcb37414 Mon Sep 17 00:00:00 2001 From: rubenrua Date: Sun, 13 Jan 2013 20:31:40 +0100 Subject: [PATCH 124/128] Added Galician translation in security component --- .../Resources/translations/security.gl.xlf | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Symfony/Component/Security/Resources/translations/security.gl.xlf diff --git a/src/Symfony/Component/Security/Resources/translations/security.gl.xlf b/src/Symfony/Component/Security/Resources/translations/security.gl.xlf new file mode 100644 index 0000000000..ed6491f7ef --- /dev/null +++ b/src/Symfony/Component/Security/Resources/translations/security.gl.xlf @@ -0,0 +1,71 @@ + + + + + + An authentication exception occurred. + Ocorreu un erro de autenticación. + + + Authentication credentials could not be found. + Non se atoparon as credenciais de autenticación. + + + Authentication request could not be processed due to a system problem. + A solicitude de autenticación no puido ser procesada debido a un problema do sistema. + + + Invalid credentials. + Credenciais non válidas. + + + Cookie has already been used by someone else. + A cookie xa foi empregado por outro usuario. + + + Not privileged to request the resource. + Non ten privilexios para solicitar o recurso. + + + Invalid CSRF token. + Token CSRF non válido. + + + Digest nonce has expired. + O vector de inicialización (digest nonce) expirou. + + + No authentication provider found to support the authentication token. + Non se atopou un provedor de autenticación que soporte o token de autenticación. + + + No session available, it either timed out or cookies are not enabled. + Non hai ningunha sesión dispoñible, expirou ou as cookies non están habilitadas. + + + No token could be found. + Non se atopou ningún token. + + + Username could not be found. + Non se atopou o nome de usuario. + + + Account has expired. + A conta expirou. + + + Credentials have expired. + As credenciais expiraron. + + + Account is disabled. + A conta está deshabilitada. + + + Account is locked. + A conta está bloqueada. + + + + From a5a04b81f3a550fda80a54e7e4ffeef1b6bd0fa8 Mon Sep 17 00:00:00 2001 From: Emanuele Gaspari Date: Mon, 14 Jan 2013 09:21:46 +0100 Subject: [PATCH 125/128] fixed italian translation typo --- .../Component/Security/Resources/translations/security.it.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.it.xlf b/src/Symfony/Component/Security/Resources/translations/security.it.xlf index 25d82ef7c2..75d81cc8d9 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.it.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.it.xlf @@ -20,7 +20,7 @@ Cookie has already been used by someone else. - Il cookie è già stato usato da qualcun'altro. + Il cookie è già stato usato da qualcun altro. Not privileged to request the resource. From cd3d6de849e2a7de4aad2e65894892684bd4c1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Mon, 14 Jan 2013 10:10:39 +0100 Subject: [PATCH 126/128] [Security] Fixed typo in cs translation --- .../Component/Security/Resources/translations/security.cs.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Resources/translations/security.cs.xlf b/src/Symfony/Component/Security/Resources/translations/security.cs.xlf index 4757762b32..bd146c6804 100644 --- a/src/Symfony/Component/Security/Resources/translations/security.cs.xlf +++ b/src/Symfony/Component/Security/Resources/translations/security.cs.xlf @@ -12,7 +12,7 @@ Authentication request could not be processed due to a system problem. - Požadavek na ověření nemohl být zpracován kvôli systémové chybě. + Požadavek na ověření nemohl být zpracován kvůli systémové chybě. Invalid credentials. From a0ba4cf5377df818058241806bcd56371afecfe1 Mon Sep 17 00:00:00 2001 From: oscartv Date: Mon, 14 Jan 2013 14:48:41 +0100 Subject: [PATCH 127/128] Update src/Symfony/Component/Form/Resources/translations/validators.ca.xlf --- .../Component/Form/Resources/translations/validators.ca.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf index c33bbab8f0..3a2fa484f8 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf @@ -12,7 +12,7 @@ The CSRF token is invalid. Please try to resubmit the form. - El token CSRF no és vàlid. Per favor, provi d'enviar novament el formulari + El token CSRF no és vàlid. Per favor, provi d'enviar novament el formulari. From fb526a480938c97d561985a676165dd48235cd7e Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 18 Dec 2012 14:15:42 +0100 Subject: [PATCH 128/128] [FileProfilerStorage] optimize file reads --- .../Profiler/FileProfilerStorage.php | 53 ++++++++++--------- .../Profiler/FileProfilerStorageTest.php | 15 ++++++ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php index 41287c825a..25d0fdde16 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php +++ b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php @@ -61,17 +61,13 @@ class FileProfilerStorage implements ProfilerStorageInterface $result = array(); - while ($limit > 0) { + for (;$limit > 0; $limit--) { $line = $this->readLineFromFile($file); - if (false === $line) { + if (null === $line) { break; } - if ($line === '') { - continue; - } - list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent) = str_getcsv($line); $csvTime = (int) $csvTime; @@ -96,7 +92,6 @@ class FileProfilerStorage implements ProfilerStorageInterface 'time' => $csvTime, 'parent' => $csvParent, ); - --$limit; } fclose($file); @@ -213,44 +208,50 @@ class FileProfilerStorage implements ProfilerStorageInterface } /** - * Reads a line in the file, ending with the current position. + * Reads a line in the file, backward. * * This function automatically skips the empty lines and do not include the line return in result value. * * @param resource $file The file resource, with the pointer placed at the end of the line to read * - * @return mixed A string representing the line or FALSE if beginning of file is reached + * @return mixed A string representing the line or null if beginning of file is reached */ protected function readLineFromFile($file) { - if (ftell($file) === 0) { - return false; + $line = ''; + $position = ftell($file); + + if (0 === $position) { + return null; } - fseek($file, -1, SEEK_CUR); - $str = ''; + while(true) { + $chunkSize = min($position, 1024); + $position -= $chunkSize; + fseek($file, $position); - while (true) { - $char = fgetc($file); - - if ($char === "\n") { - // Leave the file with cursor before the line return - fseek($file, -1, SEEK_CUR); + if (0 === $chunkSize) { + // bof reached break; } - $str = $char.$str; + $buffer = fread($file, $chunkSize); - if (ftell($file) === 1) { - // All file is read, so we move cursor to the position 0 - fseek($file, -1, SEEK_CUR); - break; + if (false === ($upTo = strrpos($buffer, "\n"))) { + $line = $buffer . $line; + continue; } - fseek($file, -2, SEEK_CUR); + $position += $upTo; + $line = substr($buffer, $upTo + 1) . $line; + fseek($file, max(0, $position), SEEK_SET); + + if ('' !== $line) { + break; + } } - return $str === '' ? $this->readLineFromFile($file) : $str; + return '' === $line ? null : $line; } protected function createProfileFromData($token, $data, $parent = null) diff --git a/src/Symfony/Component/HttpKernel/Tests/Profiler/FileProfilerStorageTest.php b/src/Symfony/Component/HttpKernel/Tests/Profiler/FileProfilerStorageTest.php index ad225129d3..21e0bf3df9 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Profiler/FileProfilerStorageTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Profiler/FileProfilerStorageTest.php @@ -82,4 +82,19 @@ class FileProfilerStorageTest extends AbstractProfilerStorageTest } $this->assertFalse(fgetcsv($handle)); } + + public function testReadLineFromFile() + { + $r = new \ReflectionMethod(self::$storage, 'readLineFromFile'); + + $r->setAccessible(true); + + $h = tmpfile(); + + fwrite($h, "line1\n\n\nline2\n"); + fseek($h, 0, SEEK_END); + + $this->assertEquals("line2", $r->invoke(self::$storage, $h)); + $this->assertEquals("line1", $r->invoke(self::$storage, $h)); + } }