Merge branch '4.2'

* 4.2:
  [Routing] fix trailing slash redirections involving a trailing var
  [EventDispatcher] Revers event tracing order
  [Security] Prefer clone over unserialize(serialize()) for user refreshment
  [Console] OutputFormatter: move strtolower to createStyleFromString
  Adjust tests to work in the armhf architecture. Fixes #29281.
  Vietnamese translations improvement
  [Form] Fixed FormErrorIterator class phpdoc
  Renamed test controller from Controller to TestController so it doesn't show up in the IDE autocomplete.
  Don't use he in docs when its not needed
  EventSubscriberInterface isn't a man
  Fix undefined variable in cache ArrayTrait
  fixed public directory of web server and assets install when configured in composer.json
This commit is contained in:
Nicolas Grekas 2018-12-17 14:49:19 +01:00
commit 75eebcf7dc
37 changed files with 1380 additions and 1297 deletions

View File

@ -18,6 +18,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
@ -56,7 +57,7 @@ class AssetsInstallCommand extends Command
{
$this
->setDefinition(array(
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', 'public'),
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', null),
))
->addOption('symlink', null, InputOption::VALUE_NONE, 'Symlinks the assets instead of copying it')
->addOption('relative', null, InputOption::VALUE_NONE, 'Make relative symlinks')
@ -94,6 +95,10 @@ EOT
$kernel = $this->getApplication()->getKernel();
$targetArg = rtrim($input->getArgument('target'), '/');
if (!$targetArg) {
$targetArg = $this->getPublicDirectory($this->getContainer());
}
if (!is_dir($targetArg)) {
$targetArg = $kernel->getProjectDir().'/'.$targetArg;
@ -250,4 +255,27 @@ EOT
return self::METHOD_COPY;
}
private function getPublicDirectory(ContainerInterface $container)
{
$defaultPublicDir = 'public';
if (!$container->hasParameter('kernel.project_dir')) {
return $defaultPublicDir;
}
$composerFilePath = $container->getParameter('kernel.project_dir').'/composer.json';
if (!file_exists($composerFilePath)) {
return $defaultPublicDir;
}
$composerConfig = json_decode(file_get_contents($composerFilePath), true);
if (isset($composerConfig['extra']['public-dir'])) {
return $composerConfig['extra']['public-dir'];
}
return $defaultPublicDir;
}
}

View File

@ -27,8 +27,31 @@ class WebServerExtension extends Extension
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('webserver.xml');
$publicDirectory = $this->getPublicDirectory($container);
$container->getDefinition('web_server.command.server_run')->replaceArgument(0, $publicDirectory);
$container->getDefinition('web_server.command.server_start')->replaceArgument(0, $publicDirectory);
if (!class_exists(ConsoleFormatter::class)) {
$container->removeDefinition('web_server.command.server_log');
}
}
private function getPublicDirectory(ContainerBuilder $container)
{
$kernelProjectDir = $container->getParameter('kernel.project_dir');
$publicDir = 'public';
$composerFilePath = $kernelProjectDir.'/composer.json';
if (!file_exists($composerFilePath)) {
return $kernelProjectDir.'/'.$publicDir;
}
$composerConfig = json_decode(file_get_contents($composerFilePath), true);
if (isset($composerConfig['extra']['public-dir'])) {
$publicDir = $composerConfig['extra']['public-dir'];
}
return $kernelProjectDir.'/'.$publicDir;
}
}

View File

@ -21,8 +21,17 @@ class WebServerExtensionTest extends TestCase
public function testLoad()
{
$container = new ContainerBuilder();
$container->setParameter('kernel.project_dir', __DIR__);
(new WebServerExtension())->load(array(), $container);
$this->assertSame(
__DIR__.'/test',
$container->getDefinition('web_server.command.server_run')->getArgument(0)
);
$this->assertSame(
__DIR__.'/test',
$container->getDefinition('web_server.command.server_start')->getArgument(0)
);
$this->assertTrue($container->hasDefinition('web_server.command.server_run'));
$this->assertTrue($container->hasDefinition('web_server.command.server_start'));
$this->assertTrue($container->hasDefinition('web_server.command.server_stop'));

View File

@ -0,0 +1,6 @@
{
"name": "test-composer.json",
"extra": {
"public-dir": "test"
}
}

View File

@ -124,7 +124,7 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
return true;
}
if ($this->storeSerialized && null === $value = $this->freeze($value)) {
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;
}
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {

View File

@ -129,7 +129,7 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte
$expiry = 0 < $ttl ? microtime(true) + $ttl : PHP_INT_MAX;
foreach ($valuesArray as $key => $value) {
if ($this->storeSerialized && null === $value = $this->freeze($value)) {
if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) {
return false;
}
$this->values[$key] = $value;

View File

@ -113,7 +113,7 @@ trait ArrayTrait
}
}
private function freeze($value)
private function freeze($value, $key)
{
if (null === $value) {
return 'N;';

View File

@ -166,7 +166,7 @@ class OutputFormatter implements WrappableOutputFormatterInterface
if (!$open && !$tag) {
// </>
$this->styleStack->pop();
} elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
} elseif (false === $style = $this->createStyleFromString($tag)) {
$output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength);
} elseif ($open) {
$this->styleStack->push($style);
@ -210,15 +210,16 @@ class OutputFormatter implements WrappableOutputFormatterInterface
$style = new OutputFormatterStyle();
foreach ($matches as $match) {
array_shift($match);
$match[0] = strtolower($match[0]);
if ('fg' == $match[0]) {
$style->setForeground($match[1]);
$style->setForeground(strtolower($match[1]));
} elseif ('bg' == $match[0]) {
$style->setBackground($match[1]);
$style->setBackground(strtolower($match[1]));
} elseif ('href' === $match[0]) {
$style->setHref($match[1]);
} elseif ('options' === $match[0]) {
preg_match_all('([^,;]+)', $match[1], $options);
preg_match_all('([^,;]+)', strtolower($match[1]), $options);
$options = array_shift($options);
foreach ($options as $option) {
$style->setOption($option);

View File

@ -29,7 +29,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
protected $logger;
protected $stopwatch;
private $called;
private $callStack;
private $dispatcher;
private $wrappedListeners;
private $orphanedEvents;
@ -39,7 +39,6 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
$this->dispatcher = $dispatcher;
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->called = array();
$this->wrappedListeners = array();
$this->orphanedEvents = array();
}
@ -125,6 +124,10 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
*/
public function dispatch($eventName, Event $event = null)
{
if (null === $this->callStack) {
$this->callStack = new \SplObjectStorage();
}
if (null === $event) {
$event = new Event();
}
@ -160,11 +163,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
*/
public function getCalledListeners()
{
if (null === $this->callStack) {
return array();
}
$called = array();
foreach ($this->called as $eventName => $listeners) {
foreach ($listeners as $listener) {
$called[$eventName.'.'.$listener->getPretty()] = $listener->getInfo($eventName);
}
foreach ($this->callStack as $listener) {
list($eventName) = $this->callStack->getInfo();
$called[] = $listener->getInfo($eventName);
}
return $called;
@ -190,9 +197,9 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
foreach ($allListeners as $eventName => $listeners) {
foreach ($listeners as $listener) {
$called = false;
if (isset($this->called[$eventName])) {
foreach ($this->called[$eventName] as $l) {
if ($l->getWrappedListener() === $listener) {
if (null !== $this->callStack) {
foreach ($this->callStack as $calledListener) {
if ($calledListener->getWrappedListener() === $listener) {
$called = true;
break;
@ -204,12 +211,12 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
if (!$listener instanceof WrappedListener) {
$listener = new WrappedListener($listener, null, $this->stopwatch, $this);
}
$notCalled[$eventName.'.'.$listener->getPretty()] = $listener->getInfo($eventName);
$notCalled[] = $listener->getInfo($eventName);
}
}
}
uasort($notCalled, array($this, 'sortListenersByPriority'));
uasort($notCalled, array($this, 'sortNotCalledListeners'));
return $notCalled;
}
@ -221,7 +228,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
public function reset()
{
$this->called = array();
$this->callStack = array();
$this->orphanedEvents = array();
}
@ -272,6 +279,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
$this->wrappedListeners[$eventName][] = $wrappedListener;
$this->dispatcher->removeListener($eventName, $listener);
$this->dispatcher->addListener($eventName, $wrappedListener, $priority);
$this->callStack->attach($wrappedListener, array($eventName));
}
}
@ -300,8 +308,8 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
if (!isset($this->called[$eventName])) {
$this->called[$eventName] = new \SplObjectStorage();
}
$this->called[$eventName]->attach($listener);
} else {
$this->callStack->detach($listener);
}
if (null !== $this->logger && $skipped) {
@ -318,8 +326,12 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
}
}
private function sortListenersByPriority($a, $b)
private function sortNotCalledListeners(array $a, array $b)
{
if (0 !== $cmp = strcmp($a['event'], $b['event'])) {
return $cmp;
}
if (\is_int($a['priority']) && !\is_int($b['priority'])) {
return 1;
}

View File

@ -46,7 +46,7 @@ interface EventDispatcherInterface
/**
* Adds an event subscriber.
*
* The subscriber is asked for all the events he is
* The subscriber is asked for all the events it is
* interested in and added as a listener for these events.
*/
public function addSubscriber(EventSubscriberInterface $subscriber);

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\EventDispatcher;
/**
* An EventSubscriber knows himself what events he is interested in.
* An EventSubscriber knows itself what events it is interested in.
* If an EventSubscriber is added to an EventDispatcherInterface, the manager invokes
* {@link getSubscribedEvents} and registers the subscriber as a listener for all
* returned events.

View File

@ -110,17 +110,17 @@ class TraceableEventDispatcherTest extends TestCase
$tdispatcher->addListener('foo', function () {}, 5);
$listeners = $tdispatcher->getNotCalledListeners();
$this->assertArrayHasKey('stub', $listeners['foo.closure']);
unset($listeners['foo.closure']['stub']);
$this->assertArrayHasKey('stub', $listeners[0]);
unset($listeners[0]['stub']);
$this->assertEquals(array(), $tdispatcher->getCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'pretty' => 'closure', 'priority' => 5)), $listeners);
$this->assertEquals(array(array('event' => 'foo', 'pretty' => 'closure', 'priority' => 5)), $listeners);
$tdispatcher->dispatch('foo');
$listeners = $tdispatcher->getCalledListeners();
$this->assertArrayHasKey('stub', $listeners['foo.closure']);
unset($listeners['foo.closure']['stub']);
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'pretty' => 'closure', 'priority' => 5)), $listeners);
$this->assertArrayHasKey('stub', $listeners[0]);
unset($listeners[0]['stub']);
$this->assertEquals(array(array('event' => 'foo', 'pretty' => 'closure', 'priority' => 5)), $listeners);
$this->assertEquals(array(), $tdispatcher->getNotCalledListeners());
}
@ -133,10 +133,10 @@ class TraceableEventDispatcherTest extends TestCase
$tdispatcher->reset();
$listeners = $tdispatcher->getNotCalledListeners();
$this->assertArrayHasKey('stub', $listeners['foo.closure']);
unset($listeners['foo.closure']['stub']);
$this->assertArrayHasKey('stub', $listeners[0]);
unset($listeners[0]['stub']);
$this->assertEquals(array(), $tdispatcher->getCalledListeners());
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'pretty' => 'closure', 'priority' => 5)), $listeners);
$this->assertEquals(array(array('event' => 'foo', 'pretty' => 'closure', 'priority' => 5)), $listeners);
}
public function testGetCalledListenersNested()

View File

@ -378,7 +378,7 @@ class ChoiceType extends AbstractType
if ($options['multiple']) {
$choiceType = __NAMESPACE__.'\CheckboxType';
// The user can check 0 or more checkboxes. If required
// is true, he is required to check all of them.
// is true, they are required to check all of them.
$choiceOpts['required'] = false;
} else {
$choiceType = __NAMESPACE__.'\RadioType';

View File

@ -19,10 +19,9 @@ use Symfony\Component\Validator\ConstraintViolation;
/**
* Iterates over the errors of a form.
*
* Optionally, this class supports recursive iteration. In order to iterate
* recursively, set the constructor argument $deep to true. Now each element
* returned by the iterator is either an instance of {@link FormError} or of
* {@link FormErrorIterator}, in case the errors belong to a sub-form.
* This class supports recursive iteration. In order to iterate recursively,
* pass a structure of {@link FormError} and {@link FormErrorIterator} objects
* to the $errors constructor argument.
*
* You can also wrap the iterator into a {@link \RecursiveIteratorIterator} to
* flatten the recursive structure into a flat list of errors.

View File

@ -183,7 +183,7 @@ class HttpKernelTest extends TestCase
public function testHandleWhenTheControllerIsAnObjectWithInvoke()
{
$dispatcher = new EventDispatcher();
$kernel = $this->getHttpKernel($dispatcher, new Controller());
$kernel = $this->getHttpKernel($dispatcher, new TestController());
$this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
}
@ -199,7 +199,7 @@ class HttpKernelTest extends TestCase
public function testHandleWhenTheControllerIsAnArray()
{
$dispatcher = new EventDispatcher();
$kernel = $this->getHttpKernel($dispatcher, array(new Controller(), 'controller'));
$kernel = $this->getHttpKernel($dispatcher, array(new TestController(), 'controller'));
$this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
}
@ -207,7 +207,7 @@ class HttpKernelTest extends TestCase
public function testHandleWhenTheControllerIsAStaticArray()
{
$dispatcher = new EventDispatcher();
$kernel = $this->getHttpKernel($dispatcher, array('Symfony\Component\HttpKernel\Tests\Controller', 'staticcontroller'));
$kernel = $this->getHttpKernel($dispatcher, array('Symfony\Component\HttpKernel\Tests\TestController', 'staticcontroller'));
$this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request()));
}
@ -372,7 +372,7 @@ class HttpKernelTest extends TestCase
}
}
class Controller
class TestController
{
public function __invoke()
{

View File

@ -209,7 +209,7 @@ EOF;
foreach ($staticRoutes as $url => $routes) {
$code .= self::export($url)." => array(\n";
foreach ($routes as $name => list($route, $hasTrailingSlash)) {
$code .= $this->compileRoute($route, $name, !$route->compile()->getHostVariables() ? $route->getHost() : $route->compile()->getHostRegex() ?: null, $hasTrailingSlash, $conditions);
$code .= $this->compileRoute($route, $name, !$route->compile()->getHostVariables() ? $route->getHost() : $route->compile()->getHostRegex() ?: null, $hasTrailingSlash, false, $conditions);
}
$code .= "),\n";
}
@ -321,8 +321,9 @@ EOF;
if ($hasTrailingSlash = '/' !== $regex && '/' === $regex[-1]) {
$regex = substr($regex, 0, -1);
}
$hasTrailingVar = (bool) preg_match('#\{\w+\}/?$#', $route->getPath());
$tree->addRoute($regex, array($name, $regex, $state->vars, $route, $hasTrailingSlash));
$tree->addRoute($regex, array($name, $regex, $state->vars, $route, $hasTrailingSlash, $hasTrailingVar));
}
$code .= $this->compileStaticPrefixCollection($tree, $state, 0, $conditions);
@ -331,7 +332,7 @@ EOF;
$code .= "\n .')'";
$state->regex .= ')';
}
$rx = ")(?:/?)$}{$modifiers}";
$rx = ")/?$}{$modifiers}";
$code .= "\n .'{$rx}',";
$state->regex .= $rx;
$state->markTail = 0;
@ -377,12 +378,12 @@ EOF;
continue;
}
list($name, $regex, $vars, $route, $hasTrailingSlash) = $route;
list($name, $regex, $vars, $route, $hasTrailingSlash, $hasTrailingVar) = $route;
$compiledRoute = $route->compile();
$vars = array_merge($state->hostVars, $vars);
if ($compiledRoute->getRegex() === $prevRegex) {
$state->routes = substr_replace($state->routes, $this->compileRoute($route, $name, $vars, $hasTrailingSlash, $conditions), -3, 0);
$state->routes = substr_replace($state->routes, $this->compileRoute($route, $name, $vars, $hasTrailingSlash, $hasTrailingVar, $conditions), -3, 0);
continue;
}
@ -393,7 +394,7 @@ EOF;
$state->regex .= $rx;
$prevRegex = $compiledRoute->getRegex();
$state->routes .= sprintf("%s => array(\n%s),\n", $state->mark, $this->compileRoute($route, $name, $vars, $hasTrailingSlash, $conditions));
$state->routes .= sprintf("%s => array(\n%s),\n", $state->mark, $this->compileRoute($route, $name, $vars, $hasTrailingSlash, $hasTrailingVar, $conditions));
}
return $code;
@ -402,7 +403,7 @@ EOF;
/**
* Compiles a single Route to PHP code used to match it against the path info.
*/
private function compileRoute(Route $route, string $name, $vars, bool $hasTrailingSlash, array &$conditions): string
private function compileRoute(Route $route, string $name, $vars, bool $hasTrailingSlash, bool $hasTrailingVar, array &$conditions): string
{
$defaults = $route->getDefaults();
@ -419,12 +420,13 @@ EOF;
}
return sprintf(
" array(%s, %s, %s, %s, %s, %s),\n",
" array(%s, %s, %s, %s, %s, %s, %s),\n",
self::export(array('_route' => $name) + $defaults),
self::export($vars),
self::export(array_flip($route->getMethods()) ?: null),
self::export(array_flip($route->getSchemes()) ?: null),
self::export($hasTrailingSlash),
self::export($hasTrailingVar),
$condition
);
}

View File

@ -54,8 +54,8 @@ trait PhpMatcherTrait
} finally {
$this->context->setScheme($scheme);
}
} elseif ('/' !== $pathinfo) {
$pathinfo = '/' !== $pathinfo[-1] ? $pathinfo.'/' : substr($pathinfo, 0, -1);
} elseif ('/' !== $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/') {
$pathinfo = $trimmedPathinfo === $pathinfo ? $pathinfo.'/' : $trimmedPathinfo;
if ($ret = $this->doMatch($pathinfo, $allow, $allowSchemes)) {
return $this->redirect($pathinfo, $ret['_route']) + $ret;
}
@ -67,13 +67,13 @@ trait PhpMatcherTrait
throw new ResourceNotFoundException();
}
private function doMatch(string $rawPathinfo, array &$allow = array(), array &$allowSchemes = array()): array
private function doMatch(string $pathinfo, array &$allow = array(), array &$allowSchemes = array()): array
{
$allow = $allowSchemes = array();
$pathinfo = rawurldecode($rawPathinfo) ?: '/';
$pathinfo = rawurldecode($pathinfo) ?: '/';
$trimmedPathinfo = rtrim($pathinfo, '/') ?: '/';
$context = $this->context;
$requestMethod = $canonicalMethod = $context->getMethod();
$trimmedPathinfo = '/' !== $pathinfo && '/' === $pathinfo[-1] ? substr($pathinfo, 0, -1) : $pathinfo;
if ($this->matchHost) {
$host = strtolower($context->getHost());
@ -82,17 +82,17 @@ trait PhpMatcherTrait
if ('HEAD' === $requestMethod) {
$canonicalMethod = 'GET';
}
$supportsRedirections = 'GET' === $canonicalMethod && $this instanceof RedirectableUrlMatcherInterface;
foreach ($this->staticRoutes[$trimmedPathinfo] ?? array() as list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash, $condition)) {
foreach ($this->staticRoutes[$trimmedPathinfo] ?? array() as list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash, , $condition)) {
if ($condition && !($this->checkCondition)($condition, $context, 0 < $condition ? $request ?? $request = $this->request ?: $this->createRequest($pathinfo) : null)) {
continue;
}
if ('/' === $pathinfo || $hasTrailingSlash === ('/' === $pathinfo[-1])) {
// no-op
} elseif ($this instanceof RedirectableUrlMatcherInterface && (!$requiredMethods || isset($requiredMethods['GET'])) && 'GET' === $canonicalMethod) {
return $allow = $allowSchemes = array();
} else {
if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
return $allow = $allowSchemes = array();
}
continue;
}
@ -125,23 +125,24 @@ trait PhpMatcherTrait
foreach ($this->regexpList as $offset => $regex) {
while (preg_match($regex, $matchedPathinfo, $matches)) {
foreach ($this->dynamicRoutes[$m = (int) $matches['MARK']] as list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash, $condition)) {
foreach ($this->dynamicRoutes[$m = (int) $matches['MARK']] as list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash, $hasTrailingVar, $condition)) {
if ($condition && !($this->checkCondition)($condition, $context, 0 < $condition ? $request ?? $request = $this->request ?: $this->createRequest($pathinfo) : null)) {
continue;
}
if ('/' !== $pathinfo) {
if ('/' === $pathinfo[-1]) {
if (preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) {
$matches = $n;
} else {
$hasTrailingSlash = true;
}
if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar) {
// no-op
} elseif (preg_match($regex, $this->matchHost ? $host.'.'.$trimmedPathinfo : $trimmedPathinfo, $n) && $m === (int) $n['MARK']) {
$matches = $n;
} else {
$hasTrailingSlash = true;
}
if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
if ($supportsRedirections && (!$requiredMethods || isset($requiredMethods['GET']))) {
return $allow = $allowSchemes = array();
}
if ($hasTrailingSlash !== ('/' === $pathinfo[-1])) {
if ($this instanceof RedirectableUrlMatcherInterface && (!$requiredMethods || isset($requiredMethods['GET'])) && 'GET' === $canonicalMethod) {
return $allow = $allowSchemes = array();
}
if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar) {
continue;
}
}

View File

@ -44,11 +44,11 @@ abstract class RedirectableUrlMatcher extends UrlMatcher implements Redirectable
} finally {
$this->context->setScheme($scheme);
}
} elseif ('/' === $pathinfo) {
} elseif ('/' === $trimmedPathinfo = rtrim($pathinfo, '/') ?: '/') {
throw $e;
} else {
try {
$pathinfo = '/' !== $pathinfo[-1] ? $pathinfo.'/' : substr($pathinfo, 0, -1);
$pathinfo = $trimmedPathinfo === $pathinfo ? $pathinfo.'/' : $trimmedPathinfo;
$ret = parent::match($pathinfo);
return $this->redirect($pathinfo, $ret['_route'] ?? null) + $ret;

View File

@ -84,7 +84,7 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
{
$this->allow = $this->allowSchemes = array();
if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) {
if ($ret = $this->matchCollection(rawurldecode($pathinfo) ?: '/', $this->routes)) {
return $ret;
}
@ -134,49 +134,41 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
if ('HEAD' === $method = $this->context->getMethod()) {
$method = 'GET';
}
$supportsTrailingSlash = '/' !== $pathinfo && '' !== $pathinfo && $this instanceof RedirectableUrlMatcherInterface;
$supportsTrailingSlash = 'GET' === $method && $this instanceof RedirectableUrlMatcherInterface;
$trimmedPathinfo = rtrim($pathinfo, '/') ?: '/';
foreach ($routes as $name => $route) {
$compiledRoute = $route->compile();
$staticPrefix = $compiledRoute->getStaticPrefix();
$staticPrefix = rtrim($compiledRoute->getStaticPrefix(), '/');
$requiredMethods = $route->getMethods();
// check the static prefix of the URL first. Only use the more expensive preg_match when it matches
if ('' === $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) {
// no-op
} elseif (!$supportsTrailingSlash || ($requiredMethods && !\in_array('GET', $requiredMethods)) || 'GET' !== $method) {
continue;
} elseif ('/' === $staticPrefix[-1] && substr($staticPrefix, 0, -1) === $pathinfo) {
return $this->allow = $this->allowSchemes = array();
} elseif ('/' === $pathinfo[-1] && substr($pathinfo, 0, -1) === $staticPrefix) {
return $this->allow = $this->allowSchemes = array();
} else {
if ('' !== $staticPrefix && 0 !== strpos($trimmedPathinfo, $staticPrefix)) {
continue;
}
$regex = $compiledRoute->getRegex();
if ($supportsTrailingSlash) {
$pos = strrpos($regex, '$');
$hasTrailingSlash = '/' === $regex[$pos - 1];
$regex = substr_replace($regex, '/?$', $pos - $hasTrailingSlash, 1 + $hasTrailingSlash);
}
$pos = strrpos($regex, '$');
$hasTrailingSlash = '/' === $regex[$pos - 1];
$regex = substr_replace($regex, '/?$', $pos - $hasTrailingSlash, 1 + $hasTrailingSlash);
if (!preg_match($regex, $pathinfo, $matches)) {
continue;
}
if ($supportsTrailingSlash) {
if ('/' === $pathinfo[-1]) {
if (preg_match($regex, substr($pathinfo, 0, -1), $m)) {
$matches = $m;
} else {
$hasTrailingSlash = true;
}
if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar = preg_match('#\{\w+\}/?$#', $route->getPath())) {
// no-op
} elseif (preg_match($regex, $trimmedPathinfo, $m)) {
$matches = $m;
} else {
$hasTrailingSlash = true;
}
if ('/' !== $pathinfo && $hasTrailingSlash === ($trimmedPathinfo === $pathinfo)) {
if ($supportsTrailingSlash && (!$requiredMethods || \in_array('GET', $requiredMethods))) {
return $this->allow = $this->allowSchemes = array();
}
if ($hasTrailingSlash !== ('/' === $pathinfo[-1])) {
if ((!$requiredMethods || \in_array('GET', $requiredMethods)) && 'GET' === $method) {
return $this->allow = $this->allowSchemes = array();
}
if ($trimmedPathinfo === $pathinfo || !$hasTrailingVar) {
continue;
}
}

View File

@ -16,23 +16,23 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
$this->context = $context;
$this->matchHost = true;
$this->staticRoutes = array(
'/test/baz' => array(array(array('_route' => 'baz'), null, null, null, false, null)),
'/test/baz.html' => array(array(array('_route' => 'baz2'), null, null, null, false, null)),
'/test/baz3' => array(array(array('_route' => 'baz3'), null, null, null, true, null)),
'/foofoo' => array(array(array('_route' => 'foofoo', 'def' => 'test'), null, null, null, false, null)),
'/spa ce' => array(array(array('_route' => 'space'), null, null, null, false, null)),
'/multi/new' => array(array(array('_route' => 'overridden2'), null, null, null, false, null)),
'/multi/hey' => array(array(array('_route' => 'hey'), null, null, null, true, null)),
'/ababa' => array(array(array('_route' => 'ababa'), null, null, null, false, null)),
'/route1' => array(array(array('_route' => 'route1'), 'a.example.com', null, null, false, null)),
'/c2/route2' => array(array(array('_route' => 'route2'), 'a.example.com', null, null, false, null)),
'/route4' => array(array(array('_route' => 'route4'), 'a.example.com', null, null, false, null)),
'/c2/route3' => array(array(array('_route' => 'route3'), 'b.example.com', null, null, false, null)),
'/route5' => array(array(array('_route' => 'route5'), 'c.example.com', null, null, false, null)),
'/route6' => array(array(array('_route' => 'route6'), null, null, null, false, null)),
'/route11' => array(array(array('_route' => 'route11'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, null)),
'/route12' => array(array(array('_route' => 'route12', 'var1' => 'val'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, null)),
'/route17' => array(array(array('_route' => 'route17'), null, null, null, false, null)),
'/test/baz' => array(array(array('_route' => 'baz'), null, null, null, false, false, null)),
'/test/baz.html' => array(array(array('_route' => 'baz2'), null, null, null, false, false, null)),
'/test/baz3' => array(array(array('_route' => 'baz3'), null, null, null, true, false, null)),
'/foofoo' => array(array(array('_route' => 'foofoo', 'def' => 'test'), null, null, null, false, false, null)),
'/spa ce' => array(array(array('_route' => 'space'), null, null, null, false, false, null)),
'/multi/new' => array(array(array('_route' => 'overridden2'), null, null, null, false, false, null)),
'/multi/hey' => array(array(array('_route' => 'hey'), null, null, null, true, false, null)),
'/ababa' => array(array(array('_route' => 'ababa'), null, null, null, false, false, null)),
'/route1' => array(array(array('_route' => 'route1'), 'a.example.com', null, null, false, false, null)),
'/c2/route2' => array(array(array('_route' => 'route2'), 'a.example.com', null, null, false, false, null)),
'/route4' => array(array(array('_route' => 'route4'), 'a.example.com', null, null, false, false, null)),
'/c2/route3' => array(array(array('_route' => 'route3'), 'b.example.com', null, null, false, false, null)),
'/route5' => array(array(array('_route' => 'route5'), 'c.example.com', null, null, false, false, null)),
'/route6' => array(array(array('_route' => 'route6'), null, null, null, false, false, null)),
'/route11' => array(array(array('_route' => 'route11'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, false, null)),
'/route12' => array(array(array('_route' => 'route12', 'var1' => 'val'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, false, null)),
'/route17' => array(array(array('_route' => 'route17'), null, null, null, false, false, null)),
);
$this->regexpList = array(
0 => '{^(?'
@ -80,34 +80,34 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
.')'
.')'
.')'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
47 => array(array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null, false, null)),
70 => array(array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null, false, null)),
90 => array(array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null, false, null)),
47 => array(array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null, false, true, null)),
70 => array(array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null, false, true, null)),
90 => array(array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null, false, true, null)),
115 => array(
array(array('_route' => 'baz4'), array('foo'), null, null, true, null),
array(array('_route' => 'baz5'), array('foo'), array('POST' => 0), null, true, null),
array(array('_route' => 'baz.baz6'), array('foo'), array('PUT' => 0), null, true, null),
array(array('_route' => 'baz4'), array('foo'), null, null, true, true, null),
array(array('_route' => 'baz5'), array('foo'), array('POST' => 0), null, true, true, null),
array(array('_route' => 'baz.baz6'), array('foo'), array('PUT' => 0), null, true, true, null),
),
131 => array(array(array('_route' => 'quoter'), array('quoter'), null, null, false, null)),
160 => array(array(array('_route' => 'foo1'), array('foo'), array('PUT' => 0), null, false, null)),
168 => array(array(array('_route' => 'bar1'), array('bar'), null, null, false, null)),
181 => array(array(array('_route' => 'overridden'), array('var'), null, null, false, null)),
204 => array(array(array('_route' => 'foo2'), array('foo1'), null, null, false, null)),
212 => array(array(array('_route' => 'bar2'), array('bar1'), null, null, false, null)),
248 => array(array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null, false, null)),
279 => array(array(array('_route' => 'foo3'), array('_locale', 'foo'), null, null, false, null)),
287 => array(array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null, false, null)),
309 => array(array(array('_route' => 'foo4'), array('foo'), null, null, false, null)),
371 => array(array(array('_route' => 'route13'), array('var1', 'name'), null, null, false, null)),
389 => array(array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null, false, null)),
441 => array(array(array('_route' => 'route15'), array('name'), null, null, false, null)),
489 => array(array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null, false, null)),
510 => array(array(array('_route' => 'a'), array(), null, null, false, null)),
531 => array(array(array('_route' => 'b'), array('var'), null, null, false, null)),
549 => array(array(array('_route' => 'c'), array('var'), null, null, false, null)),
131 => array(array(array('_route' => 'quoter'), array('quoter'), null, null, false, true, null)),
160 => array(array(array('_route' => 'foo1'), array('foo'), array('PUT' => 0), null, false, true, null)),
168 => array(array(array('_route' => 'bar1'), array('bar'), null, null, false, true, null)),
181 => array(array(array('_route' => 'overridden'), array('var'), null, null, false, true, null)),
204 => array(array(array('_route' => 'foo2'), array('foo1'), null, null, false, true, null)),
212 => array(array(array('_route' => 'bar2'), array('bar1'), null, null, false, true, null)),
248 => array(array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null, false, true, null)),
279 => array(array(array('_route' => 'foo3'), array('_locale', 'foo'), null, null, false, true, null)),
287 => array(array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null, false, true, null)),
309 => array(array(array('_route' => 'foo4'), array('foo'), null, null, false, true, null)),
371 => array(array(array('_route' => 'route13'), array('var1', 'name'), null, null, false, true, null)),
389 => array(array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null, false, true, null)),
441 => array(array(array('_route' => 'route15'), array('name'), null, null, false, true, null)),
489 => array(array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null, false, true, null)),
510 => array(array(array('_route' => 'a'), array(), null, null, false, false, null)),
531 => array(array(array('_route' => 'b'), array('var'), null, null, false, true, null)),
549 => array(array(array('_route' => 'c'), array('var'), null, null, false, true, null)),
);
}
}

View File

@ -44,23 +44,23 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
.')'
.')'
.'|/(en|fr)?(*:264)'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
32 => array(array(array('_route' => 'a', '_locale' => 'en'), array('_locale'), null, null, true, null)),
46 => array(array(array('_route' => 'b', '_locale' => 'en'), array('_locale'), null, null, false, null)),
58 => array(array(array('_route' => 'c', '_locale' => 'en'), array('_locale', 'id'), null, null, false, null)),
75 => array(array(array('_route' => 'd', '_locale' => 'en'), array('_locale', 'id'), null, null, false, null)),
94 => array(array(array('_route' => 'e', '_locale' => 'en'), array('_locale', 'id'), null, null, false, null)),
110 => array(array(array('_route' => 'f', '_locale' => 'en'), array('_locale'), null, null, true, null)),
130 => array(array(array('_route' => 'g', '_locale' => 'en'), array('_locale'), null, null, false, null)),
154 => array(array(array('_route' => 'h', '_locale' => 'en'), array('_locale', 'page'), null, null, false, null)),
175 => array(array(array('_route' => 'i', '_locale' => 'en'), array('_locale', 'page'), null, null, false, null)),
202 => array(array(array('_route' => 'j', '_locale' => 'en'), array('_locale', 'id'), null, null, false, null)),
216 => array(array(array('_route' => 'k', '_locale' => 'en'), array('_locale'), null, null, false, null)),
234 => array(array(array('_route' => 'l', '_locale' => 'en'), array('_locale'), null, null, false, null)),
245 => array(array(array('_route' => 'm', '_locale' => 'en'), array('_locale'), null, null, false, null)),
264 => array(array(array('_route' => 'n', '_locale' => 'en'), array('_locale'), null, null, false, null)),
32 => array(array(array('_route' => 'a', '_locale' => 'en'), array('_locale'), null, null, true, false, null)),
46 => array(array(array('_route' => 'b', '_locale' => 'en'), array('_locale'), null, null, false, false, null)),
58 => array(array(array('_route' => 'c', '_locale' => 'en'), array('_locale', 'id'), null, null, false, true, null)),
75 => array(array(array('_route' => 'd', '_locale' => 'en'), array('_locale', 'id'), null, null, false, false, null)),
94 => array(array(array('_route' => 'e', '_locale' => 'en'), array('_locale', 'id'), null, null, false, false, null)),
110 => array(array(array('_route' => 'f', '_locale' => 'en'), array('_locale'), null, null, true, false, null)),
130 => array(array(array('_route' => 'g', '_locale' => 'en'), array('_locale'), null, null, false, false, null)),
154 => array(array(array('_route' => 'h', '_locale' => 'en'), array('_locale', 'page'), null, null, false, true, null)),
175 => array(array(array('_route' => 'i', '_locale' => 'en'), array('_locale', 'page'), null, null, false, true, null)),
202 => array(array(array('_route' => 'j', '_locale' => 'en'), array('_locale', 'id'), null, null, false, false, null)),
216 => array(array(array('_route' => 'k', '_locale' => 'en'), array('_locale'), null, null, false, false, null)),
234 => array(array(array('_route' => 'l', '_locale' => 'en'), array('_locale'), null, null, false, false, null)),
245 => array(array(array('_route' => 'm', '_locale' => 'en'), array('_locale'), null, null, false, false, null)),
264 => array(array(array('_route' => 'n', '_locale' => 'en'), array('_locale'), null, null, false, true, null)),
);
}
}

View File

@ -32,15 +32,15 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
.')'
.')'
.')'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
27 => array(array(array('_route' => 'r1'), array('foo'), null, null, false, null)),
38 => array(array(array('_route' => 'r10'), array('foo'), null, null, false, null)),
46 => array(array(array('_route' => 'r100'), array('foo'), null, null, false, null)),
59 => array(array(array('_route' => 'r2'), array('foo'), null, null, false, null)),
70 => array(array(array('_route' => 'r20'), array('foo'), null, null, false, null)),
78 => array(array(array('_route' => 'r200'), array('foo'), null, null, false, null)),
27 => array(array(array('_route' => 'r1'), array('foo'), null, null, false, false, null)),
38 => array(array(array('_route' => 'r10'), array('foo'), null, null, false, false, null)),
46 => array(array(array('_route' => 'r100'), array('foo'), null, null, false, false, null)),
59 => array(array(array('_route' => 'r2'), array('foo'), null, null, false, false, null)),
70 => array(array(array('_route' => 'r20'), array('foo'), null, null, false, false, null)),
78 => array(array(array('_route' => 'r200'), array('foo'), null, null, false, false, null)),
);
}
}

View File

@ -22,12 +22,12 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
.'|(*:56)'
.')'
.')'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
56 => array(
array(array('_route' => 'r1'), array('foo', 'foo'), null, null, false, null),
array(array('_route' => 'r2'), array('foo', 'foo'), null, null, false, null),
array(array('_route' => 'r1'), array('foo', 'foo'), null, null, false, true, null),
array(array('_route' => 'r2'), array('foo', 'foo'), null, null, false, true, null),
),
);
}

View File

@ -16,25 +16,25 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
$this->context = $context;
$this->matchHost = true;
$this->staticRoutes = array(
'/test/baz' => array(array(array('_route' => 'baz'), null, null, null, false, null)),
'/test/baz.html' => array(array(array('_route' => 'baz2'), null, null, null, false, null)),
'/test/baz3' => array(array(array('_route' => 'baz3'), null, null, null, true, null)),
'/foofoo' => array(array(array('_route' => 'foofoo', 'def' => 'test'), null, null, null, false, null)),
'/spa ce' => array(array(array('_route' => 'space'), null, null, null, false, null)),
'/multi/new' => array(array(array('_route' => 'overridden2'), null, null, null, false, null)),
'/multi/hey' => array(array(array('_route' => 'hey'), null, null, null, true, null)),
'/ababa' => array(array(array('_route' => 'ababa'), null, null, null, false, null)),
'/route1' => array(array(array('_route' => 'route1'), 'a.example.com', null, null, false, null)),
'/c2/route2' => array(array(array('_route' => 'route2'), 'a.example.com', null, null, false, null)),
'/route4' => array(array(array('_route' => 'route4'), 'a.example.com', null, null, false, null)),
'/c2/route3' => array(array(array('_route' => 'route3'), 'b.example.com', null, null, false, null)),
'/route5' => array(array(array('_route' => 'route5'), 'c.example.com', null, null, false, null)),
'/route6' => array(array(array('_route' => 'route6'), null, null, null, false, null)),
'/route11' => array(array(array('_route' => 'route11'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, null)),
'/route12' => array(array(array('_route' => 'route12', 'var1' => 'val'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, null)),
'/route17' => array(array(array('_route' => 'route17'), null, null, null, false, null)),
'/secure' => array(array(array('_route' => 'secure'), null, null, array('https' => 0), false, null)),
'/nonsecure' => array(array(array('_route' => 'nonsecure'), null, null, array('http' => 0), false, null)),
'/test/baz' => array(array(array('_route' => 'baz'), null, null, null, false, false, null)),
'/test/baz.html' => array(array(array('_route' => 'baz2'), null, null, null, false, false, null)),
'/test/baz3' => array(array(array('_route' => 'baz3'), null, null, null, true, false, null)),
'/foofoo' => array(array(array('_route' => 'foofoo', 'def' => 'test'), null, null, null, false, false, null)),
'/spa ce' => array(array(array('_route' => 'space'), null, null, null, false, false, null)),
'/multi/new' => array(array(array('_route' => 'overridden2'), null, null, null, false, false, null)),
'/multi/hey' => array(array(array('_route' => 'hey'), null, null, null, true, false, null)),
'/ababa' => array(array(array('_route' => 'ababa'), null, null, null, false, false, null)),
'/route1' => array(array(array('_route' => 'route1'), 'a.example.com', null, null, false, false, null)),
'/c2/route2' => array(array(array('_route' => 'route2'), 'a.example.com', null, null, false, false, null)),
'/route4' => array(array(array('_route' => 'route4'), 'a.example.com', null, null, false, false, null)),
'/c2/route3' => array(array(array('_route' => 'route3'), 'b.example.com', null, null, false, false, null)),
'/route5' => array(array(array('_route' => 'route5'), 'c.example.com', null, null, false, false, null)),
'/route6' => array(array(array('_route' => 'route6'), null, null, null, false, false, null)),
'/route11' => array(array(array('_route' => 'route11'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, false, null)),
'/route12' => array(array(array('_route' => 'route12', 'var1' => 'val'), '#^(?P<var1>[^\\.]++)\\.example\\.com$#sDi', null, null, false, false, null)),
'/route17' => array(array(array('_route' => 'route17'), null, null, null, false, false, null)),
'/secure' => array(array(array('_route' => 'secure'), null, null, array('https' => 0), false, false, null)),
'/nonsecure' => array(array(array('_route' => 'nonsecure'), null, null, array('http' => 0), false, false, null)),
);
$this->regexpList = array(
0 => '{^(?'
@ -82,34 +82,34 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
.')'
.')'
.')'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
47 => array(array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null, false, null)),
70 => array(array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null, false, null)),
90 => array(array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null, false, null)),
47 => array(array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null, false, true, null)),
70 => array(array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null, false, true, null)),
90 => array(array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null, false, true, null)),
115 => array(
array(array('_route' => 'baz4'), array('foo'), null, null, true, null),
array(array('_route' => 'baz5'), array('foo'), array('POST' => 0), null, true, null),
array(array('_route' => 'baz.baz6'), array('foo'), array('PUT' => 0), null, true, null),
array(array('_route' => 'baz4'), array('foo'), null, null, true, true, null),
array(array('_route' => 'baz5'), array('foo'), array('POST' => 0), null, true, true, null),
array(array('_route' => 'baz.baz6'), array('foo'), array('PUT' => 0), null, true, true, null),
),
131 => array(array(array('_route' => 'quoter'), array('quoter'), null, null, false, null)),
160 => array(array(array('_route' => 'foo1'), array('foo'), array('PUT' => 0), null, false, null)),
168 => array(array(array('_route' => 'bar1'), array('bar'), null, null, false, null)),
181 => array(array(array('_route' => 'overridden'), array('var'), null, null, false, null)),
204 => array(array(array('_route' => 'foo2'), array('foo1'), null, null, false, null)),
212 => array(array(array('_route' => 'bar2'), array('bar1'), null, null, false, null)),
248 => array(array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null, false, null)),
279 => array(array(array('_route' => 'foo3'), array('_locale', 'foo'), null, null, false, null)),
287 => array(array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null, false, null)),
309 => array(array(array('_route' => 'foo4'), array('foo'), null, null, false, null)),
371 => array(array(array('_route' => 'route13'), array('var1', 'name'), null, null, false, null)),
389 => array(array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null, false, null)),
441 => array(array(array('_route' => 'route15'), array('name'), null, null, false, null)),
489 => array(array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null, false, null)),
510 => array(array(array('_route' => 'a'), array(), null, null, false, null)),
531 => array(array(array('_route' => 'b'), array('var'), null, null, false, null)),
549 => array(array(array('_route' => 'c'), array('var'), null, null, false, null)),
131 => array(array(array('_route' => 'quoter'), array('quoter'), null, null, false, true, null)),
160 => array(array(array('_route' => 'foo1'), array('foo'), array('PUT' => 0), null, false, true, null)),
168 => array(array(array('_route' => 'bar1'), array('bar'), null, null, false, true, null)),
181 => array(array(array('_route' => 'overridden'), array('var'), null, null, false, true, null)),
204 => array(array(array('_route' => 'foo2'), array('foo1'), null, null, false, true, null)),
212 => array(array(array('_route' => 'bar2'), array('bar1'), null, null, false, true, null)),
248 => array(array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null, false, true, null)),
279 => array(array(array('_route' => 'foo3'), array('_locale', 'foo'), null, null, false, true, null)),
287 => array(array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null, false, true, null)),
309 => array(array(array('_route' => 'foo4'), array('foo'), null, null, false, true, null)),
371 => array(array(array('_route' => 'route13'), array('var1', 'name'), null, null, false, true, null)),
389 => array(array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null, false, true, null)),
441 => array(array(array('_route' => 'route15'), array('name'), null, null, false, true, null)),
489 => array(array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null, false, true, null)),
510 => array(array(array('_route' => 'a'), array(), null, null, false, false, null)),
531 => array(array(array('_route' => 'b'), array('var'), null, null, false, true, null)),
549 => array(array(array('_route' => 'c'), array('var'), null, null, false, true, null)),
);
}
}

View File

@ -15,16 +15,16 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
{
$this->context = $context;
$this->staticRoutes = array(
'/rootprefix/test' => array(array(array('_route' => 'static'), null, null, null, false, null)),
'/with-condition' => array(array(array('_route' => 'with-condition'), null, null, null, false, -1)),
'/rootprefix/test' => array(array(array('_route' => 'static'), null, null, null, false, false, null)),
'/with-condition' => array(array(array('_route' => 'with-condition'), null, null, null, false, false, -1)),
);
$this->regexpList = array(
0 => '{^(?'
.'|/rootprefix/([^/]++)(*:27)'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
27 => array(array(array('_route' => 'dynamic'), array('var'), null, null, false, null)),
27 => array(array(array('_route' => 'dynamic'), array('var'), null, null, false, true, null)),
);
$this->checkCondition = static function ($condition, $context, $request) {
switch ($condition) {

View File

@ -15,13 +15,13 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
{
$this->context = $context;
$this->staticRoutes = array(
'/just_head' => array(array(array('_route' => 'just_head'), null, array('HEAD' => 0), null, false, null)),
'/head_and_get' => array(array(array('_route' => 'head_and_get'), null, array('HEAD' => 0, 'GET' => 1), null, false, null)),
'/get_and_head' => array(array(array('_route' => 'get_and_head'), null, array('GET' => 0, 'HEAD' => 1), null, false, null)),
'/post_and_head' => array(array(array('_route' => 'post_and_head'), null, array('POST' => 0, 'HEAD' => 1), null, false, null)),
'/just_head' => array(array(array('_route' => 'just_head'), null, array('HEAD' => 0), null, false, false, null)),
'/head_and_get' => array(array(array('_route' => 'head_and_get'), null, array('HEAD' => 0, 'GET' => 1), null, false, false, null)),
'/get_and_head' => array(array(array('_route' => 'get_and_head'), null, array('GET' => 0, 'HEAD' => 1), null, false, false, null)),
'/post_and_head' => array(array(array('_route' => 'post_and_head'), null, array('POST' => 0, 'HEAD' => 1), null, false, false, null)),
'/put_and_post' => array(
array(array('_route' => 'put_and_post'), null, array('PUT' => 0, 'POST' => 1), null, false, null),
array(array('_route' => 'put_and_get_and_head'), null, array('PUT' => 0, 'GET' => 1, 'HEAD' => 2), null, false, null),
array(array('_route' => 'put_and_post'), null, array('PUT' => 0, 'POST' => 1), null, false, false, null),
array(array('_route' => 'put_and_get_and_head'), null, array('PUT' => 0, 'GET' => 1, 'HEAD' => 2), null, false, false, null),
),
);
}

View File

@ -15,28 +15,28 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
{
$this->context = $context;
$this->staticRoutes = array(
'/a/11' => array(array(array('_route' => 'a_first'), null, null, null, false, null)),
'/a/22' => array(array(array('_route' => 'a_second'), null, null, null, false, null)),
'/a/333' => array(array(array('_route' => 'a_third'), null, null, null, false, null)),
'/a/44' => array(array(array('_route' => 'a_fourth'), null, null, null, true, null)),
'/a/55' => array(array(array('_route' => 'a_fifth'), null, null, null, true, null)),
'/a/66' => array(array(array('_route' => 'a_sixth'), null, null, null, true, null)),
'/nested/group/a' => array(array(array('_route' => 'nested_a'), null, null, null, true, null)),
'/nested/group/b' => array(array(array('_route' => 'nested_b'), null, null, null, true, null)),
'/nested/group/c' => array(array(array('_route' => 'nested_c'), null, null, null, true, null)),
'/slashed/group' => array(array(array('_route' => 'slashed_a'), null, null, null, true, null)),
'/slashed/group/b' => array(array(array('_route' => 'slashed_b'), null, null, null, true, null)),
'/slashed/group/c' => array(array(array('_route' => 'slashed_c'), null, null, null, true, null)),
'/a/11' => array(array(array('_route' => 'a_first'), null, null, null, false, false, null)),
'/a/22' => array(array(array('_route' => 'a_second'), null, null, null, false, false, null)),
'/a/333' => array(array(array('_route' => 'a_third'), null, null, null, false, false, null)),
'/a/44' => array(array(array('_route' => 'a_fourth'), null, null, null, true, false, null)),
'/a/55' => array(array(array('_route' => 'a_fifth'), null, null, null, true, false, null)),
'/a/66' => array(array(array('_route' => 'a_sixth'), null, null, null, true, false, null)),
'/nested/group/a' => array(array(array('_route' => 'nested_a'), null, null, null, true, false, null)),
'/nested/group/b' => array(array(array('_route' => 'nested_b'), null, null, null, true, false, null)),
'/nested/group/c' => array(array(array('_route' => 'nested_c'), null, null, null, true, false, null)),
'/slashed/group' => array(array(array('_route' => 'slashed_a'), null, null, null, true, false, null)),
'/slashed/group/b' => array(array(array('_route' => 'slashed_b'), null, null, null, true, false, null)),
'/slashed/group/c' => array(array(array('_route' => 'slashed_c'), null, null, null, true, false, null)),
);
$this->regexpList = array(
0 => '{^(?'
.'|/([^/]++)(*:16)'
.'|/nested/([^/]++)(*:39)'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
16 => array(array(array('_route' => 'a_wildcard'), array('param'), null, null, false, null)),
39 => array(array(array('_route' => 'nested_wildcard'), array('param'), null, null, false, null)),
16 => array(array(array('_route' => 'a_wildcard'), array('param'), null, null, false, true, null)),
39 => array(array(array('_route' => 'nested_wildcard'), array('param'), null, null, false, true, null)),
);
}
}

View File

@ -15,14 +15,14 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
{
$this->context = $context;
$this->staticRoutes = array(
'/trailing/simple/no-methods' => array(array(array('_route' => 'simple_trailing_slash_no_methods'), null, null, null, true, null)),
'/trailing/simple/get-method' => array(array(array('_route' => 'simple_trailing_slash_GET_method'), null, array('GET' => 0), null, true, null)),
'/trailing/simple/head-method' => array(array(array('_route' => 'simple_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, true, null)),
'/trailing/simple/post-method' => array(array(array('_route' => 'simple_trailing_slash_POST_method'), null, array('POST' => 0), null, true, null)),
'/not-trailing/simple/no-methods' => array(array(array('_route' => 'simple_not_trailing_slash_no_methods'), null, null, null, false, null)),
'/not-trailing/simple/get-method' => array(array(array('_route' => 'simple_not_trailing_slash_GET_method'), null, array('GET' => 0), null, false, null)),
'/not-trailing/simple/head-method' => array(array(array('_route' => 'simple_not_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, false, null)),
'/not-trailing/simple/post-method' => array(array(array('_route' => 'simple_not_trailing_slash_POST_method'), null, array('POST' => 0), null, false, null)),
'/trailing/simple/no-methods' => array(array(array('_route' => 'simple_trailing_slash_no_methods'), null, null, null, true, false, null)),
'/trailing/simple/get-method' => array(array(array('_route' => 'simple_trailing_slash_GET_method'), null, array('GET' => 0), null, true, false, null)),
'/trailing/simple/head-method' => array(array(array('_route' => 'simple_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, true, false, null)),
'/trailing/simple/post-method' => array(array(array('_route' => 'simple_trailing_slash_POST_method'), null, array('POST' => 0), null, true, false, null)),
'/not-trailing/simple/no-methods' => array(array(array('_route' => 'simple_not_trailing_slash_no_methods'), null, null, null, false, false, null)),
'/not-trailing/simple/get-method' => array(array(array('_route' => 'simple_not_trailing_slash_GET_method'), null, array('GET' => 0), null, false, false, null)),
'/not-trailing/simple/head-method' => array(array(array('_route' => 'simple_not_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, false, false, null)),
'/not-trailing/simple/post-method' => array(array(array('_route' => 'simple_not_trailing_slash_POST_method'), null, array('POST' => 0), null, false, false, null)),
);
$this->regexpList = array(
0 => '{^(?'
@ -38,17 +38,17 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
.'|head\\-method/([^/]++)(*:240)'
.'|post\\-method/([^/]++)(*:269)'
.')'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
46 => array(array(array('_route' => 'regex_trailing_slash_no_methods'), array('param'), null, null, true, null)),
73 => array(array(array('_route' => 'regex_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, true, null)),
101 => array(array(array('_route' => 'regex_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, true, null)),
130 => array(array(array('_route' => 'regex_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, true, null)),
183 => array(array(array('_route' => 'regex_not_trailing_slash_no_methods'), array('param'), null, null, false, null)),
211 => array(array(array('_route' => 'regex_not_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, false, null)),
240 => array(array(array('_route' => 'regex_not_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, false, null)),
269 => array(array(array('_route' => 'regex_not_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, false, null)),
46 => array(array(array('_route' => 'regex_trailing_slash_no_methods'), array('param'), null, null, true, true, null)),
73 => array(array(array('_route' => 'regex_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, true, true, null)),
101 => array(array(array('_route' => 'regex_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, true, true, null)),
130 => array(array(array('_route' => 'regex_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, true, true, null)),
183 => array(array(array('_route' => 'regex_not_trailing_slash_no_methods'), array('param'), null, null, false, true, null)),
211 => array(array(array('_route' => 'regex_not_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, false, true, null)),
240 => array(array(array('_route' => 'regex_not_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, false, true, null)),
269 => array(array(array('_route' => 'regex_not_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, false, true, null)),
);
}
}

View File

@ -15,14 +15,14 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
{
$this->context = $context;
$this->staticRoutes = array(
'/trailing/simple/no-methods' => array(array(array('_route' => 'simple_trailing_slash_no_methods'), null, null, null, true, null)),
'/trailing/simple/get-method' => array(array(array('_route' => 'simple_trailing_slash_GET_method'), null, array('GET' => 0), null, true, null)),
'/trailing/simple/head-method' => array(array(array('_route' => 'simple_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, true, null)),
'/trailing/simple/post-method' => array(array(array('_route' => 'simple_trailing_slash_POST_method'), null, array('POST' => 0), null, true, null)),
'/not-trailing/simple/no-methods' => array(array(array('_route' => 'simple_not_trailing_slash_no_methods'), null, null, null, false, null)),
'/not-trailing/simple/get-method' => array(array(array('_route' => 'simple_not_trailing_slash_GET_method'), null, array('GET' => 0), null, false, null)),
'/not-trailing/simple/head-method' => array(array(array('_route' => 'simple_not_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, false, null)),
'/not-trailing/simple/post-method' => array(array(array('_route' => 'simple_not_trailing_slash_POST_method'), null, array('POST' => 0), null, false, null)),
'/trailing/simple/no-methods' => array(array(array('_route' => 'simple_trailing_slash_no_methods'), null, null, null, true, false, null)),
'/trailing/simple/get-method' => array(array(array('_route' => 'simple_trailing_slash_GET_method'), null, array('GET' => 0), null, true, false, null)),
'/trailing/simple/head-method' => array(array(array('_route' => 'simple_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, true, false, null)),
'/trailing/simple/post-method' => array(array(array('_route' => 'simple_trailing_slash_POST_method'), null, array('POST' => 0), null, true, false, null)),
'/not-trailing/simple/no-methods' => array(array(array('_route' => 'simple_not_trailing_slash_no_methods'), null, null, null, false, false, null)),
'/not-trailing/simple/get-method' => array(array(array('_route' => 'simple_not_trailing_slash_GET_method'), null, array('GET' => 0), null, false, false, null)),
'/not-trailing/simple/head-method' => array(array(array('_route' => 'simple_not_trailing_slash_HEAD_method'), null, array('HEAD' => 0), null, false, false, null)),
'/not-trailing/simple/post-method' => array(array(array('_route' => 'simple_not_trailing_slash_POST_method'), null, array('POST' => 0), null, false, false, null)),
);
$this->regexpList = array(
0 => '{^(?'
@ -38,17 +38,17 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
.'|head\\-method/([^/]++)(*:240)'
.'|post\\-method/([^/]++)(*:269)'
.')'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
46 => array(array(array('_route' => 'regex_trailing_slash_no_methods'), array('param'), null, null, true, null)),
73 => array(array(array('_route' => 'regex_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, true, null)),
101 => array(array(array('_route' => 'regex_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, true, null)),
130 => array(array(array('_route' => 'regex_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, true, null)),
183 => array(array(array('_route' => 'regex_not_trailing_slash_no_methods'), array('param'), null, null, false, null)),
211 => array(array(array('_route' => 'regex_not_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, false, null)),
240 => array(array(array('_route' => 'regex_not_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, false, null)),
269 => array(array(array('_route' => 'regex_not_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, false, null)),
46 => array(array(array('_route' => 'regex_trailing_slash_no_methods'), array('param'), null, null, true, true, null)),
73 => array(array(array('_route' => 'regex_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, true, true, null)),
101 => array(array(array('_route' => 'regex_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, true, true, null)),
130 => array(array(array('_route' => 'regex_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, true, true, null)),
183 => array(array(array('_route' => 'regex_not_trailing_slash_no_methods'), array('param'), null, null, false, true, null)),
211 => array(array(array('_route' => 'regex_not_trailing_slash_GET_method'), array('param'), array('GET' => 0), null, false, true, null)),
240 => array(array(array('_route' => 'regex_not_trailing_slash_HEAD_method'), array('param'), array('HEAD' => 0), null, false, true, null)),
269 => array(array(array('_route' => 'regex_not_trailing_slash_POST_method'), array('param'), array('POST' => 0), null, false, true, null)),
);
}
}

View File

@ -17,18 +17,18 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
$this->regexpList = array(
0 => '{^(?'
.'|/(a)(*:11)'
.')(?:/?)$}sD',
.')/?$}sD',
11 => '{^(?'
.'|/(.)(*:22)'
.')(?:/?)$}sDu',
.')/?$}sDu',
22 => '{^(?'
.'|/(.)(*:33)'
.')(?:/?)$}sD',
.')/?$}sD',
);
$this->dynamicRoutes = array(
11 => array(array(array('_route' => 'a'), array('a'), null, null, false, null)),
22 => array(array(array('_route' => 'b'), array('a'), null, null, false, null)),
33 => array(array(array('_route' => 'c'), array('a'), null, null, false, null)),
11 => array(array(array('_route' => 'a'), array('a'), null, null, false, true, null)),
22 => array(array(array('_route' => 'b'), array('a'), null, null, false, true, null)),
33 => array(array(array('_route' => 'c'), array('a'), null, null, false, true, null)),
);
}
}

View File

@ -17,9 +17,9 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Matcher\UrlMatcher
$this->matchHost = true;
$this->staticRoutes = array(
'/' => array(
array(array('_route' => 'a'), '#^(?P<d>[^\\.]++)\\.e\\.c\\.b\\.a$#sDi', null, null, false, null),
array(array('_route' => 'c'), '#^(?P<e>[^\\.]++)\\.e\\.c\\.b\\.a$#sDi', null, null, false, null),
array(array('_route' => 'b'), 'd.c.b.a', null, null, false, null),
array(array('_route' => 'a'), '#^(?P<d>[^\\.]++)\\.e\\.c\\.b\\.a$#sDi', null, null, false, false, null),
array(array('_route' => 'c'), '#^(?P<e>[^\\.]++)\\.e\\.c\\.b\\.a$#sDi', null, null, false, false, null),
array(array('_route' => 'b'), 'd.c.b.a', null, null, false, false, null),
),
);
}

View File

@ -709,6 +709,16 @@ class UrlMatcherTest extends TestCase
$matcher = $this->getUrlMatcher($coll);
$this->assertSame(array('_route' => 'b'), $matcher->match('/bar/'));
$coll = new RouteCollection();
$coll->add('a', new Route('/dav/{foo<.*>?}', array(), array(), array(), '', array(), array('GET', 'OPTIONS')));
$matcher = $this->getUrlMatcher($coll, new RequestContext('', 'OPTIONS'));
$expected = array(
'_route' => 'a',
'foo' => 'files/bar',
);
$this->assertEquals($expected, $matcher->match('/dav/files/bar/'));
}
public function testSlashAndVerbPrecedence()

View File

@ -44,7 +44,7 @@
</trans-unit>
<trans-unit id="12">
<source>Username could not be found.</source>
<target>Không tìm thấy tên người dùng username.</target>
<target>Không tìm thấy tên người dùng.</target>
</trans-unit>
<trans-unit id="13">
<source>Account has expired.</source>

View File

@ -170,7 +170,7 @@ class ContextListener implements ListenerInterface
try {
$refreshedUser = $provider->refreshUser($user);
$newToken = unserialize(serialize($token));
$newToken = clone $token;
$newToken->setUser($refreshedUser);
// tokens can be deauthenticated if the user has been changed.

View File

@ -40,7 +40,7 @@
</trans-unit>
<trans-unit id="10">
<source>This field is missing.</source>
<target>Lĩnh vực này là mất tích.</target>
<target>Lĩnh vực này bị thiếu.</target>
</trans-unit>
<trans-unit id="11">
<source>This value is not a valid date.</source>
@ -132,7 +132,7 @@
</trans-unit>
<trans-unit id="36">
<source>This file is not a valid image.</source>
<target>Tập tin không phải là hình ảnh.</target>
<target>Tập tin không phải là hình ảnh hợp lệ.</target>
</trans-unit>
<trans-unit id="37">
<source>This is not a valid IP address.</source>
@ -148,7 +148,7 @@
</trans-unit>
<trans-unit id="40">
<source>This value is not a valid country.</source>
<target>Giá trị không phải là nước hợp lệ.</target>
<target>Giá trị không phải là quốc gia hợp lệ.</target>
</trans-unit>
<trans-unit id="41">
<source>This value is already used.</source>
@ -180,7 +180,7 @@
</trans-unit>
<trans-unit id="48">
<source>This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.</source>
<target>Giá trị phải có chính xác {{ limit }} kí tự.|Giá trị phải có chính xác {{ limit }} kí tự.</target>
<target>Giá trị này phải có chính xác {{ limit }} kí tự.|Giá trị này phải có chính xác {{ limit }} kí tự.</target>
</trans-unit>
<trans-unit id="49">
<source>The file was only partially uploaded.</source>
@ -204,11 +204,11 @@
</trans-unit>
<trans-unit id="54">
<source>This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.</source>
<target>Danh sách phải chứa {{ limit }} hoặc nhiều hơn thành phần.|Danh sách phải chứa {{ limit }} hoặc nhiều hơn thành phần.</target>
<target>Danh sách phải chứa {{ limit }} thành phần hoặc nhiều hơn.|Danh sách phải chứa {{ limit }} thành phần hoặc nhiều hơn.</target>
</trans-unit>
<trans-unit id="55">
<source>This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.</source>
<target>Danh sách phải chứa {{ limit }} hoặc ít hơn thành phần.|Danh sách phải chứa {{ limit }} hoặc ít hơn thành phần.</target>
<target>Danh sách phải chứa {{ limit }} thành phần hoặc ít hơn.|Danh sách phải chứa {{ limit }} thành phần hoặc ít hơn.</target>
</trans-unit>
<trans-unit id="56">
<source>This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.</source>
@ -240,11 +240,11 @@
</trans-unit>
<trans-unit id="63">
<source>This value is not a valid ISSN.</source>
<target>Giá trị không là ISSN hợp lệ.</target>
<target>Giá trị không phải là ISSN hợp lệ.</target>
</trans-unit>
<trans-unit id="64">
<source>This value is not a valid currency.</source>
<target>Giá trị không phải là đơn vi tiền tệ hợp lệ.</target>
<target>Giá trị không phải là đơn v tiền tệ hợp lệ.</target>
</trans-unit>
<trans-unit id="65">
<source>This value should be equal to {{ compared_value }}.</source>
@ -268,7 +268,7 @@
</trans-unit>
<trans-unit id="70">
<source>This value should be less than or equal to {{ compared_value }}.</source>
<target>Giá trị không được phép nhỏ hơn hoặc bằng {{ compared_value }}.</target>
<target>Giá trị phải nhỏ hơn hoặc bằng {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="71">
<source>This value should not be equal to {{ compared_value }}.</source>

View File

@ -35,7 +35,7 @@ SplFileInfo {
aTime: %s-%s-%d %d:%d:%d
mTime: %s-%s-%d %d:%d:%d
cTime: %s-%s-%d %d:%d:%d
inode: %d
inode: %i
size: %d
perms: 0%d
owner: %d
@ -85,7 +85,7 @@ SplFileObject {
aTime: %s-%s-%d %d:%d:%d
mTime: %s-%s-%d %d:%d:%d
cTime: %s-%s-%d %d:%d:%d
inode: %d
inode: %i
size: %d
perms: 0%d
owner: %d
@ -105,7 +105,7 @@ SplFileObject {
maxLineLen: 0
fstat: array:26 [
"dev" => %d
"ino" => %d
"ino" => %i
"nlink" => %d
"rdev" => 0
"blksize" => %i