diff --git a/.travis.yml b/.travis.yml
index da1bacca59..711fa49c74 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -56,15 +56,38 @@ before_install:
export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data"
export COMPOSER_UP='composer update --no-progress --no-suggest --ansi'
+ nanoseconds() {
+ local cmd="date"
+ local format="+%s%N"
+ local os=$(uname)
+ if hash gdate > /dev/null 2>&1; then
+ cmd="gdate"
+ elif [[ "$os" = Darwin ]]; then
+ format="+%s000000000"
+ fi
+ $cmd -u $format
+ }
+ export -f nanoseconds
+
# tfold is a helper to create folded reports
tfold () {
- title=$1
- fold=$(echo $title | sed -r 's/[^-_A-Za-z\d]+/./g')
+ local title=$1
+ local fold=$(echo $title | sed -r 's/[^-_A-Za-z0-9]+/./g')
shift
- echo -e "travis_fold:start:$fold\\n\\e[1;34m$title\\e[0m"
- bash -xc "$*" 2>&1 &&
+ local id=$(printf %08x $(( RANDOM * RANDOM )))
+ local start=$(nanoseconds)
+ echo -e "travis_fold:start:$fold"
+ echo -e "travis_time:start:$id"
+ echo -e "\\e[1;34m$title\\e[0m"
+
+ bash -xc "$*" 2>&1
+ local ok=$?
+ local end=$(nanoseconds)
+ echo -e "\\ntravis_time:end:$id:start=$start,finish=$end,duration=$(($end-$start))"
+ (exit $ok) &&
echo -e "\\e[32mOK\\e[0m $title\\n\\ntravis_fold:end:$fold" ||
- ( echo -e "\\e[41mKO\\e[0m $title\\n" && exit 1 )
+ echo -e "\\e[41mKO\\e[0m $title\\n"
+ (exit $ok)
}
export -f tfold
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index 8fa8bf5e11..66b42ffcd8 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -72,6 +72,7 @@ class Application
private $terminal;
private $defaultCommand;
private $singleCommand;
+ private $initialized;
/**
* @param string $name The name of the application
@@ -83,12 +84,6 @@ class Application
$this->version = $version;
$this->terminal = new Terminal();
$this->defaultCommand = 'list';
- $this->helperSet = $this->getDefaultHelperSet();
- $this->definition = $this->getDefaultInputDefinition();
-
- foreach ($this->getDefaultCommands() as $command) {
- $this->add($command);
- }
}
public function setDispatcher(EventDispatcherInterface $dispatcher)
@@ -195,10 +190,11 @@ class Application
if (!$name) {
$name = $this->defaultCommand;
- $this->definition->setArguments(array_merge(
- $this->definition->getArguments(),
+ $definition = $this->getDefinition();
+ $definition->setArguments(array_merge(
+ $definition->getArguments(),
array(
- 'command' => new InputArgument('command', InputArgument::OPTIONAL, $this->definition->getArgument('command')->getDescription(), $name),
+ 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
)
));
}
@@ -248,6 +244,10 @@ class Application
*/
public function getHelperSet()
{
+ if (!$this->helperSet) {
+ $this->helperSet = $this->getDefaultHelperSet();
+ }
+
return $this->helperSet;
}
@@ -268,6 +268,10 @@ class Application
*/
public function getDefinition()
{
+ if (!$this->definition) {
+ $this->definition = $this->getDefaultInputDefinition();
+ }
+
if ($this->singleCommand) {
$inputDefinition = $this->definition;
$inputDefinition->setArguments();
@@ -424,6 +428,8 @@ class Application
*/
public function add(Command $command)
{
+ $this->init();
+
$command->setApplication($this);
if (!$command->isEnabled()) {
@@ -456,6 +462,8 @@ class Application
*/
public function get($name)
{
+ $this->init();
+
if (!isset($this->commands[$name])) {
throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
}
@@ -483,6 +491,8 @@ class Application
*/
public function has($name)
{
+ $this->init();
+
return isset($this->commands[$name]);
}
@@ -560,6 +570,8 @@ class Application
*/
public function find($name)
{
+ $this->init();
+
$allCommands = array_keys($this->commands);
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);
@@ -626,6 +638,8 @@ class Application
*/
public function all($namespace = null)
{
+ $this->init();
+
if (null === $namespace) {
return $this->commands;
}
@@ -1139,4 +1153,16 @@ class Application
return $namespaces;
}
+
+ private function init()
+ {
+ if ($this->initialized) {
+ return;
+ }
+ $this->initialized = true;
+
+ foreach ($this->getDefaultCommands() as $command) {
+ $this->add($command);
+ }
+ }
}
diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php
index 2e1d71808e..3a8b7d247e 100644
--- a/src/Symfony/Component/Debug/DebugClassLoader.php
+++ b/src/Symfony/Component/Debug/DebugClassLoader.php
@@ -26,6 +26,7 @@ class DebugClassLoader
{
private $classLoader;
private $isFinder;
+ private $loaded = array();
private static $caseCheck;
private static $final = array();
private static $finalMethods = array();
@@ -139,9 +140,10 @@ class DebugClassLoader
ErrorHandler::stackErrors();
try {
- if ($this->isFinder) {
+ if ($this->isFinder && !isset($this->loaded[$class])) {
+ $this->loaded[$class] = true;
if ($file = $this->classLoader[0]->findFile($class)) {
- require_once $file;
+ require $file;
}
} else {
call_user_func($this->classLoader, $class);
diff --git a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php
index f1e3fb7c61..af88d17fd2 100644
--- a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php
+++ b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php
@@ -59,6 +59,23 @@ class DebugClassLoaderTest extends TestCase
$this->fail('DebugClassLoader did not register');
}
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage boo
+ */
+ public function testThrowingClass()
+ {
+ try {
+ class_exists(__NAMESPACE__.'\Fixtures\Throwing');
+ $this->fail('Exception expected');
+ } catch (\Exception $e) {
+ $this->assertSame('boo', $e->getMessage());
+ }
+
+ // the second call also should throw
+ class_exists(__NAMESPACE__.'\Fixtures\Throwing');
+ }
+
public function testUnsilencing()
{
if (\PHP_VERSION_ID >= 70000) {
@@ -124,6 +141,7 @@ class DebugClassLoaderTest extends TestCase
/**
* @expectedException \RuntimeException
+ * @expectedExceptionMessage Case mismatch between loaded and declared class names
*/
public function testNameCaseMismatch()
{
@@ -145,6 +163,7 @@ class DebugClassLoaderTest extends TestCase
/**
* @expectedException \RuntimeException
+ * @expectedExceptionMessage Case mismatch between loaded and declared class names
*/
public function testPsr4CaseMismatch()
{
diff --git a/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php
new file mode 100644
index 0000000000..21e0aba17d
--- /dev/null
+++ b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php
@@ -0,0 +1,3 @@
+
*/
class File extends Constraint
diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
index af32dae4ae..3381076f3e 100644
--- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
+++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
@@ -339,6 +339,10 @@ class ClassMetadata extends GenericMetadata implements ClassMetadataInterface
*/
public function mergeConstraints(ClassMetadata $source)
{
+ if ($source->isGroupSequenceProvider()) {
+ $this->setGroupSequenceProvider(true);
+ }
+
foreach ($source->getConstraints() as $constraint) {
$this->addConstraint(clone $constraint);
}
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf
index 4fa0d42220..a3199bcc9d 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf
@@ -100,7 +100,7 @@
This value is not valid.
- Αυτή η τιμή δεν είναι έκγυρη.
+ Αυτή η τιμή δεν είναι έγκυρη.
This value is not a valid time.
@@ -136,11 +136,11 @@
This is not a valid IP address.
- Αυτό δεν είναι μια έκγυρη διεύθυνση IP.
+ Αυτό δεν είναι μια έγκυρη διεύθυνση IP.
This value is not a valid language.
- Αυτή η τιμή δεν αντιστοιχεί σε μια έκγυρη γλώσσα.
+ Αυτή η τιμή δεν αντιστοιχεί σε μια έγκυρη γλώσσα.
This value is not a valid locale.
@@ -148,7 +148,7 @@
This value is not a valid country.
- Αυτή η τιμή δεν αντιστοιχεί σε μια έκγυρη χώρα.
+ Αυτή η τιμή δεν αντιστοιχεί σε μια έγκυρη χώρα.
This value is already used.
diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderChildEntity.php b/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderChildEntity.php
new file mode 100644
index 0000000000..be7191f9b6
--- /dev/null
+++ b/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderChildEntity.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Validator\Tests\Fixtures;
+
+class GroupSequenceProviderChildEntity extends GroupSequenceProviderEntity
+{
+}
diff --git a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php
index 9a23e8cf35..a3f8a8c1ec 100644
--- a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php
+++ b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php
@@ -24,6 +24,7 @@ class ClassMetadataTest extends TestCase
const CLASSNAME = 'Symfony\Component\Validator\Tests\Fixtures\Entity';
const PARENTCLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityParent';
const PROVIDERCLASS = 'Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity';
+ const PROVIDERCHILDCLASS = 'Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderChildEntity';
protected $metadata;
@@ -301,6 +302,17 @@ class ClassMetadataTest extends TestCase
$this->assertTrue($metadata->isGroupSequenceProvider());
}
+ public function testMergeConstraintsMergesGroupSequenceProvider()
+ {
+ $parent = new ClassMetadata(self::PROVIDERCLASS);
+ $parent->setGroupSequenceProvider(true);
+
+ $metadata = new ClassMetadata(self::PROVIDERCHILDCLASS);
+ $metadata->mergeConstraints($parent);
+
+ $this->assertTrue($metadata->isGroupSequenceProvider());
+ }
+
/**
* https://github.com/symfony/symfony/issues/11604.
*/
@@ -309,13 +321,3 @@ class ClassMetadataTest extends TestCase
$this->assertCount(0, $this->metadata->getPropertyMetadata('foo'), '->getPropertyMetadata() returns an empty collection if no metadata is configured for the given property');
}
}
-
-class ParentClass
-{
- public $example = 0;
-}
-
-class ChildClass extends ParentClass
-{
- public $example = 1; // overrides parent property of same name
-}
diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
index 83f6aa7c31..0fbd213abe 100644
--- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
@@ -159,7 +159,8 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
/**
* Dumps the current line.
*
- * @param int $depth The recursive depth in the dumped structure for the line being dumped
+ * @param int $depth The recursive depth in the dumped structure for the line being dumped,
+ * or -1 to signal the end-of-dump to the line dumper callable
*/
protected function dumpLine($depth)
{
diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
index 02ec543b5a..90596f2551 100644
--- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
@@ -155,10 +155,10 @@ if (!doc.addEventListener) {
function toggle(a, recursive) {
var s = a.nextSibling || {}, oldClass = s.className, arrow, newClass;
- if ('sf-dump-compact' == oldClass) {
+ if (/\bsf-dump-compact\b/.test(oldClass)) {
arrow = '▼';
newClass = 'sf-dump-expanded';
- } else if ('sf-dump-expanded' == oldClass) {
+ } else if (/\bsf-dump-expanded\b/.test(oldClass)) {
arrow = '▶';
newClass = 'sf-dump-compact';
} else {
@@ -166,13 +166,13 @@ function toggle(a, recursive) {
}
a.lastChild.innerHTML = arrow;
- s.className = newClass;
+ s.className = s.className.replace(/\bsf-dump-(compact|expanded)\b/, newClass);
if (recursive) {
try {
a = s.querySelectorAll('.'+oldClass);
for (s = 0; s < a.length; ++s) {
- if (a[s].className !== newClass) {
+ if (-1 == a[s].className.indexOf(newClass)) {
a[s].className = newClass;
a[s].previousSibling.lastChild.innerHTML = arrow;
}
@@ -334,7 +334,7 @@ return function (root, x) {
if (f && t && f[0] !== t[0]) {
r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\$1'), 'mg'), t[0]);
}
- if ('sf-dump-compact' == r.className) {
+ if (/\bsf-dump-compact\b/.test(r.className)) {
toggle(s, isCtrlKey(e));
}
}
@@ -378,6 +378,7 @@ return function (root, x) {
a.title = (a.title ? a.title+'\n[' : '[')+keyHint+'+click] Expand all children';
a.innerHTML += '▼';
a.className += ' sf-dump-toggle';
+
x = 1;
if ('sf-dump' != elt.parentNode.className) {
x += elt.parentNode.getAttribute('data-depth')/1;
@@ -386,7 +387,7 @@ return function (root, x) {
if (x > options.maxDepth) {
toggle(a);
}
- } else if ('sf-dump-ref' == elt.className && (a = elt.getAttribute('href'))) {
+ } else if (/\bsf-dump-ref\b/.test(elt.className) && (a = elt.getAttribute('href'))) {
a = a.substr(1);
elt.className += ' '+a;