Merge remote-tracking branch 'origin/2.7' into 2.8
Conflicts: src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php
This commit is contained in:
commit
05f3c3db7b
|
@ -50,30 +50,7 @@ class DbalLogger implements SQLLogger
|
|||
}
|
||||
|
||||
if (is_array($params)) {
|
||||
foreach ($params as $index => $param) {
|
||||
if (!is_string($params[$index])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// non utf-8 strings break json encoding
|
||||
if (!preg_match('//u', $params[$index])) {
|
||||
$params[$index] = self::BINARY_DATA_VALUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// detect if the too long string must be shorten
|
||||
if (function_exists('mb_strlen')) {
|
||||
if (self::MAX_STRING_LENGTH < mb_strlen($params[$index], 'UTF-8')) {
|
||||
$params[$index] = mb_substr($params[$index], 0, self::MAX_STRING_LENGTH - 6, 'UTF-8').' [...]';
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (self::MAX_STRING_LENGTH < strlen($params[$index])) {
|
||||
$params[$index] = substr($params[$index], 0, self::MAX_STRING_LENGTH - 6).' [...]';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
$params = $this->normalizeParams($params);
|
||||
}
|
||||
|
||||
if (null !== $this->logger) {
|
||||
|
@ -101,4 +78,40 @@ class DbalLogger implements SQLLogger
|
|||
{
|
||||
$this->logger->debug($message, $params);
|
||||
}
|
||||
|
||||
private function normalizeParams(array $params)
|
||||
{
|
||||
foreach ($params as $index => $param) {
|
||||
// normalize recursively
|
||||
if (is_array($param)) {
|
||||
$params[$index] = $this->normalizeParams($param);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_string($params[$index])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// non utf-8 strings break json encoding
|
||||
if (!preg_match('//u', $params[$index])) {
|
||||
$params[$index] = self::BINARY_DATA_VALUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// detect if the too long string must be shorten
|
||||
if (function_exists('mb_strlen')) {
|
||||
if (self::MAX_STRING_LENGTH < mb_strlen($params[$index], 'UTF-8')) {
|
||||
$params[$index] = mb_substr($params[$index], 0, self::MAX_STRING_LENGTH - 6, 'UTF-8').' [...]';
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (self::MAX_STRING_LENGTH < strlen($params[$index])) {
|
||||
$params[$index] = substr($params[$index], 0, self::MAX_STRING_LENGTH - 6).' [...]';
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,37 @@ class DbalLoggerTest extends \PHPUnit_Framework_TestCase
|
|||
));
|
||||
}
|
||||
|
||||
public function testLogNonUtf8Array()
|
||||
{
|
||||
$logger = $this->getMock('Psr\\Log\\LoggerInterface');
|
||||
|
||||
$dbalLogger = $this
|
||||
->getMockBuilder('Symfony\\Bridge\\Doctrine\\Logger\\DbalLogger')
|
||||
->setConstructorArgs(array($logger, null))
|
||||
->setMethods(array('log'))
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$dbalLogger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
->with('SQL', array(
|
||||
'utf8' => 'foo',
|
||||
array(
|
||||
'nonutf8' => DbalLogger::BINARY_DATA_VALUE,
|
||||
)
|
||||
)
|
||||
)
|
||||
;
|
||||
|
||||
$dbalLogger->startQuery('SQL', array(
|
||||
'utf8' => 'foo',
|
||||
array(
|
||||
'nonutf8' => "\x7F\xFF",
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
public function testLogLongString()
|
||||
{
|
||||
$logger = $this->getMock('Psr\\Log\\LoggerInterface');
|
||||
|
|
|
@ -82,7 +82,7 @@ class UniqueEntityValidator extends ConstraintValidator
|
|||
$criteria = array();
|
||||
foreach ($fields as $fieldName) {
|
||||
if (!$class->hasField($fieldName) && !$class->hasAssociation($fieldName)) {
|
||||
throw new ConstraintDefinitionException(sprintf("The field '%s' is not mapped by Doctrine, so it cannot be validated for uniqueness.", $fieldName));
|
||||
throw new ConstraintDefinitionException(sprintf('The field "%s" is not mapped by Doctrine, so it cannot be validated for uniqueness.', $fieldName));
|
||||
}
|
||||
|
||||
$criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity);
|
||||
|
|
|
@ -21,10 +21,10 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
|||
*/
|
||||
class WebProcessor extends BaseWebProcessor
|
||||
{
|
||||
public function __construct()
|
||||
public function __construct(array $extraFields = null)
|
||||
{
|
||||
// Pass an empty array as the default null value would access $_SERVER
|
||||
parent::__construct(array());
|
||||
parent::__construct(array(), $extraFields);
|
||||
}
|
||||
|
||||
public function onKernelRequest(GetResponseEvent $event)
|
||||
|
|
|
@ -18,6 +18,42 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
class WebProcessorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testUsesRequestServerData()
|
||||
{
|
||||
list($event, $server) = $this->createRequestEvent();
|
||||
|
||||
$processor = new WebProcessor();
|
||||
$processor->onKernelRequest($event);
|
||||
$record = $processor($this->getRecord());
|
||||
|
||||
$this->assertCount(5, $record['extra']);
|
||||
$this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
|
||||
$this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']);
|
||||
$this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']);
|
||||
$this->assertEquals($server['SERVER_NAME'], $record['extra']['server']);
|
||||
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
|
||||
}
|
||||
|
||||
public function testCanBeConstructedWithExtraFields()
|
||||
{
|
||||
if (!$this->isExtraFieldsSupported()) {
|
||||
$this->markTestSkipped('WebProcessor of the installed Monolog version does not support $extraFields parameter');
|
||||
}
|
||||
|
||||
list($event, $server) = $this->createRequestEvent();
|
||||
|
||||
$processor = new WebProcessor(array('url', 'referrer'));
|
||||
$processor->onKernelRequest($event);
|
||||
$record = $processor($this->getRecord());
|
||||
|
||||
$this->assertCount(2, $record['extra']);
|
||||
$this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
|
||||
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function createRequestEvent()
|
||||
{
|
||||
$server = array(
|
||||
'REQUEST_URI' => 'A',
|
||||
|
@ -40,15 +76,7 @@ class WebProcessorTest extends \PHPUnit_Framework_TestCase
|
|||
->method('getRequest')
|
||||
->will($this->returnValue($request));
|
||||
|
||||
$processor = new WebProcessor();
|
||||
$processor->onKernelRequest($event);
|
||||
$record = $processor($this->getRecord());
|
||||
|
||||
$this->assertEquals($server['REQUEST_URI'], $record['extra']['url']);
|
||||
$this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']);
|
||||
$this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']);
|
||||
$this->assertEquals($server['SERVER_NAME'], $record['extra']['server']);
|
||||
$this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']);
|
||||
return array($event, $server);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -57,7 +85,7 @@ class WebProcessorTest extends \PHPUnit_Framework_TestCase
|
|||
*
|
||||
* @return array Record
|
||||
*/
|
||||
protected function getRecord($level = Logger::WARNING, $message = 'test')
|
||||
private function getRecord($level = Logger::WARNING, $message = 'test')
|
||||
{
|
||||
return array(
|
||||
'message' => $message,
|
||||
|
@ -69,4 +97,17 @@ class WebProcessorTest extends \PHPUnit_Framework_TestCase
|
|||
'extra' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
private function isExtraFieldsSupported()
|
||||
{
|
||||
$monologWebProcessorClass = new \ReflectionClass('Monolog\Processor\WebProcessor');
|
||||
|
||||
foreach ($monologWebProcessorClass->getConstructor()->getParameters() as $parameter) {
|
||||
if ('extraFields' === $parameter->getName()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ Provides utilities for PHPUnit, especially user deprecation notices management.
|
|||
It comes with the following features:
|
||||
|
||||
* disable the garbage collector;
|
||||
* enforce a consistent `C` locale;
|
||||
* auto-register `class_exists` to load Doctrine annotations;
|
||||
* print a user deprecation notices summary at the end of the test suite.
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ if (PHP_VERSION_ID >= 50400 && gc_enabled()) {
|
|||
gc_disable();
|
||||
}
|
||||
|
||||
// Enforce a consistent locale
|
||||
setlocale(LC_ALL, 'C');
|
||||
|
||||
if (class_exists('Doctrine\Common\Annotations\AnnotationRegistry')) {
|
||||
AnnotationRegistry::registerLoader('class_exists');
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
{%- for child in form %}
|
||||
{{- form_widget(child, {
|
||||
parent_label_class: label_attr.class|default(''),
|
||||
translation_domain: choice_translation_domain,
|
||||
}) -}}
|
||||
{% endfor -%}
|
||||
</div>
|
||||
|
@ -106,6 +107,7 @@
|
|||
{%- for child in form %}
|
||||
{{- form_widget(child, {
|
||||
parent_label_class: label_attr.class|default(''),
|
||||
translation_domain: choice_translation_domain,
|
||||
}) -}}
|
||||
{% endfor -%}
|
||||
</div>
|
||||
|
@ -156,7 +158,7 @@
|
|||
{%- endblock radio_label %}
|
||||
|
||||
{% block checkbox_radio_label %}
|
||||
{# Do no display the label if widget is not defined in order to prevent double label rendering #}
|
||||
{# Do not display the label if widget is not defined in order to prevent double label rendering #}
|
||||
{% if widget is defined %}
|
||||
{% if required %}
|
||||
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
|
||||
|
@ -169,7 +171,7 @@
|
|||
{% endif %}
|
||||
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
|
||||
{{- widget|raw -}}
|
||||
{{- label is not sameas(false) ? label|trans({}, translation_domain) -}}
|
||||
{{- label is not sameas(false) ? (translation_domain is sameas(false) ? label : label|trans({}, translation_domain)) -}}
|
||||
</label>
|
||||
{% endif %}
|
||||
{% endblock checkbox_radio_label %}
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<div {{ block('widget_container_attributes') }}>
|
||||
{%- for child in form %}
|
||||
{{- form_widget(child) -}}
|
||||
{{- form_label(child) -}}
|
||||
{{- form_label(child, null, {translation_domain: choice_translation_domain}) -}}
|
||||
{% endfor -%}
|
||||
</div>
|
||||
{%- endblock choice_widget_expanded -%}
|
||||
|
@ -57,7 +57,7 @@
|
|||
{%- endif -%}
|
||||
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
|
||||
{%- if placeholder is not none -%}
|
||||
<option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ placeholder|trans({}, translation_domain) }}</option>
|
||||
<option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ placeholder != '' ? placeholder|trans({}, translation_domain) }}</option>
|
||||
{%- endif -%}
|
||||
{%- if preferred_choices|length > 0 -%}
|
||||
{% set options = preferred_choices %}
|
||||
|
@ -225,7 +225,7 @@
|
|||
{% set label = name|humanize %}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>
|
||||
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ translation_domain is sameas(false) ? label : label|trans({}, translation_domain) }}</label>
|
||||
{%- endif -%}
|
||||
{%- endblock form_label -%}
|
||||
|
||||
|
|
|
@ -106,106 +106,103 @@ EOF
|
|||
$kernel = $this->getContainer()->get('kernel');
|
||||
|
||||
// Define Root Path to App folder
|
||||
$rootPaths = array($kernel->getRootDir());
|
||||
$transPaths = array($kernel->getRootDir().'/Resources/');
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$rootPaths = array($kernel->getBundle($input->getArgument('bundle'))->getPath());
|
||||
$bundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$transPaths = array(
|
||||
$bundle->getPath().'/Resources/',
|
||||
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName()),
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$rootPaths = array($input->getArgument('bundle'));
|
||||
$transPaths = array($input->getArgument('bundle').'/Resources/');
|
||||
|
||||
if (!is_dir($rootPaths[0])) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.</error>', $rootPaths[0]));
|
||||
if (!is_dir($transPaths[0])) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
|
||||
}
|
||||
}
|
||||
} elseif ($input->getOption('all')) {
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$rootPaths[] = $bundle->getPath();
|
||||
$transPaths[] = $bundle->getPath().'/Resources/';
|
||||
$transPaths[] = sprintf('%s/Resources/%s/', $kernel->getRootDir(), $bundle->getName());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rootPaths as $rootPath) {
|
||||
// get bundle directory
|
||||
$translationsPath = $rootPath.'/Resources/translations';
|
||||
// Extract used messages
|
||||
$extractedCatalogue = $this->extractMessages($locale, $transPaths);
|
||||
|
||||
$output->writeln(sprintf('Translations in <info>%s</info>', $translationsPath));
|
||||
// Load defined messages
|
||||
$currentCatalogue = $this->loadCurrentMessages($locale, $transPaths, $loader);
|
||||
|
||||
// Extract used messages
|
||||
$extractedCatalogue = $this->extractMessages($locale, $rootPath);
|
||||
// Merge defined and extracted messages to get all message ids
|
||||
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
|
||||
$allMessages = $mergeOperation->getResult()->all($domain);
|
||||
if (null !== $domain) {
|
||||
$allMessages = array($domain => $allMessages);
|
||||
}
|
||||
|
||||
// Load defined messages
|
||||
$currentCatalogue = $this->loadCurrentMessages($locale, $translationsPath, $loader);
|
||||
// No defined or extracted messages
|
||||
if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
|
||||
$outputMessage = sprintf('No defined or extracted messages for locale "%s"', $locale);
|
||||
|
||||
// Merge defined and extracted messages to get all message ids
|
||||
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
|
||||
$allMessages = $mergeOperation->getResult()->all($domain);
|
||||
if (null !== $domain) {
|
||||
$allMessages = array($domain => $allMessages);
|
||||
$outputMessage .= sprintf(' and domain "%s"', $domain);
|
||||
}
|
||||
|
||||
// No defined or extracted messages
|
||||
if (empty($allMessages) || null !== $domain && empty($allMessages[$domain])) {
|
||||
$outputMessage = sprintf('<info>No defined or extracted messages for locale "%s"</info>', $locale);
|
||||
$output->warning($outputMessage);
|
||||
|
||||
if (null !== $domain) {
|
||||
$outputMessage .= sprintf(' <info>and domain "%s"</info>', $domain);
|
||||
}
|
||||
|
||||
$output->writeln($outputMessage);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Load the fallback catalogues
|
||||
$fallbackCatalogues = $this->loadFallbackCatalogues($locale, $translationsPath, $loader);
|
||||
|
||||
// Display header line
|
||||
$headers = array('State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale));
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale());
|
||||
}
|
||||
|
||||
// Iterate all message ids and determine their state
|
||||
$rows = array();
|
||||
foreach ($allMessages as $domain => $messages) {
|
||||
foreach (array_keys($messages) as $messageId) {
|
||||
$value = $currentCatalogue->get($messageId, $domain);
|
||||
$states = array();
|
||||
|
||||
if ($extractedCatalogue->defines($messageId, $domain)) {
|
||||
if (!$currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_MISSING;
|
||||
}
|
||||
} elseif ($currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_UNUSED;
|
||||
}
|
||||
|
||||
if (!in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused')
|
||||
|| !in_array(self::MESSAGE_MISSING, $states) && true === $input->getOption('only-missing')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_EQUALS_FALLBACK;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$row = array($this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value));
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain));
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$output->table($headers, $rows);
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the fallback catalogues
|
||||
$fallbackCatalogues = $this->loadFallbackCatalogues($locale, $transPaths, $loader);
|
||||
|
||||
// Display header line
|
||||
$headers = array('State', 'Domain', 'Id', sprintf('Message Preview (%s)', $locale));
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$headers[] = sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale());
|
||||
}
|
||||
$rows = array();
|
||||
// Iterate all message ids and determine their state
|
||||
foreach ($allMessages as $domain => $messages) {
|
||||
foreach (array_keys($messages) as $messageId) {
|
||||
$value = $currentCatalogue->get($messageId, $domain);
|
||||
$states = array();
|
||||
|
||||
if ($extractedCatalogue->defines($messageId, $domain)) {
|
||||
if (!$currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_MISSING;
|
||||
}
|
||||
} elseif ($currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_UNUSED;
|
||||
}
|
||||
|
||||
if (!in_array(self::MESSAGE_UNUSED, $states) && true === $input->getOption('only-unused')
|
||||
|| !in_array(self::MESSAGE_MISSING, $states) && true === $input->getOption('only-missing')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_EQUALS_FALLBACK;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$row = array($this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value));
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain));
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$output->table($headers, $rows);
|
||||
}
|
||||
|
||||
private function formatState($state)
|
||||
|
@ -257,15 +254,18 @@ EOF
|
|||
|
||||
/**
|
||||
* @param string $locale
|
||||
* @param string $rootPath
|
||||
* @param array $transPaths
|
||||
*
|
||||
* @return MessageCatalogue
|
||||
*/
|
||||
private function extractMessages($locale, $rootPath)
|
||||
private function extractMessages($locale, $transPaths)
|
||||
{
|
||||
$extractedCatalogue = new MessageCatalogue($locale);
|
||||
if (is_dir($rootPath.'/Resources/views')) {
|
||||
$this->getContainer()->get('translation.extractor')->extract($rootPath.'/Resources/views', $extractedCatalogue);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'views';
|
||||
if (is_dir($path)) {
|
||||
$this->getContainer()->get('translation.extractor')->extract($path, $extractedCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $extractedCatalogue;
|
||||
|
@ -273,16 +273,19 @@ EOF
|
|||
|
||||
/**
|
||||
* @param string $locale
|
||||
* @param string $translationsPath
|
||||
* @param array $transPaths
|
||||
* @param TranslationLoader $loader
|
||||
*
|
||||
* @return MessageCatalogue
|
||||
*/
|
||||
private function loadCurrentMessages($locale, $translationsPath, TranslationLoader $loader)
|
||||
private function loadCurrentMessages($locale, $transPaths, TranslationLoader $loader)
|
||||
{
|
||||
$currentCatalogue = new MessageCatalogue($locale);
|
||||
if (is_dir($translationsPath)) {
|
||||
$loader->loadMessages($translationsPath, $currentCatalogue);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'translations';
|
||||
if (is_dir($path)) {
|
||||
$loader->loadMessages($path, $currentCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCatalogue;
|
||||
|
@ -290,12 +293,12 @@ EOF
|
|||
|
||||
/**
|
||||
* @param string $locale
|
||||
* @param string $translationsPath
|
||||
* @param array $transPaths
|
||||
* @param TranslationLoader $loader
|
||||
*
|
||||
* @return MessageCatalogue[]
|
||||
*/
|
||||
private function loadFallbackCatalogues($locale, $translationsPath, TranslationLoader $loader)
|
||||
private function loadFallbackCatalogues($locale, $transPaths, TranslationLoader $loader)
|
||||
{
|
||||
$fallbackCatalogues = array();
|
||||
$translator = $this->getContainer()->get('translator');
|
||||
|
@ -306,7 +309,12 @@ EOF
|
|||
}
|
||||
|
||||
$fallbackCatalogue = new MessageCatalogue($fallbackLocale);
|
||||
$loader->loadMessages($translationsPath, $fallbackCatalogue);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'translations';
|
||||
if (is_dir($path)) {
|
||||
$loader->loadMessages($path, $fallbackCatalogue);
|
||||
}
|
||||
}
|
||||
$fallbackCatalogues[] = $fallbackCatalogue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ EOF
|
|||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output = new SymfonyStyle($input, $output);
|
||||
$kernel = $this->getContainer()->get('kernel');
|
||||
|
||||
// check presence of force or dump-message
|
||||
if ($input->getOption('force') !== true && $input->getOption('dump-messages') !== true) {
|
||||
$output->error('You must choose one of --force or --dump-messages');
|
||||
|
@ -87,30 +89,30 @@ EOF
|
|||
$kernel = $this->getContainer()->get('kernel');
|
||||
|
||||
// Define Root Path to App folder
|
||||
$rootPath = $kernel->getRootDir();
|
||||
$transPaths = array($kernel->getRootDir().'/Resources/');
|
||||
$currentName = 'app folder';
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$foundBundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$rootPath = $foundBundle->getPath();
|
||||
$transPaths = array(
|
||||
$foundBundle->getPath().'/Resources/',
|
||||
sprintf('%s/Resources/%s/', $kernel->getRootDir(), $foundBundle->getName()),
|
||||
);
|
||||
$currentName = $foundBundle->getName();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$rootPath = $input->getArgument('bundle');
|
||||
$currentName = $rootPath;
|
||||
$transPaths = array($input->getArgument('bundle').'/Resources/');
|
||||
$currentName = $transPaths[0];
|
||||
|
||||
if (!is_dir($rootPath)) {
|
||||
throw new \InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $rootPath));
|
||||
if (!is_dir($transPaths[0])) {
|
||||
throw new \InvalidArgumentException(sprintf('<error>"%s" is neither an enabled bundle nor a directory.</error>', $transPaths[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output->title('Symfony translation update command');
|
||||
|
||||
// get bundle directory
|
||||
$translationsPath = $rootPath.'/Resources/translations';
|
||||
$output->text(sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
|
||||
|
||||
// load any messages from templates
|
||||
|
@ -118,13 +120,23 @@ EOF
|
|||
$output->text('Parsing templates');
|
||||
$extractor = $this->getContainer()->get('translation.extractor');
|
||||
$extractor->setPrefix($input->getOption('prefix'));
|
||||
$extractor->extract($rootPath.'/Resources/views/', $extractedCatalogue);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'views';
|
||||
if (is_dir($path)) {
|
||||
$extractor->extract($path, $extractedCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
// load any existing messages from the translation files
|
||||
$currentCatalogue = new MessageCatalogue($input->getArgument('locale'));
|
||||
$output->text('Loading translation files');
|
||||
$loader = $this->getContainer()->get('translation.loader');
|
||||
$loader->loadMessages($translationsPath, $currentCatalogue);
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'translations';
|
||||
if (is_dir($path)) {
|
||||
$loader->loadMessages($path, $currentCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
// process catalogues
|
||||
$operation = $input->getOption('clean')
|
||||
|
@ -150,7 +162,7 @@ EOF
|
|||
array_map(function ($id) {
|
||||
return sprintf('<fg=green>%s</>', $id);
|
||||
}, $newKeys),
|
||||
array_map(function($id) {
|
||||
array_map(function ($id) {
|
||||
return sprintf('<fg=red>%s</>', $id);
|
||||
}, array_keys($operation->getObsoleteMessages($domain)))
|
||||
));
|
||||
|
@ -168,7 +180,18 @@ EOF
|
|||
// save the files
|
||||
if ($input->getOption('force') === true) {
|
||||
$output->text('Writing files');
|
||||
$writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $translationsPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
|
||||
|
||||
$bundleTransPath = false;
|
||||
foreach ($transPaths as $path) {
|
||||
$path = $path.'translations';
|
||||
if (is_dir($path)) {
|
||||
$bundleTransPath = $path;
|
||||
}
|
||||
}
|
||||
|
||||
if ($bundleTransPath) {
|
||||
$writer->writeTranslations($operation->getResult(), $input->getOption('output-format'), array('path' => $bundleTransPath, 'default_locale' => $this->getContainer()->getParameter('kernel.default_locale')));
|
||||
}
|
||||
}
|
||||
|
||||
$output->newLine();
|
||||
|
|
|
@ -119,9 +119,9 @@ class Controller extends ContainerAware
|
|||
* @param mixed $attributes The attributes
|
||||
* @param mixed $object The object
|
||||
*
|
||||
* @throws \LogicException
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function isGranted($attributes, $object = null)
|
||||
{
|
||||
|
@ -231,7 +231,7 @@ class Controller extends ContainerAware
|
|||
*
|
||||
* @return AccessDeniedException
|
||||
*/
|
||||
public function createAccessDeniedException($message = 'Access Denied', \Exception $previous = null)
|
||||
public function createAccessDeniedException($message = 'Access Denied.', \Exception $previous = null)
|
||||
{
|
||||
return new AccessDeniedException($message, $previous);
|
||||
}
|
||||
|
|
|
@ -444,7 +444,7 @@ class FrameworkExtension extends Extension
|
|||
/**
|
||||
* Loads the request configuration.
|
||||
*
|
||||
* @param array $config A session configuration array
|
||||
* @param array $config A request configuration array
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
* @param XmlFileLoader $loader An XmlFileLoader instance
|
||||
*/
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="templating.asset.path_package.class">Symfony\Bundle\FrameworkBundle\Templating\Asset\PathPackage</parameter>
|
||||
<parameter key="templating.asset.url_package.class">Symfony\Component\Templating\Asset\UrlPackage</parameter>
|
||||
<parameter key="templating.asset.package_factory.class">Symfony\Bundle\FrameworkBundle\Templating\Asset\PackageFactory</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="templating.asset.path_package" class="%templating.asset.path_package.class%" abstract="true">
|
||||
<argument type="service" id="request" />
|
||||
<argument /> <!-- version -->
|
||||
<argument /> <!-- version format -->
|
||||
</service>
|
||||
|
||||
<service id="templating.asset.url_package" class="%templating.asset.url_package.class%" abstract="true">
|
||||
<argument /> <!-- base urls -->
|
||||
<argument /> <!-- version -->
|
||||
<argument /> <!-- version format -->
|
||||
</service>
|
||||
|
||||
<service id="templating.asset.request_aware_package" class="Symfony\Component\Templating\Asset\PackageInterface" abstract="true">
|
||||
<factory service="templating.asset.package_factory" method="getPackage" />
|
||||
<argument type="service" id="request" strict="false" />
|
||||
<argument /> <!-- HTTP id -->
|
||||
<argument /> <!-- SSL id -->
|
||||
</service>
|
||||
|
||||
<service id="templating.asset.package_factory" class="%templating.asset.package_factory.class%">
|
||||
<argument type="service" id="service_container" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
|
@ -7,7 +7,7 @@
|
|||
)) ?>
|
||||
<?php if ($multiple): ?> multiple="multiple"<?php endif ?>
|
||||
>
|
||||
<?php if (null !== $placeholder): ?><option value=""<?php if ($required and empty($value) && "0" !== $value): ?> selected="selected"<?php endif?>><?php echo $view->escape($view['translator']->trans($placeholder, array(), $translation_domain)) ?></option><?php endif; ?>
|
||||
<?php if (null !== $placeholder): ?><option value=""<?php if ($required and empty($value) && '0' !== $value): ?> selected="selected"<?php endif?>><?php echo '' != $placeholder ? $view->escape($view['translator']->trans($placeholder, array(), $translation_domain)) : '' ?></option><?php endif; ?>
|
||||
<?php if (count($preferred_choices) > 0): ?>
|
||||
<?php echo $view['form']->block($form, 'choice_widget_options', array('choices' => $preferred_choices)) ?>
|
||||
<?php if (count($choices) > 0 && null !== $separator): ?>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div <?php echo $view['form']->block($form, 'widget_container_attributes') ?>>
|
||||
<?php foreach ($form as $child): ?>
|
||||
<?php echo $view['form']->widget($child) ?>
|
||||
<?php echo $view['form']->label($child) ?>
|
||||
<?php echo $view['form']->label($child, null, array('translation_domain' => $choice_translation_domain)) ?>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
<?php if (!$label) { $label = isset($label_format)
|
||||
? strtr($label_format, array('%name%' => $name, '%id%' => $id))
|
||||
: $view['form']->humanize($name); } ?>
|
||||
<label <?php foreach ($label_attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape($view['translator']->trans($label, array(), $translation_domain)) ?></label>
|
||||
<label <?php foreach ($label_attr as $k => $v) { printf('%s="%s" ', $view->escape($k), $view->escape($v)); } ?>><?php echo $view->escape(false !== $translation_domain ? $view['translator']->trans($label, array(), $translation_domain) : $label) ?></label>
|
||||
<?php endif ?>
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection;
|
|||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\FrameworkExtension;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\DependencyInjection\Loader\ClosureLoader;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
@ -530,14 +530,14 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||
$this->assertUrlPackage($container, $package, array('https://bar2.example.com'), $legacy ? '' : 'SomeVersionScheme', $legacy ? '%%s?%%s' : '%%s?version=%%s');
|
||||
}
|
||||
|
||||
private function assertPathPackage(ContainerBuilder $container, Definition $package, $basePath, $version, $format)
|
||||
private function assertPathPackage(ContainerBuilder $container, DefinitionDecorator $package, $basePath, $version, $format)
|
||||
{
|
||||
$this->assertEquals('assets.path_package', $package->getParent());
|
||||
$this->assertEquals($basePath, $package->getArgument(0));
|
||||
$this->assertVersionStrategy($container, $package->getArgument(1), $version, $format);
|
||||
}
|
||||
|
||||
private function assertUrlPackage(ContainerBuilder $container, Definition $package, $baseUrls, $version, $format)
|
||||
private function assertUrlPackage(ContainerBuilder $container, DefinitionDecorator $package, $baseUrls, $version, $format)
|
||||
{
|
||||
$this->assertEquals('assets.url_package', $package->getParent());
|
||||
$this->assertEquals($baseUrls, $package->getArgument(0));
|
||||
|
|
|
@ -77,7 +77,7 @@ class Cookie
|
|||
if (null !== $expires) {
|
||||
$timestampAsDateTime = \DateTime::createFromFormat('U', $expires);
|
||||
if (false === $timestampAsDateTime) {
|
||||
throw new \UnexpectedValueException(sprintf('The cookie expiration time "%s" is not valid.'), $expires);
|
||||
throw new \UnexpectedValueException(sprintf('The cookie expiration time "%s" is not valid.', $expires));
|
||||
}
|
||||
|
||||
$this->expires = $timestampAsDateTime->getTimestamp();
|
||||
|
|
|
@ -22,7 +22,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function prepare_workspace()
|
||||
{
|
||||
$this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().rand(0, 1000);
|
||||
$this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().mt_rand(0, 1000);
|
||||
mkdir($this->workspace, 0777, true);
|
||||
$this->workspace = realpath($this->workspace);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if the resource has not changed');
|
||||
$this->assertFalse($resource->isFresh(time() - 86400), '->isFresh() returns false if the resource has been updated');
|
||||
|
||||
$resource = new DirectoryResource('/____foo/foobar'.rand(1, 999999));
|
||||
$resource = new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999));
|
||||
$this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the resource does not exist');
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class FileResourceTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertTrue($this->resource->isFresh($this->time + 10), '->isFresh() returns true if the resource has not changed');
|
||||
$this->assertFalse($this->resource->isFresh($this->time - 86400), '->isFresh() returns false if the resource has been updated');
|
||||
|
||||
$resource = new FileResource('/____foo/foobar'.rand(1, 999999));
|
||||
$resource = new FileResource('/____foo/foobar'.mt_rand(1, 999999));
|
||||
$this->assertFalse($resource->isFresh($this->time), '->isFresh() returns false if the resource does not exist');
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ class TextDescriptor extends Descriptor
|
|||
$totalWidth = isset($options['total_width']) ? $options['total_width'] : strlen($argument->getName());
|
||||
$spacingWidth = $totalWidth - strlen($argument->getName()) + 2;
|
||||
|
||||
$this->writeText(sprintf(" <info>%s</info>%s%s%s",
|
||||
$this->writeText(sprintf(' <info>%s</info>%s%s%s',
|
||||
$argument->getName(),
|
||||
str_repeat(' ', $spacingWidth),
|
||||
// + 17 = 2 spaces + <info> + </info> + 2 spaces
|
||||
|
@ -77,7 +77,7 @@ class TextDescriptor extends Descriptor
|
|||
|
||||
$spacingWidth = $totalWidth - strlen($synopsis) + 2;
|
||||
|
||||
$this->writeText(sprintf(" <info>%s</info>%s%s%s%s",
|
||||
$this->writeText(sprintf(' <info>%s</info>%s%s%s%s',
|
||||
$synopsis,
|
||||
str_repeat(' ', $spacingWidth),
|
||||
// + 17 = 2 spaces + <info> + </info> + 2 spaces
|
||||
|
@ -207,7 +207,7 @@ class TextDescriptor extends Descriptor
|
|||
foreach ($namespace['commands'] as $name) {
|
||||
$this->writeText("\n");
|
||||
$spacingWidth = $width - strlen($name);
|
||||
$this->writeText(sprintf(" <info>%s</info>%s%s", $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options);
|
||||
$this->writeText(sprintf(' <info>%s</info>%s%s', $name, str_repeat(' ', $spacingWidth), $description->getCommand($name)->getDescription()), $options);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,8 @@ class TextDescriptor extends Descriptor
|
|||
{
|
||||
$totalWidth = 0;
|
||||
foreach ($options as $option) {
|
||||
$nameLength = 4 + strlen($option->getName()) + 2; // - + shortcut + , + whitespace + name + --
|
||||
// "-" + shortcut + ", --" + name
|
||||
$nameLength = 1 + max(strlen($option->getShortcut()), 1) + 4 + strlen($option->getName());
|
||||
|
||||
if ($option->acceptValue()) {
|
||||
$valueLength = 1 + strlen($option->getName()); // = + value
|
||||
|
|
|
@ -221,7 +221,7 @@ class ArgvInput extends Input
|
|||
}
|
||||
|
||||
if (null !== $value && !$option->acceptValue()) {
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name, $value));
|
||||
throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name));
|
||||
}
|
||||
|
||||
if (null === $value && $option->acceptValue() && count($this->parsed)) {
|
||||
|
|
|
@ -30,6 +30,9 @@ use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
|||
*/
|
||||
class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
||||
{
|
||||
/**
|
||||
* @var StreamOutput
|
||||
*/
|
||||
private $stderr;
|
||||
|
||||
/**
|
||||
|
@ -43,14 +46,12 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
|||
*/
|
||||
public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null)
|
||||
{
|
||||
$outputStream = 'php://stdout';
|
||||
if (!$this->hasStdoutSupport()) {
|
||||
$outputStream = 'php://output';
|
||||
}
|
||||
$outputStream = $this->hasStdoutSupport() ? 'php://stdout' : 'php://output';
|
||||
$errorStream = $this->hasStderrSupport() ? 'php://stderr' : 'php://output';
|
||||
|
||||
parent::__construct(fopen($outputStream, 'w'), $verbosity, $decorated, $formatter);
|
||||
|
||||
$this->stderr = new StreamOutput(fopen('php://stderr', 'w'), $verbosity, $decorated, $this->getFormatter());
|
||||
$this->stderr = new StreamOutput(fopen($errorStream, 'w'), $verbosity, $decorated, $this->getFormatter());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,14 +101,32 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
|
|||
* Returns true if current environment supports writing console output to
|
||||
* STDOUT.
|
||||
*
|
||||
* IBM iSeries (OS400) exhibits character-encoding issues when writing to
|
||||
* STDOUT and doesn't properly convert ASCII to EBCDIC, resulting in garbage
|
||||
* output.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasStdoutSupport()
|
||||
{
|
||||
return ('OS400' != php_uname('s'));
|
||||
return false === $this->isRunningOS400();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if current environment supports writing console output to
|
||||
* STDERR.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasStderrSupport()
|
||||
{
|
||||
return false === $this->isRunningOS400();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current executing environment is IBM iSeries (OS400), which
|
||||
* doesn't properly convert character-encodings between ASCII to EBCDIC.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isRunningOS400()
|
||||
{
|
||||
return 'OS400' === php_uname('s');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ class ObjectsProvider
|
|||
'input_option_3' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, 'option description'),
|
||||
'input_option_4' => new InputOption('option_name', 'o', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'option description', array()),
|
||||
'input_option_5' => new InputOption('option_name', 'o', InputOption::VALUE_REQUIRED, "multiline\noption description"),
|
||||
'input_option_6' => new InputOption('option_name', array('o', 'O'), InputOption::VALUE_REQUIRED, 'option with multiple shortcuts'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"name":"--option_name","shortcut":"-o|-O","accept_value":true,"is_value_required":true,"is_multiple":false,"description":"option with multiple shortcuts","default":null}
|
|
@ -0,0 +1,9 @@
|
|||
**option_name:**
|
||||
|
||||
* Name: `--option_name`
|
||||
* Shortcut: `-o|-O`
|
||||
* Accept value: yes
|
||||
* Is value required: yes
|
||||
* Is multiple: no
|
||||
* Description: option with multiple shortcuts
|
||||
* Default: `NULL`
|
|
@ -0,0 +1 @@
|
|||
<info>-o|O, --option_name=OPTION_NAME</info> option with multiple shortcuts
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<option name="--option_name" shortcut="-o" shortcuts="-o|-O" accept_value="1" is_value_required="1" is_multiple="0">
|
||||
<description>option with multiple shortcuts</description>
|
||||
<defaults/>
|
||||
</option>
|
|
@ -162,6 +162,14 @@ class ResolveDefinitionTemplatesPass implements CompilerPassInterface
|
|||
if (isset($changes['lazy'])) {
|
||||
$def->setLazy($definition->isLazy());
|
||||
}
|
||||
if (isset($changes['decorated_service'])) {
|
||||
$decoratedService = $definition->getDecoratedService();
|
||||
if (null === $decoratedService) {
|
||||
$def->setDecoratedService($decoratedService);
|
||||
} else {
|
||||
$def->setDecoratedService($decoratedService[0], $decoratedService[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// merge arguments
|
||||
foreach ($definition->getArguments() as $k => $v) {
|
||||
|
|
|
@ -170,6 +170,16 @@ class DefinitionDecorator extends Definition
|
|||
return parent::setLazy($boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setDecoratedService($id, $renamedId = null)
|
||||
{
|
||||
$this->changes['decorated_service'] = true;
|
||||
|
||||
return parent::setDecoratedService($id, $renamedId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an argument to pass to the service constructor/factory method.
|
||||
*
|
||||
|
|
|
@ -1301,11 +1301,6 @@ EOF;
|
|||
foreach ($value->getArguments() as $argument) {
|
||||
$arguments[] = $this->dumpValue($argument);
|
||||
}
|
||||
$class = $this->dumpValue($value->getClass());
|
||||
|
||||
if (false !== strpos($class, '$')) {
|
||||
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
|
||||
}
|
||||
|
||||
if (null !== $value->getFactory()) {
|
||||
$factory = $value->getFactory();
|
||||
|
@ -1343,6 +1338,15 @@ EOF;
|
|||
}
|
||||
}
|
||||
|
||||
$class = $value->getClass();
|
||||
if (null === $class) {
|
||||
throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
|
||||
}
|
||||
$class = $this->dumpValue($class);
|
||||
if (false !== strpos($class, '$')) {
|
||||
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
|
||||
}
|
||||
|
||||
return sprintf('new \\%s(%s)', substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
|
||||
} elseif ($value instanceof Variable) {
|
||||
return '$'.$value;
|
||||
|
|
|
@ -151,7 +151,7 @@ class XmlFileLoader extends FileLoader
|
|||
foreach (array('class', 'shared', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
|
||||
if ($value = $service->getAttribute($key)) {
|
||||
if (in_array($key, array('factory-class', 'factory-method', 'factory-service'))) {
|
||||
@trigger_error(sprintf('The "%s" attribute in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, $file), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "%s" attribute of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
|
||||
}
|
||||
$method = 'set'.str_replace('-', '', $key);
|
||||
$definition->$method(XmlUtils::phpize($value));
|
||||
|
@ -172,7 +172,7 @@ class XmlFileLoader extends FileLoader
|
|||
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
|
||||
|
||||
if ($triggerDeprecation) {
|
||||
@trigger_error(sprintf('The "synchronized" attribute in file "%s" is deprecated since version 2.7 and will be removed in 3.0.', $file), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "synchronized" attribute of service "%s" in file "%s" is deprecated since version 2.7 and will be removed in 3.0.', (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
$definition->setSynchronized(XmlUtils::phpize($value), $triggerDeprecation);
|
||||
|
|
|
@ -179,7 +179,7 @@ class YamlFileLoader extends FileLoader
|
|||
}
|
||||
|
||||
if (isset($service['synchronized'])) {
|
||||
@trigger_error(sprintf('The "synchronized" key in file "%s" is deprecated since version 2.7 and will be removed in 3.0.', $file), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "synchronized" key of service "%s" in file "%s" is deprecated since version 2.7 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
|
||||
$definition->setSynchronized($service['synchronized'], 'request' !== $id);
|
||||
}
|
||||
|
||||
|
@ -209,17 +209,17 @@ class YamlFileLoader extends FileLoader
|
|||
}
|
||||
|
||||
if (isset($service['factory_class'])) {
|
||||
@trigger_error(sprintf('The "factory_class" key in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $file), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "factory_class" key of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
|
||||
$definition->setFactoryClass($service['factory_class']);
|
||||
}
|
||||
|
||||
if (isset($service['factory_method'])) {
|
||||
@trigger_error(sprintf('The "factory_method" key in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $file), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "factory_method" key of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
|
||||
$definition->setFactoryMethod($service['factory_method']);
|
||||
}
|
||||
|
||||
if (isset($service['factory_service'])) {
|
||||
@trigger_error(sprintf('The "factory_service" key in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $file), E_USER_DEPRECATED);
|
||||
@trigger_error(sprintf('The "factory_service" key of service "%s" in file "%s" is deprecated since version 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
|
||||
$definition->setFactoryService($service['factory_service']);
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,25 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals(array(), $def->getTags());
|
||||
}
|
||||
|
||||
public function testProcessDoesNotCopyDecoratedService()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container
|
||||
->register('parent')
|
||||
->setDecoratedService('foo')
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('child', new DefinitionDecorator('parent'))
|
||||
;
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$def = $container->getDefinition('child');
|
||||
$this->assertNull($def->getDecoratedService());
|
||||
}
|
||||
|
||||
public function testProcessHandlesMultipleInheritance()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
@ -212,6 +231,19 @@ class ResolveDefinitionTemplatesPassTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertSame('parentClass', $methodCalls[0][1][0]->getClass());
|
||||
}
|
||||
|
||||
public function testSetDecoratedServiceOnServiceHasParent()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('parent', 'stdClass');
|
||||
|
||||
$container->setDefinition('child1', new DefinitionDecorator('parent'))
|
||||
->setDecoratedService('foo', 'foo_inner')
|
||||
;
|
||||
|
||||
$this->assertEquals(array('foo', 'foo_inner'), $container->getDefinition('child1')->getDecoratedService());
|
||||
}
|
||||
|
||||
protected function process(ContainerBuilder $container)
|
||||
{
|
||||
$pass = new ResolveDefinitionTemplatesPass();
|
||||
|
|
Binary file not shown.
|
@ -44,4 +44,4 @@ $phar->addFromString('schema/project-1.0.xsd', <<<EOT
|
|||
</xsd:schema>
|
||||
EOT
|
||||
);
|
||||
$phar->setStub('<?php require_once "phar://ProjectWithXsdExtensionInPhar.phar/ProjectWithXsdExtensionInPhar.php"; __HALT_COMPILER(); ?>');
|
||||
$phar->setStub('<?php Phar::mapPhar("ProjectWithXsdExtensionInPhar.phar"); require_once "phar://ProjectWithXsdExtensionInPhar.phar/ProjectWithXsdExtensionInPhar.php"; __HALT_COMPILER(); ?>');
|
||||
|
|
|
@ -244,7 +244,7 @@ class Filesystem
|
|||
$this->chgrp(new \FilesystemIterator($file), $group, true);
|
||||
}
|
||||
if (is_link($file) && function_exists('lchgrp')) {
|
||||
if (true !== @lchgrp($file, $group)) {
|
||||
if (true !== @lchgrp($file, $group) || (defined('HHVM_VERSION') && !posix_getgrnam($group))) {
|
||||
throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -15,11 +15,10 @@ use Symfony\Component\Finder\Glob;
|
|||
|
||||
class GlobTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
public function testGlobToRegexDelimiters()
|
||||
{
|
||||
$this->assertEquals(Glob::toRegex('.*'), '#^\.[^/]*$#');
|
||||
$this->assertEquals(Glob::toRegex('.*', true, true, ''), '^\.[^/]*$');
|
||||
$this->assertEquals(Glob::toRegex('.*', true, true, '/'), '/^\.[^/]*$/');
|
||||
$this->assertEquals('#^\.[^/]*$#', Glob::toRegex('.*'));
|
||||
$this->assertEquals('^\.[^/]*$', Glob::toRegex('.*', true, true, ''));
|
||||
$this->assertEquals('/^\.[^/]*$/', Glob::toRegex('.*', true, true, '/'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,14 +30,21 @@ class ArrayChoiceList implements ChoiceListInterface
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $choices = array();
|
||||
protected $choices;
|
||||
|
||||
/**
|
||||
* The values of the choices.
|
||||
* The values indexed by the original keys.
|
||||
*
|
||||
* @var string[]
|
||||
* @var array
|
||||
*/
|
||||
protected $values = array();
|
||||
protected $structuredValues;
|
||||
|
||||
/**
|
||||
* The original keys of the choices array.
|
||||
*
|
||||
* @var int[]|string[]
|
||||
*/
|
||||
protected $originalKeys;
|
||||
|
||||
/**
|
||||
* The callback for creating the value for a choice.
|
||||
|
@ -51,31 +58,41 @@ class ArrayChoiceList implements ChoiceListInterface
|
|||
*
|
||||
* The given choice array must have the same array keys as the value array.
|
||||
*
|
||||
* @param array $choices The selectable choices
|
||||
* @param callable|null $value The callable for creating the value for a
|
||||
* choice. If `null` is passed, incrementing
|
||||
* integers are used as values
|
||||
* @param array|\Traversable $choices The selectable choices
|
||||
* @param callable|null $value The callable for creating the value
|
||||
* for a choice. If `null` is passed,
|
||||
* incrementing integers are used as
|
||||
* values
|
||||
*/
|
||||
public function __construct(array $choices, $value = null)
|
||||
public function __construct($choices, $value = null)
|
||||
{
|
||||
if (null !== $value && !is_callable($value)) {
|
||||
throw new UnexpectedTypeException($value, 'null or callable');
|
||||
}
|
||||
|
||||
$this->choices = $choices;
|
||||
$this->values = array();
|
||||
$this->valueCallback = $value;
|
||||
|
||||
if (null === $value) {
|
||||
$i = 0;
|
||||
foreach ($this->choices as $key => $choice) {
|
||||
$this->values[$key] = (string) $i++;
|
||||
}
|
||||
} else {
|
||||
foreach ($choices as $key => $choice) {
|
||||
$this->values[$key] = (string) call_user_func($value, $choice);
|
||||
}
|
||||
if ($choices instanceof \Traversable) {
|
||||
$choices = iterator_to_array($choices);
|
||||
}
|
||||
|
||||
if (null !== $value) {
|
||||
// If a deterministic value generator was passed, use it later
|
||||
$this->valueCallback = $value;
|
||||
} else {
|
||||
// Otherwise simply generate incrementing integers as values
|
||||
$i = 0;
|
||||
$value = function () use (&$i) {
|
||||
return $i++;
|
||||
};
|
||||
}
|
||||
|
||||
// If the choices are given as recursive array (i.e. with explicit
|
||||
// choice groups), flatten the array. The grouping information is needed
|
||||
// in the view only.
|
||||
$this->flatten($choices, $value, $choicesByValues, $keysByValues, $structuredValues);
|
||||
|
||||
$this->choices = $choicesByValues;
|
||||
$this->originalKeys = $keysByValues;
|
||||
$this->structuredValues = $structuredValues;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,7 +108,23 @@ class ArrayChoiceList implements ChoiceListInterface
|
|||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
return array_map('strval', array_keys($this->choices));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStructuredValues()
|
||||
{
|
||||
return $this->structuredValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOriginalKeys()
|
||||
{
|
||||
return $this->originalKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,17 +135,8 @@ class ArrayChoiceList implements ChoiceListInterface
|
|||
$choices = array();
|
||||
|
||||
foreach ($values as $i => $givenValue) {
|
||||
foreach ($this->values as $j => $value) {
|
||||
if ($value !== (string) $givenValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$choices[$i] = $this->choices[$j];
|
||||
unset($values[$i]);
|
||||
|
||||
if (0 === count($values)) {
|
||||
break 2;
|
||||
}
|
||||
if (isset($this->choices[$givenValue])) {
|
||||
$choices[$i] = $this->choices[$givenValue];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,28 +155,56 @@ class ArrayChoiceList implements ChoiceListInterface
|
|||
$givenValues = array();
|
||||
|
||||
foreach ($choices as $i => $givenChoice) {
|
||||
$givenValues[$i] = (string) call_user_func($this->valueCallback, $givenChoice);
|
||||
$givenValues[$i] = call_user_func($this->valueCallback, $givenChoice);
|
||||
}
|
||||
|
||||
return array_intersect($givenValues, $this->values);
|
||||
return array_intersect($givenValues, array_keys($this->choices));
|
||||
}
|
||||
|
||||
// Otherwise compare choices by identity
|
||||
foreach ($choices as $i => $givenChoice) {
|
||||
foreach ($this->choices as $j => $choice) {
|
||||
if ($choice !== $givenChoice) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$values[$i] = $this->values[$j];
|
||||
unset($choices[$i]);
|
||||
|
||||
if (0 === count($choices)) {
|
||||
break 2;
|
||||
foreach ($this->choices as $value => $choice) {
|
||||
if ($choice === $givenChoice) {
|
||||
$values[$i] = (string) $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an array into the given output variables.
|
||||
*
|
||||
* @param array $choices The array to flatten
|
||||
* @param callable $value The callable for generating choice values
|
||||
* @param array $choicesByValues The flattened choices indexed by the
|
||||
* corresponding values
|
||||
* @param array $keysByValues The original keys indexed by the
|
||||
* corresponding values
|
||||
*
|
||||
* @internal Must not be used by user-land code
|
||||
*/
|
||||
protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues)
|
||||
{
|
||||
if (null === $choicesByValues) {
|
||||
$choicesByValues = array();
|
||||
$keysByValues = array();
|
||||
$structuredValues = array();
|
||||
}
|
||||
|
||||
foreach ($choices as $key => $choice) {
|
||||
if (is_array($choice)) {
|
||||
$this->flatten($choice, $value, $choicesByValues, $keysByValues, $structuredValues[$key]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$choiceValue = (string) call_user_func($value, $choice);
|
||||
$choicesByValues[$choiceValue] = $choice;
|
||||
$keysByValues[$choiceValue] = $key;
|
||||
$structuredValues[$key] = $choiceValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
|||
* @return int|string The choice as PHP array key
|
||||
*
|
||||
* @throws InvalidArgumentException If the choice is not scalar
|
||||
*
|
||||
* @internal Must not be used outside this class
|
||||
*/
|
||||
public static function toArrayKey($choice)
|
||||
{
|
||||
|
@ -89,23 +91,27 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
|||
* If no values are given, the choices are cast to strings and used as
|
||||
* values.
|
||||
*
|
||||
* @param array $choices The selectable choices
|
||||
* @param callable $value The callable for creating the value for a
|
||||
* choice. If `null` is passed, the choices are
|
||||
* cast to strings and used as values
|
||||
* @param array|\Traversable $choices The selectable choices
|
||||
* @param callable $value The callable for creating the value
|
||||
* for a choice. If `null` is passed, the
|
||||
* choices are cast to strings and used
|
||||
* as values
|
||||
*
|
||||
* @throws InvalidArgumentException If the keys of the choices don't match
|
||||
* the keys of the values or if any of the
|
||||
* choices is not scalar
|
||||
*/
|
||||
public function __construct(array $choices, $value = null)
|
||||
public function __construct($choices, $value = null)
|
||||
{
|
||||
$choices = array_map(array(__CLASS__, 'toArrayKey'), $choices);
|
||||
|
||||
// If no values are given, use the choices as values
|
||||
// Since the choices are stored in the collection keys, i.e. they are
|
||||
// strings or integers, we are guaranteed to be able to convert them
|
||||
// to strings
|
||||
if (null === $value) {
|
||||
$value = function ($choice) {
|
||||
return (string) $choice;
|
||||
};
|
||||
|
||||
$this->useChoicesAsValues = true;
|
||||
}
|
||||
|
||||
|
@ -122,7 +128,7 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
|||
|
||||
// If the values are identical to the choices, so we can just return
|
||||
// them to improve performance a little bit
|
||||
return array_map(array(__CLASS__, 'toArrayKey'), array_intersect($values, $this->values));
|
||||
return array_map(array(__CLASS__, 'toArrayKey'), array_intersect($values, array_keys($this->choices)));
|
||||
}
|
||||
|
||||
return parent::getChoicesForValues($values);
|
||||
|
@ -143,4 +149,38 @@ class ArrayKeyChoiceList extends ArrayChoiceList
|
|||
|
||||
return parent::getValuesForChoices($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens and flips an array into the given output variable.
|
||||
*
|
||||
* @param array $choices The array to flatten
|
||||
* @param callable $value The callable for generating choice values
|
||||
* @param array $choicesByValues The flattened choices indexed by the
|
||||
* corresponding values
|
||||
* @param array $keysByValues The original keys indexed by the
|
||||
* corresponding values
|
||||
*
|
||||
* @internal Must not be used by user-land code
|
||||
*/
|
||||
protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues)
|
||||
{
|
||||
if (null === $choicesByValues) {
|
||||
$choicesByValues = array();
|
||||
$keysByValues = array();
|
||||
$structuredValues = array();
|
||||
}
|
||||
|
||||
foreach ($choices as $choice => $key) {
|
||||
if (is_array($key)) {
|
||||
$this->flatten($key, $value, $choicesByValues, $keysByValues, $structuredValues[$choice]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$choiceValue = (string) call_user_func($value, $choice);
|
||||
$choicesByValues[$choiceValue] = $choice;
|
||||
$keysByValues[$choiceValue] = $key;
|
||||
$structuredValues[$key] = $choiceValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,16 +14,13 @@ namespace Symfony\Component\Form\ChoiceList;
|
|||
/**
|
||||
* A list of choices that can be selected in a choice field.
|
||||
*
|
||||
* A choice list assigns string values to each of a list of choices. These
|
||||
* string values are displayed in the "value" attributes in HTML and submitted
|
||||
* back to the server.
|
||||
* A choice list assigns unique string values to each of a list of choices.
|
||||
* These string values are displayed in the "value" attributes in HTML and
|
||||
* submitted back to the server.
|
||||
*
|
||||
* The acceptable data types for the choices depend on the implementation.
|
||||
* Values must always be strings and (within the list) free of duplicates.
|
||||
*
|
||||
* The choices returned by {@link getChoices()} and the values returned by
|
||||
* {@link getValues()} must have the same array indices.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface ChoiceListInterface
|
||||
|
@ -31,23 +28,66 @@ interface ChoiceListInterface
|
|||
/**
|
||||
* Returns all selectable choices.
|
||||
*
|
||||
* The keys of the choices correspond to the keys of the values returned by
|
||||
* {@link getValues()}.
|
||||
*
|
||||
* @return array The selectable choices
|
||||
* @return array The selectable choices indexed by the corresponding values
|
||||
*/
|
||||
public function getChoices();
|
||||
|
||||
/**
|
||||
* Returns the values for the choices.
|
||||
*
|
||||
* The keys of the values correspond to the keys of the choices returned by
|
||||
* {@link getChoices()}.
|
||||
* The values are strings that do not contain duplicates.
|
||||
*
|
||||
* @return string[] The choice values
|
||||
*/
|
||||
public function getValues();
|
||||
|
||||
/**
|
||||
* Returns the values in the structure originally passed to the list.
|
||||
*
|
||||
* Contrary to {@link getValues()}, the result is indexed by the original
|
||||
* keys of the choices. If the original array contained nested arrays, these
|
||||
* nested arrays are represented here as well:
|
||||
*
|
||||
* $form->add('field', 'choice', array(
|
||||
* 'choices' => array(
|
||||
* 'Decided' => array('Yes' => true, 'No' => false),
|
||||
* 'Undecided' => array('Maybe' => null),
|
||||
* ),
|
||||
* ));
|
||||
*
|
||||
* In this example, the result of this method is:
|
||||
*
|
||||
* array(
|
||||
* 'Decided' => array('Yes' => '0', 'No' => '1'),
|
||||
* 'Undecided' => array('Maybe' => '2'),
|
||||
* )
|
||||
*
|
||||
* @return string[] The choice values
|
||||
*/
|
||||
public function getStructuredValues();
|
||||
|
||||
/**
|
||||
* Returns the original keys of the choices.
|
||||
*
|
||||
* The original keys are the keys of the choice array that was passed in the
|
||||
* "choice" option of the choice type. Note that this array may contain
|
||||
* duplicates if the "choice" option contained choice groups:
|
||||
*
|
||||
* $form->add('field', 'choice', array(
|
||||
* 'choices' => array(
|
||||
* 'Decided' => array(true, false),
|
||||
* 'Undecided' => array(null),
|
||||
* ),
|
||||
* ));
|
||||
*
|
||||
* In this example, the original key 0 appears twice, once for `true` and
|
||||
* once for `null`.
|
||||
*
|
||||
* @return int[]|string[] The original choice keys indexed by the
|
||||
* corresponding choice values
|
||||
*/
|
||||
public function getOriginalKeys();
|
||||
|
||||
/**
|
||||
* Returns the choices corresponding to the given values.
|
||||
*
|
||||
|
|
|
@ -65,6 +65,30 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||
return hash('sha256', $namespace.':'.json_encode($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens an array into the given output variable.
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param array $output The flattened output
|
||||
*
|
||||
* @internal Should not be used by user-land code
|
||||
*/
|
||||
private static function flatten(array $array, &$output)
|
||||
{
|
||||
if (null === $output) {
|
||||
$output = array();
|
||||
}
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
self::flatten($value, $output);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorates the given factory.
|
||||
*
|
||||
|
@ -100,7 +124,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||
// We ignore the choice groups for caching. If two choice lists are
|
||||
// requested with the same choices, but a different grouping, the same
|
||||
// choice list is returned.
|
||||
DefaultChoiceListFactory::flatten($choices, $flatChoices);
|
||||
self::flatten($choices, $flatChoices);
|
||||
|
||||
$hash = self::generateHash(array($flatChoices, $value), 'fromChoices');
|
||||
|
||||
|
@ -129,7 +153,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||
// We ignore the choice groups for caching. If two choice lists are
|
||||
// requested with the same choices, but a different grouping, the same
|
||||
// choice list is returned.
|
||||
DefaultChoiceListFactory::flattenFlipped($choices, $flatChoices);
|
||||
self::flatten($choices, $flatChoices);
|
||||
|
||||
$hash = self::generateHash(array($flatChoices, $value), 'fromFlippedChoices');
|
||||
|
||||
|
@ -161,7 +185,6 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||
{
|
||||
// The input is not validated on purpose. This way, the decorated
|
||||
// factory may decide which input to accept and which not.
|
||||
|
||||
$hash = self::generateHash(array($list, $preferredChoices, $label, $index, $groupBy, $attr));
|
||||
|
||||
if (!isset($this->views[$hash])) {
|
||||
|
|
|
@ -69,7 +69,7 @@ interface ChoiceListFactoryInterface
|
|||
* argument.
|
||||
*
|
||||
* @param ChoiceLoaderInterface $loader The choice loader
|
||||
* @param null|callable $value The callable generating the choice
|
||||
* @param null|callable $value The callable generating the choice
|
||||
* values
|
||||
*
|
||||
* @return ChoiceListInterface The choice list
|
||||
|
@ -98,25 +98,20 @@ interface ChoiceListFactoryInterface
|
|||
* The preferred choices can also be passed as array. Each choice that is
|
||||
* contained in that array will be marked as preferred.
|
||||
*
|
||||
* The groups can be passed as a multi-dimensional array. In that case, a
|
||||
* group will be created for each array entry containing a nested array.
|
||||
* For all other entries, the choice for the corresponding key will be
|
||||
* inserted at that position.
|
||||
*
|
||||
* The attributes can be passed as multi-dimensional array. The keys should
|
||||
* match the keys of the choices. The values should be arrays of HTML
|
||||
* attributes that should be added to the respective choice.
|
||||
*
|
||||
* @param ChoiceListInterface $list The choice list
|
||||
* @param null|array|callable $preferredChoices The preferred choices
|
||||
* @param null|callable $label The callable generating
|
||||
* the choice labels
|
||||
* @param null|callable $index The callable generating
|
||||
* the view indices
|
||||
* @param null|array|\Traversable|callable $groupBy The callable generating
|
||||
* the group names
|
||||
* @param null|array|callable $attr The callable generating
|
||||
* the HTML attributes
|
||||
* @param ChoiceListInterface $list The choice list
|
||||
* @param null|array|callable $preferredChoices The preferred choices
|
||||
* @param null|callable $label The callable generating the
|
||||
* choice labels
|
||||
* @param null|callable $index The callable generating the
|
||||
* view indices
|
||||
* @param null|callable $groupBy The callable generating the
|
||||
* group names
|
||||
* @param null|array|callable $attr The callable generating the
|
||||
* HTML attributes
|
||||
*
|
||||
* @return ChoiceListView The choice list view
|
||||
*/
|
||||
|
|
|
@ -15,11 +15,11 @@ use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList;
|
|||
use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface as LegacyChoiceListInterface;
|
||||
use Symfony\Component\Form\Extension\Core\View\ChoiceView as LegacyChoiceView;
|
||||
|
||||
/**
|
||||
|
@ -29,72 +29,12 @@ use Symfony\Component\Form\Extension\Core\View\ChoiceView as LegacyChoiceView;
|
|||
*/
|
||||
class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Flattens an array into the given output variable.
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param array $output The flattened output
|
||||
*
|
||||
* @internal Should not be used by user-land code
|
||||
*/
|
||||
public static function flatten(array $array, &$output)
|
||||
{
|
||||
if (null === $output) {
|
||||
$output = array();
|
||||
}
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
self::flatten($value, $output);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens and flips an array into the given output variable.
|
||||
*
|
||||
* During the flattening, the keys and values of the input array are
|
||||
* flipped.
|
||||
*
|
||||
* @param array $array The array to flatten
|
||||
* @param array $output The flattened output
|
||||
*
|
||||
* @internal Should not be used by user-land code
|
||||
*/
|
||||
public static function flattenFlipped(array $array, &$output)
|
||||
{
|
||||
if (null === $output) {
|
||||
$output = array();
|
||||
}
|
||||
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
self::flattenFlipped($value, $output);
|
||||
continue;
|
||||
}
|
||||
|
||||
$output[$value] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createListFromChoices($choices, $value = null)
|
||||
{
|
||||
if ($choices instanceof \Traversable) {
|
||||
$choices = iterator_to_array($choices);
|
||||
}
|
||||
|
||||
// If the choices are given as recursive array (i.e. with explicit
|
||||
// choice groups), flatten the array. The grouping information is needed
|
||||
// in the view only.
|
||||
self::flatten($choices, $flatChoices);
|
||||
|
||||
return new ArrayChoiceList($flatChoices, $value);
|
||||
return new ArrayChoiceList($choices, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,26 +45,7 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
*/
|
||||
public function createListFromFlippedChoices($choices, $value = null)
|
||||
{
|
||||
if ($choices instanceof \Traversable) {
|
||||
$choices = iterator_to_array($choices);
|
||||
}
|
||||
|
||||
// If the choices are given as recursive array (i.e. with explicit
|
||||
// choice groups), flatten the array. The grouping information is needed
|
||||
// in the view only.
|
||||
self::flattenFlipped($choices, $flatChoices);
|
||||
|
||||
// If no values are given, use the choices as values
|
||||
// Since the choices are stored in the collection keys, i.e. they are
|
||||
// strings or integers, we are guaranteed to be able to convert them
|
||||
// to strings
|
||||
if (null === $value) {
|
||||
$value = function ($choice) {
|
||||
return (string) $choice;
|
||||
};
|
||||
}
|
||||
|
||||
return new ArrayKeyChoiceList($flatChoices, $value);
|
||||
return new ArrayKeyChoiceList($choices, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,22 +62,24 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
|
||||
{
|
||||
// Backwards compatibility
|
||||
if ($list instanceof LegacyChoiceListInterface && empty($preferredChoices)
|
||||
if ($list instanceof LegacyChoiceListAdapter && empty($preferredChoices)
|
||||
&& null === $label && null === $index && null === $groupBy && null === $attr) {
|
||||
$mapToNonLegacyChoiceView = function (LegacyChoiceView $choiceView) {
|
||||
return new ChoiceView($choiceView->data, $choiceView->value, $choiceView->label);
|
||||
};
|
||||
|
||||
$adaptedList = $list->getAdaptedList();
|
||||
|
||||
return new ChoiceListView(
|
||||
array_map($mapToNonLegacyChoiceView, $list->getRemainingViews()),
|
||||
array_map($mapToNonLegacyChoiceView, $list->getPreferredViews())
|
||||
array_map($mapToNonLegacyChoiceView, $adaptedList->getRemainingViews()),
|
||||
array_map($mapToNonLegacyChoiceView, $adaptedList->getPreferredViews())
|
||||
);
|
||||
}
|
||||
|
||||
$preferredViews = array();
|
||||
$otherViews = array();
|
||||
$choices = $list->getChoices();
|
||||
$values = $list->getValues();
|
||||
$keys = $list->getOriginalKeys();
|
||||
|
||||
if (!is_callable($preferredChoices) && !empty($preferredChoices)) {
|
||||
$preferredChoices = function ($choice) use ($preferredChoices) {
|
||||
|
@ -169,36 +92,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
$index = 0;
|
||||
}
|
||||
|
||||
// If $groupBy is not given, no grouping is done
|
||||
if (empty($groupBy)) {
|
||||
foreach ($choices as $key => $choice) {
|
||||
self::addChoiceView(
|
||||
$choice,
|
||||
$key,
|
||||
$label,
|
||||
$values,
|
||||
$index,
|
||||
$attr,
|
||||
$preferredChoices,
|
||||
$preferredViews,
|
||||
$otherViews
|
||||
);
|
||||
}
|
||||
|
||||
return new ChoiceListView($otherViews, $preferredViews);
|
||||
}
|
||||
|
||||
// If $groupBy is a callable, choices are added to the group with the
|
||||
// name returned by the callable. If the callable returns null, the
|
||||
// choice is not added to any group
|
||||
if (is_callable($groupBy)) {
|
||||
foreach ($choices as $key => $choice) {
|
||||
foreach ($choices as $value => $choice) {
|
||||
self::addChoiceViewGroupedBy(
|
||||
$groupBy,
|
||||
$choice,
|
||||
$key,
|
||||
(string) $value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$preferredChoices,
|
||||
|
@ -207,13 +111,12 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
);
|
||||
}
|
||||
} else {
|
||||
// If $groupBy is passed as array, use that array as template for
|
||||
// constructing the groups
|
||||
// Otherwise use the original structure of the choices
|
||||
self::addChoiceViewsGroupedBy(
|
||||
$groupBy,
|
||||
$list->getStructuredValues(),
|
||||
$label,
|
||||
$choices,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$preferredChoices,
|
||||
|
@ -239,15 +142,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
return new ChoiceListView($otherViews, $preferredViews);
|
||||
}
|
||||
|
||||
private static function addChoiceView($choice, $key, $label, $values, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
private static function addChoiceView($choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
{
|
||||
$value = $values[$key];
|
||||
// $value may be an integer or a string, since it's stored in the array
|
||||
// keys. We want to guarantee it's a string though.
|
||||
$key = $keys[$value];
|
||||
$nextIndex = is_int($index) ? $index++ : call_user_func($index, $choice, $key, $value);
|
||||
|
||||
$view = new ChoiceView(
|
||||
$choice,
|
||||
$value,
|
||||
// If the labels are null, use the choice key by default
|
||||
// If the labels are null, use the original choice key by default
|
||||
null === $label ? (string) $key : (string) call_user_func($label, $choice, $key, $value),
|
||||
// The attributes may be a callable or a mapping from choice indices
|
||||
// to nested arrays
|
||||
|
@ -262,19 +167,19 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
}
|
||||
}
|
||||
|
||||
private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $values, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
{
|
||||
foreach ($groupBy as $key => $content) {
|
||||
foreach ($groupBy as $key => $value) {
|
||||
// Add the contents of groups to new ChoiceGroupView instances
|
||||
if (is_array($content)) {
|
||||
if (is_array($value)) {
|
||||
$preferredViewsForGroup = array();
|
||||
$otherViewsForGroup = array();
|
||||
|
||||
self::addChoiceViewsGroupedBy(
|
||||
$content,
|
||||
$value,
|
||||
$label,
|
||||
$choices,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
|
@ -295,10 +200,10 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
|
||||
// Add ungrouped items directly
|
||||
self::addChoiceView(
|
||||
$choices[$key],
|
||||
$key,
|
||||
$choices[$value],
|
||||
$value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
|
@ -308,17 +213,17 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
}
|
||||
}
|
||||
|
||||
private static function addChoiceViewGroupedBy($groupBy, $choice, $key, $label, $values, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
|
||||
{
|
||||
$groupLabel = call_user_func($groupBy, $choice, $key, $values[$key]);
|
||||
$groupLabel = call_user_func($groupBy, $choice, $keys[$value], $value);
|
||||
|
||||
if (null === $groupLabel) {
|
||||
// If the callable returns null, don't group the choice
|
||||
self::addChoiceView(
|
||||
$choice,
|
||||
$key,
|
||||
$value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
|
@ -329,6 +234,8 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
return;
|
||||
}
|
||||
|
||||
$groupLabel = (string) $groupLabel;
|
||||
|
||||
// Initialize the group views if necessary. Unnnecessarily built group
|
||||
// views will be cleaned up at the end of createView()
|
||||
if (!isset($preferredViews[$groupLabel])) {
|
||||
|
@ -338,9 +245,9 @@ class DefaultChoiceListFactory implements ChoiceListFactoryInterface
|
|||
|
||||
self::addChoiceView(
|
||||
$choice,
|
||||
$key,
|
||||
$value,
|
||||
$label,
|
||||
$values,
|
||||
$keys,
|
||||
$index,
|
||||
$attr,
|
||||
$isPreferred,
|
||||
|
|
|
@ -54,8 +54,8 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
|||
/**
|
||||
* Decorates the given factory.
|
||||
*
|
||||
* @param ChoiceListFactoryInterface $decoratedFactory The decorated factory
|
||||
* @param null|PropertyAccessorInterface $propertyAccessor The used property accessor
|
||||
* @param ChoiceListFactoryInterface $decoratedFactory The decorated factory
|
||||
* @param null|PropertyAccessorInterface $propertyAccessor The used property accessor
|
||||
*/
|
||||
public function __construct(ChoiceListFactoryInterface $decoratedFactory, PropertyAccessorInterface $propertyAccessor = null)
|
||||
{
|
||||
|
@ -98,8 +98,6 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
|||
if (is_object($choice) || is_array($choice)) {
|
||||
return $accessor->getValue($choice, $value);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -128,9 +126,9 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param ChoiceLoaderInterface $loader The choice loader
|
||||
* @param null|callable|string|PropertyPath $value The callable or path for
|
||||
* generating the choice values
|
||||
* @param ChoiceLoaderInterface $loader The choice loader
|
||||
* @param null|callable|string|PropertyPath $value The callable or path for
|
||||
* generating the choice values
|
||||
*
|
||||
* @return ChoiceListInterface The choice list
|
||||
*/
|
||||
|
|
|
@ -43,13 +43,6 @@ class LazyChoiceList implements ChoiceListInterface
|
|||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* Whether to use the value callback to compare choices.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $compareByValue;
|
||||
|
||||
/**
|
||||
* @var ChoiceListInterface|null
|
||||
*/
|
||||
|
@ -66,11 +59,10 @@ class LazyChoiceList implements ChoiceListInterface
|
|||
* @param null|callable $value The callable generating the choice
|
||||
* values
|
||||
*/
|
||||
public function __construct(ChoiceLoaderInterface $loader, $value = null, $compareByValue = false)
|
||||
public function __construct(ChoiceLoaderInterface $loader, $value = null)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->value = $value;
|
||||
$this->compareByValue = $compareByValue;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,6 +89,30 @@ class LazyChoiceList implements ChoiceListInterface
|
|||
return $this->loadedList->getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStructuredValues()
|
||||
{
|
||||
if (!$this->loadedList) {
|
||||
$this->loadedList = $this->loader->loadChoiceList($this->value);
|
||||
}
|
||||
|
||||
return $this->loadedList->getStructuredValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOriginalKeys()
|
||||
{
|
||||
if (!$this->loadedList) {
|
||||
$this->loadedList = $this->loader->loadChoiceList($this->value);
|
||||
}
|
||||
|
||||
return $this->loadedList->getOriginalKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface as LegacyChoiceListInterface;
|
||||
|
||||
/**
|
||||
* Adapts a legacy choice list implementation to {@link ChoiceListInterface}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @deprecated Added for backwards compatibility in Symfony 2.7, to be
|
||||
* removed in Symfony 3.0.
|
||||
*/
|
||||
class LegacyChoiceListAdapter implements ChoiceListInterface
|
||||
{
|
||||
/**
|
||||
* @var LegacyChoiceListInterface
|
||||
*/
|
||||
private $adaptedList;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $choices;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $values;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
private $structuredValues;
|
||||
|
||||
/**
|
||||
* Adapts a legacy choice list to {@link ChoiceListInterface}.
|
||||
*
|
||||
* @param LegacyChoiceListInterface $adaptedList The adapted list
|
||||
*/
|
||||
public function __construct(LegacyChoiceListInterface $adaptedList)
|
||||
{
|
||||
$this->adaptedList = $adaptedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getChoices()
|
||||
{
|
||||
if (!$this->choices) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
if (!$this->values) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getStructuredValues()
|
||||
{
|
||||
if (!$this->structuredValues) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return $this->structuredValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOriginalKeys()
|
||||
{
|
||||
if (!$this->structuredValues) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return array_flip($this->structuredValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getChoicesForValues(array $values)
|
||||
{
|
||||
return $this->adaptedList->getChoicesForValues($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValuesForChoices(array $choices)
|
||||
{
|
||||
return $this->adaptedList->getValuesForChoices($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the adapted choice list.
|
||||
*
|
||||
* @return LegacyChoiceListInterface The adapted list
|
||||
*/
|
||||
public function getAdaptedList()
|
||||
{
|
||||
return $this->adaptedList;
|
||||
}
|
||||
|
||||
private function initialize()
|
||||
{
|
||||
$this->choices = array();
|
||||
$this->values = array();
|
||||
$this->structuredValues = $this->adaptedList->getValues();
|
||||
|
||||
$innerChoices = $this->adaptedList->getChoices();
|
||||
|
||||
foreach ($innerChoices as $index => $choice) {
|
||||
$value = $this->structuredValues[$index];
|
||||
$this->values[] = $value;
|
||||
$this->choices[$value] = $choice;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,9 +11,6 @@
|
|||
|
||||
namespace Symfony\Component\Form\Extension\Core\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface as BaseChoiceListInterface;
|
||||
use Symfony\Component\Form\FormConfigBuilder;
|
||||
|
||||
/**
|
||||
* Contains choices that can be selected in a form field.
|
||||
*
|
||||
|
@ -30,10 +27,24 @@ use Symfony\Component\Form\FormConfigBuilder;
|
|||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @deprecated since version 2.7, to be removed in 3.0.
|
||||
* Use {@link BaseChoiceListInterface} instead.
|
||||
* Use {@link \Symfony\Component\Form\ChoiceList\ChoiceListInterface} instead.
|
||||
*/
|
||||
interface ChoiceListInterface extends BaseChoiceListInterface
|
||||
interface ChoiceListInterface
|
||||
{
|
||||
/**
|
||||
* Returns the list of choices.
|
||||
*
|
||||
* @return array The choices with their indices as keys
|
||||
*/
|
||||
public function getChoices();
|
||||
|
||||
/**
|
||||
* Returns the values for the choices.
|
||||
*
|
||||
* @return array The values with the corresponding choice indices as keys
|
||||
*/
|
||||
public function getValues();
|
||||
|
||||
/**
|
||||
* Returns the choice views of the preferred choices as nested array with
|
||||
* the choice groups as top-level keys.
|
||||
|
@ -84,6 +95,37 @@ interface ChoiceListInterface extends BaseChoiceListInterface
|
|||
*/
|
||||
public function getRemainingViews();
|
||||
|
||||
/**
|
||||
* Returns the choices corresponding to the given values.
|
||||
*
|
||||
* The choices can have any data type.
|
||||
*
|
||||
* The choices must be returned with the same keys and in the same order
|
||||
* as the corresponding values in the given array.
|
||||
*
|
||||
* @param array $values An array of choice values. Not existing values in
|
||||
* this array are ignored
|
||||
*
|
||||
* @return array An array of choices with ascending, 0-based numeric keys
|
||||
*/
|
||||
public function getChoicesForValues(array $values);
|
||||
|
||||
/**
|
||||
* Returns the values corresponding to the given choices.
|
||||
*
|
||||
* The values must be strings.
|
||||
*
|
||||
* The values must be returned with the same keys and in the same order
|
||||
* as the corresponding choices in the given array.
|
||||
*
|
||||
* @param array $choices An array of choices. Not existing choices in this
|
||||
* array are ignored
|
||||
*
|
||||
* @return array An array of choice values with ascending, 0-based numeric
|
||||
* keys
|
||||
*/
|
||||
public function getValuesForChoices(array $choices);
|
||||
|
||||
/**
|
||||
* Returns the indices corresponding to the given choices.
|
||||
*
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Extension\Core\Type;
|
|||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
||||
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||
|
@ -27,6 +28,7 @@ use Symfony\Component\Form\FormEvent;
|
|||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface as LegacyChoiceListInterface;
|
||||
use Symfony\Component\Form\Extension\Core\EventListener\MergeCollectionListener;
|
||||
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
|
||||
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
|
||||
|
@ -259,6 +261,10 @@ class ChoiceType extends AbstractType
|
|||
if ($choiceList) {
|
||||
@trigger_error('The "choice_list" option is deprecated since version 2.7 and will be removed in 3.0. Use "choice_loader" instead.', E_USER_DEPRECATED);
|
||||
|
||||
if ($choiceList instanceof LegacyChoiceListInterface) {
|
||||
return new LegacyChoiceListAdapter($choiceList);
|
||||
}
|
||||
|
||||
return $choiceList;
|
||||
}
|
||||
|
||||
|
@ -338,7 +344,7 @@ class ChoiceType extends AbstractType
|
|||
$resolver->setNormalizer('placeholder', $placeholderNormalizer);
|
||||
$resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer);
|
||||
|
||||
$resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface'));
|
||||
$resolver->setAllowedTypes('choice_list', array('null', 'Symfony\Component\Form\ChoiceList\ChoiceListInterface', 'Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface'));
|
||||
$resolver->setAllowedTypes('choices', array('null', 'array', '\Traversable'));
|
||||
$resolver->setAllowedTypes('choice_translation_domain', array('null', 'bool', 'string'));
|
||||
$resolver->setAllowedTypes('choices_as_values', 'bool');
|
||||
|
|
|
@ -146,6 +146,10 @@ class DateType extends AbstractType
|
|||
|
||||
// remove special characters unless the format was explicitly specified
|
||||
if (!is_string($options['format'])) {
|
||||
// remove quoted strings first
|
||||
$pattern = preg_replace('/\'[^\']+\'/', '', $pattern);
|
||||
|
||||
// remove remaining special chars
|
||||
$pattern = preg_replace('/[^yMd]+/', '', $pattern);
|
||||
}
|
||||
|
||||
|
|
|
@ -931,7 +931,7 @@ class Form implements \IteratorAggregate, FormInterface
|
|||
$child->setParent($this);
|
||||
|
||||
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
|
||||
$iterator = new InheritDataAwareIterator(new \ArrayIterator(array($child)));
|
||||
$iterator = new InheritDataAwareIterator(new \ArrayIterator(array($child->getName() => $child)));
|
||||
$iterator = new \RecursiveIteratorIterator($iterator);
|
||||
$this->config->getDataMapper()->mapDataToForms($viewData, $iterator);
|
||||
}
|
||||
|
|
|
@ -200,27 +200,35 @@ class ResolvedFormType implements ResolvedFormTypeInterface
|
|||
|
||||
$this->innerType->setDefaultOptions($this->optionsResolver);
|
||||
|
||||
$reflector = new \ReflectionMethod($this->innerType, 'setDefaultOptions');
|
||||
$isOldOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractType';
|
||||
if (method_exists($this->innerType, 'configureOptions')) {
|
||||
$reflector = new \ReflectionMethod($this->innerType, 'setDefaultOptions');
|
||||
$isOldOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractType';
|
||||
|
||||
$reflector = new \ReflectionMethod($this->innerType, 'configureOptions');
|
||||
$isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractType';
|
||||
$reflector = new \ReflectionMethod($this->innerType, 'configureOptions');
|
||||
$isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractType';
|
||||
|
||||
if ($isOldOverwritten && !$isNewOverwritten) {
|
||||
@trigger_error(get_class($this->innerType).': The FormTypeInterface::setDefaultOptions() method is deprecated since version 2.7 and will be removed in 3.0. Use configureOptions() instead. This method will be added to the FormTypeInterface with Symfony 3.0.', E_USER_DEPRECATED);
|
||||
if ($isOldOverwritten && !$isNewOverwritten) {
|
||||
@trigger_error(get_class($this->innerType).': The FormTypeInterface::setDefaultOptions() method is deprecated since version 2.7 and will be removed in 3.0. Use configureOptions() instead. This method will be added to the FormTypeInterface with Symfony 3.0.', E_USER_DEPRECATED);
|
||||
}
|
||||
} else {
|
||||
@trigger_error(get_class($this->innerType).': The FormTypeInterface::configureOptions() method will be added in Symfony 3.0. You should extend AbstractType or implement it in your classes.', E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
foreach ($this->typeExtensions as $extension) {
|
||||
$extension->setDefaultOptions($this->optionsResolver);
|
||||
|
||||
$reflector = new \ReflectionMethod($extension, 'setDefaultOptions');
|
||||
$isOldOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractTypeExtension';
|
||||
if (method_exists($extension, 'configureOptions')) {
|
||||
$reflector = new \ReflectionMethod($extension, 'setDefaultOptions');
|
||||
$isOldOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractTypeExtension';
|
||||
|
||||
$reflector = new \ReflectionMethod($extension, 'configureOptions');
|
||||
$isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractTypeExtension';
|
||||
$reflector = new \ReflectionMethod($extension, 'configureOptions');
|
||||
$isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Symfony\Component\Form\AbstractTypeExtension';
|
||||
|
||||
if ($isOldOverwritten && !$isNewOverwritten) {
|
||||
@trigger_error(get_class($extension).': The FormTypeExtensionInterface::setDefaultOptions() method is deprecated since version 2.7 and will be removed in 3.0. Use configureOptions() instead. This method will be added to the FormTypeExtensionInterface with Symfony 3.0.', E_USER_DEPRECATED);
|
||||
if ($isOldOverwritten && !$isNewOverwritten) {
|
||||
@trigger_error(get_class($extension).': The FormTypeExtensionInterface::setDefaultOptions() method is deprecated since version 2.7 and will be removed in 3.0. Use configureOptions() instead. This method will be added to the FormTypeExtensionInterface with Symfony 3.0.', E_USER_DEPRECATED);
|
||||
}
|
||||
} else {
|
||||
@trigger_error(get_class($this->innerType).': The FormTypeExtensionInterface::configureOptions() method will be added in Symfony 3.0. You should extend AbstractTypeExtension or implement it in your classes.', E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,6 +231,29 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
|||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceWithoutTranslation()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'choice_translation_domain' => false,
|
||||
));
|
||||
|
||||
$this->assertWidgetMatchesXpath($form->createView(), array('attr' => array('class' => 'my&class')),
|
||||
'/select
|
||||
[@name="name"]
|
||||
[@class="my&class form-control"]
|
||||
[not(@required)]
|
||||
[
|
||||
./option[@value="&a"][@selected="selected"][.="Choice&A"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
|
||||
]
|
||||
[count(./option)=2]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
|
@ -359,7 +382,7 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
|||
[@class="my&class form-control"]
|
||||
[not(@required)]
|
||||
[
|
||||
./option[@value=""][.="[trans][/trans]"]
|
||||
./option[@value=""][.=""]
|
||||
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
|
||||
]
|
||||
|
@ -383,7 +406,7 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
|||
[@class="my&class form-control"]
|
||||
[not(@required)]
|
||||
[
|
||||
./option[@value=""][.="[trans][/trans]"]
|
||||
./option[@value=""][.=""]
|
||||
/following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
|
||||
]
|
||||
|
@ -457,7 +480,7 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
|||
[@class="my&class form-control"]
|
||||
[@required="required"]
|
||||
[
|
||||
./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]
|
||||
./option[@value=""][not(@selected)][not(@disabled)][.=""]
|
||||
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
|
||||
]
|
||||
|
@ -629,6 +652,42 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
|||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceExpandedWithoutTranslation()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
|
||||
'multiple' => false,
|
||||
'expanded' => true,
|
||||
'choice_translation_domain' => false,
|
||||
));
|
||||
|
||||
$this->assertWidgetMatchesXpath($form->createView(), array(),
|
||||
'/div
|
||||
[
|
||||
./div
|
||||
[@class="radio"]
|
||||
[
|
||||
./label
|
||||
[.="Choice&A"]
|
||||
[
|
||||
./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
|
||||
]
|
||||
]
|
||||
/following-sibling::div
|
||||
[@class="radio"]
|
||||
[
|
||||
./label
|
||||
[.="Choice&B"]
|
||||
[
|
||||
./input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
|
||||
]
|
||||
]
|
||||
/following-sibling::input[@type="hidden"][@id="name__token"][@class="form-control"]
|
||||
]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceExpandedAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
|
@ -792,6 +851,52 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
|||
);
|
||||
}
|
||||
|
||||
public function testMultipleChoiceExpandedWithoutTranslation()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
|
||||
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'required' => true,
|
||||
'choice_translation_domain' => false,
|
||||
));
|
||||
|
||||
$this->assertWidgetMatchesXpath($form->createView(), array(),
|
||||
'/div
|
||||
[
|
||||
./div
|
||||
[@class="checkbox"]
|
||||
[
|
||||
./label
|
||||
[.="Choice&A"]
|
||||
[
|
||||
./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
|
||||
]
|
||||
]
|
||||
/following-sibling::div
|
||||
[@class="checkbox"]
|
||||
[
|
||||
./label
|
||||
[.="Choice&B"]
|
||||
[
|
||||
./input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
|
||||
]
|
||||
]
|
||||
/following-sibling::div
|
||||
[@class="checkbox"]
|
||||
[
|
||||
./label
|
||||
[.="Choice&C"]
|
||||
[
|
||||
./input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
|
||||
]
|
||||
]
|
||||
/following-sibling::input[@type="hidden"][@id="name__token"][@class="form-control"]
|
||||
]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testMultipleChoiceExpandedAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
|
||||
|
@ -1278,17 +1383,17 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
|
|||
./select
|
||||
[@id="name_month"]
|
||||
[@class="form-control"]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.=""]]
|
||||
[./option[@value="1"][@selected="selected"]]
|
||||
/following-sibling::select
|
||||
[@id="name_day"]
|
||||
[@class="form-control"]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.=""]]
|
||||
[./option[@value="1"][@selected="selected"]]
|
||||
/following-sibling::select
|
||||
[@id="name_year"]
|
||||
[@class="form-control"]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.=""]]
|
||||
[./option[@value="1950"][@selected="selected"]]
|
||||
]
|
||||
[count(./select)=3]
|
||||
|
|
|
@ -168,6 +168,20 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
);
|
||||
}
|
||||
|
||||
public function testLabelWithoutTranslation()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'text', null, array(
|
||||
'translation_domain' => false,
|
||||
));
|
||||
|
||||
$this->assertMatchesXpath($this->renderLabel($form->createView()),
|
||||
'/label
|
||||
[@for="name"]
|
||||
[.="Name"]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testLabelOnForm()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'date');
|
||||
|
@ -513,6 +527,28 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceWithoutTranslation()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'choice_translation_domain' => false,
|
||||
));
|
||||
|
||||
$this->assertWidgetMatchesXpath($form->createView(), array(),
|
||||
'/select
|
||||
[@name="name"]
|
||||
[not(@required)]
|
||||
[
|
||||
./option[@value="&a"][@selected="selected"][.="Choice&A"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
|
||||
]
|
||||
[count(./option)=2]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
|
@ -635,7 +671,7 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
[@name="name"]
|
||||
[not(@required)]
|
||||
[
|
||||
./option[@value=""][.="[trans][/trans]"]
|
||||
./option[@value=""][.=""]
|
||||
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
|
||||
]
|
||||
|
@ -658,7 +694,7 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
[@name="name"]
|
||||
[not(@required)]
|
||||
[
|
||||
./option[@value=""][.="[trans][/trans]"]
|
||||
./option[@value=""][.=""]
|
||||
/following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
|
||||
]
|
||||
|
@ -735,7 +771,7 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
[@name="name"]
|
||||
[@required="required"]
|
||||
[
|
||||
./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]
|
||||
./option[@value=""][not(@selected)][not(@disabled)][.=""]
|
||||
/following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
|
||||
/following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
|
||||
]
|
||||
|
@ -889,6 +925,29 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceExpandedWithoutTranslation()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
|
||||
'multiple' => false,
|
||||
'expanded' => true,
|
||||
'choice_translation_domain' => false,
|
||||
));
|
||||
|
||||
$this->assertWidgetMatchesXpath($form->createView(), array(),
|
||||
'/div
|
||||
[
|
||||
./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
|
||||
/following-sibling::label[@for="name_0"][.="Choice&A"]
|
||||
/following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
|
||||
/following-sibling::label[@for="name_1"][.="Choice&B"]
|
||||
/following-sibling::input[@type="hidden"][@id="name__token"]
|
||||
]
|
||||
[count(./input)=3]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testSingleChoiceExpandedAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', '&a', array(
|
||||
|
@ -986,6 +1045,32 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
);
|
||||
}
|
||||
|
||||
public function testMultipleChoiceExpandedWithoutTranslation()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
|
||||
'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
|
||||
'multiple' => true,
|
||||
'expanded' => true,
|
||||
'required' => true,
|
||||
'choice_translation_domain' => false,
|
||||
));
|
||||
|
||||
$this->assertWidgetMatchesXpath($form->createView(), array(),
|
||||
'/div
|
||||
[
|
||||
./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
|
||||
/following-sibling::label[@for="name_0"][.="Choice&A"]
|
||||
/following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
|
||||
/following-sibling::label[@for="name_1"][.="Choice&B"]
|
||||
/following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
|
||||
/following-sibling::label[@for="name_2"][.="Choice&C"]
|
||||
/following-sibling::input[@type="hidden"][@id="name__token"]
|
||||
]
|
||||
[count(./input)=4]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
||||
public function testMultipleChoiceExpandedAttributes()
|
||||
{
|
||||
$form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
|
||||
|
@ -1442,15 +1527,15 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
|||
[
|
||||
./select
|
||||
[@id="name_month"]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.=""]]
|
||||
[./option[@value="1"][@selected="selected"]]
|
||||
/following-sibling::select
|
||||
[@id="name_day"]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.=""]]
|
||||
[./option[@value="1"][@selected="selected"]]
|
||||
/following-sibling::select
|
||||
[@id="name_year"]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
|
||||
[./option[@value=""][not(@selected)][not(@disabled)][.=""]]
|
||||
[./option[@value="1950"][@selected="selected"]]
|
||||
]
|
||||
[count(./select)=3]
|
||||
|
|
|
@ -31,6 +31,16 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
protected $values;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $structuredValues;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $keys;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
|
@ -71,25 +81,52 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
protected $value4;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key1;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key2;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key3;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $key4;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->list = $this->createChoiceList();
|
||||
|
||||
$this->choices = $this->getChoices();
|
||||
$choices = $this->getChoices();
|
||||
|
||||
$this->values = $this->getValues();
|
||||
$this->structuredValues = array_combine(array_keys($choices), $this->values);
|
||||
$this->choices = array_combine($this->values, $choices);
|
||||
$this->keys = array_combine($this->values, array_keys($choices));
|
||||
|
||||
// allow access to the individual entries without relying on their indices
|
||||
reset($this->choices);
|
||||
reset($this->values);
|
||||
reset($this->keys);
|
||||
|
||||
for ($i = 1; $i <= 4; ++$i) {
|
||||
$this->{'choice'.$i} = current($this->choices);
|
||||
$this->{'value'.$i} = current($this->values);
|
||||
$this->{'key'.$i} = current($this->keys);
|
||||
|
||||
next($this->choices);
|
||||
next($this->values);
|
||||
next($this->keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,6 +140,16 @@ abstract class AbstractChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertSame($this->values, $this->list->getValues());
|
||||
}
|
||||
|
||||
public function testGetStructuredValues()
|
||||
{
|
||||
$this->assertSame($this->values, $this->list->getStructuredValues());
|
||||
}
|
||||
|
||||
public function testGetOriginalKeys()
|
||||
{
|
||||
$this->assertSame($this->keys, $this->list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testGetChoicesForValues()
|
||||
{
|
||||
$values = array($this->value1, $this->value2);
|
||||
|
|
|
@ -29,8 +29,6 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
|
|||
|
||||
protected function createChoiceList()
|
||||
{
|
||||
$i = 0;
|
||||
|
||||
return new ArrayChoiceList($this->getChoices());
|
||||
}
|
||||
|
||||
|
@ -60,11 +58,31 @@ class ArrayChoiceListTest extends AbstractChoiceListTest
|
|||
|
||||
$choiceList = new ArrayChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 'baz'), $callback);
|
||||
|
||||
$this->assertSame(array(2 => ':foo', 7 => ':bar', 10 => ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo', ':bar', ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo' => 'foo', ':bar' => 'bar', ':baz' => 'baz'), $choiceList->getChoices());
|
||||
$this->assertSame(array(':foo' => 2, ':bar' => 7, ':baz' => 10), $choiceList->getOriginalKeys());
|
||||
$this->assertSame(array(1 => 'foo', 2 => 'baz'), $choiceList->getChoicesForValues(array(1 => ':foo', 2 => ':baz')));
|
||||
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz')));
|
||||
}
|
||||
|
||||
public function testCreateChoiceListWithGroupedChoices()
|
||||
{
|
||||
$choiceList = new ArrayChoiceList(array(
|
||||
'Group 1' => array('A' => 'a', 'B' => 'b'),
|
||||
'Group 2' => array('C' => 'c', 'D' => 'd'),
|
||||
));
|
||||
|
||||
$this->assertSame(array('0', '1', '2', '3'), $choiceList->getValues());
|
||||
$this->assertSame(array(
|
||||
'Group 1' => array('A' => '0', 'B' => '1'),
|
||||
'Group 2' => array('C' => '2', 'D' => '3'),
|
||||
), $choiceList->getStructuredValues());
|
||||
$this->assertSame(array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd'), $choiceList->getChoices());
|
||||
$this->assertSame(array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D'), $choiceList->getOriginalKeys());
|
||||
$this->assertSame(array(1 => 'a', 2 => 'b'), $choiceList->getChoicesForValues(array(1 => '0', 2 => '1')));
|
||||
$this->assertSame(array(1 => '0', 2 => '1'), $choiceList->getValuesForChoices(array(1 => 'a', 2 => 'b')));
|
||||
}
|
||||
|
||||
public function testCompareChoicesByIdentityByDefault()
|
||||
{
|
||||
$callback = function ($choice) {
|
||||
|
|
|
@ -29,7 +29,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||
|
||||
protected function createChoiceList()
|
||||
{
|
||||
return new ArrayKeyChoiceList($this->getChoices());
|
||||
return new ArrayKeyChoiceList(array_flip($this->getChoices()));
|
||||
}
|
||||
|
||||
protected function getChoices()
|
||||
|
@ -44,9 +44,11 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||
|
||||
public function testUseChoicesAsValuesByDefault()
|
||||
{
|
||||
$list = new ArrayKeyChoiceList(array(1 => '', 3 => 0, 7 => '1', 10 => 1.23));
|
||||
$list = new ArrayKeyChoiceList(array('' => 'Empty', 0 => 'Zero', 1 => 'One', '1.23' => 'Float'));
|
||||
|
||||
$this->assertSame(array(1 => '', 3 => '0', 7 => '1', 10 => '1.23'), $list->getValues());
|
||||
$this->assertSame(array('', '0', '1', '1.23'), $list->getValues());
|
||||
$this->assertSame(array('' => '', 0 => 0, 1 => 1, '1.23' => '1.23'), $list->getChoices());
|
||||
$this->assertSame(array('' => 'Empty', 0 => 'Zero', 1 => 'One', '1.23' => 'Float'), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testNoChoices()
|
||||
|
@ -102,33 +104,22 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||
public function provideConvertibleChoices()
|
||||
{
|
||||
return array(
|
||||
array(array(0), array(0)),
|
||||
array(array(1), array(1)),
|
||||
array(array('0'), array(0)),
|
||||
array(array('1'), array(1)),
|
||||
array(array('1.23'), array('1.23')),
|
||||
array(array('foobar'), array('foobar')),
|
||||
array(array(0 => 'Label'), array(0 => 0)),
|
||||
array(array(1 => 'Label'), array(1 => 1)),
|
||||
array(array('1.23' => 'Label'), array('1.23' => '1.23')),
|
||||
array(array('foobar' => 'Label'), array('foobar' => 'foobar')),
|
||||
// The default value of choice fields is NULL. It should be treated
|
||||
// like the empty value for this choice list type
|
||||
array(array(null), array('')),
|
||||
array(array(1.23), array('1.23')),
|
||||
array(array(null => 'Label'), array('' => '')),
|
||||
array(array('1.23' => 'Label'), array('1.23' => '1.23')),
|
||||
// Always cast booleans to 0 and 1, because:
|
||||
// array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No')
|
||||
// see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean
|
||||
array(array(true), array(1)),
|
||||
array(array(false), array(0)),
|
||||
array(array(true => 'Label'), array(1 => 1)),
|
||||
array(array(false => 'Label'), array(0 => 0)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidChoices
|
||||
* @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testFailIfInvalidChoices(array $choices)
|
||||
{
|
||||
new ArrayKeyChoiceList($choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidChoices
|
||||
* @expectedException \Symfony\Component\Form\Exception\InvalidArgumentException
|
||||
|
@ -155,7 +146,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||
return $value;
|
||||
};
|
||||
|
||||
$list = new ArrayKeyChoiceList(array('choice'), $callback);
|
||||
$list = new ArrayKeyChoiceList(array('choice' => 'Label'), $callback);
|
||||
|
||||
$this->assertSame(array($converted), $list->getValues());
|
||||
}
|
||||
|
@ -169,15 +160,7 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||
array('1', '1'),
|
||||
array('1.23', '1.23'),
|
||||
array('foobar', 'foobar'),
|
||||
// The default value of choice fields is NULL. It should be treated
|
||||
// like the empty value for this choice list type
|
||||
array(null, ''),
|
||||
array(1.23, '1.23'),
|
||||
// Always cast booleans to 0 and 1, because:
|
||||
// array(true => 'Yes', false => 'No') === array(1 => 'Yes', 0 => 'No')
|
||||
// see ChoiceTypeTest::testSetDataSingleNonExpandedAcceptsBoolean
|
||||
array(true, '1'),
|
||||
array(false, ''),
|
||||
array('', ''),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -187,9 +170,11 @@ class ArrayKeyChoiceListTest extends AbstractChoiceListTest
|
|||
return ':'.$choice;
|
||||
};
|
||||
|
||||
$choiceList = new ArrayKeyChoiceList(array(2 => 'foo', 7 => 'bar', 10 => 'baz'), $callback);
|
||||
$choiceList = new ArrayKeyChoiceList(array('foo' => 'Foo', 'bar' => 'Bar', 'baz' => 'Baz'), $callback);
|
||||
|
||||
$this->assertSame(array(2 => ':foo', 7 => ':bar', 10 => ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo', ':bar', ':baz'), $choiceList->getValues());
|
||||
$this->assertSame(array(':foo' => 'foo', ':bar' => 'bar', ':baz' => 'baz'), $choiceList->getChoices());
|
||||
$this->assertSame(array(':foo' => 'Foo', ':bar' => 'Bar', ':baz' => 'Baz'), $choiceList->getOriginalKeys());
|
||||
$this->assertSame(array(1 => 'foo', 2 => 'baz'), $choiceList->getChoicesForValues(array(1 => ':foo', 2 => ':baz')));
|
||||
$this->assertSame(array(1 => ':foo', 2 => ':baz'), $choiceList->getValuesForChoices(array(1 => 'foo', 2 => 'baz')));
|
||||
}
|
||||
|
|
|
@ -204,8 +204,8 @@ class CachingFactoryDecoratorTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testCreateFromFlippedChoicesSameChoices($choice1, $choice2)
|
||||
{
|
||||
$choices1 = array($choice1);
|
||||
$choices2 = array($choice2);
|
||||
$choices1 = array($choice1 => 'A');
|
||||
$choices2 = array($choice2 => 'A');
|
||||
$list = new \stdClass();
|
||||
|
||||
$this->decoratedFactory->expects($this->once())
|
||||
|
@ -222,8 +222,8 @@ class CachingFactoryDecoratorTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testCreateFromFlippedChoicesDifferentChoices($choice1, $choice2)
|
||||
{
|
||||
$choices1 = array($choice1);
|
||||
$choices2 = array($choice2);
|
||||
$choices1 = array($choice1 => 'A');
|
||||
$choices2 = array($choice2 => 'A');
|
||||
$list1 = new \stdClass();
|
||||
$list2 = new \stdClass();
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList;
|
|||
use Symfony\Component\Form\ChoiceList\ChoiceListInterface;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||
use Symfony\Component\Form\ChoiceList\LazyChoiceList;
|
||||
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceListView;
|
||||
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
|
||||
|
@ -77,6 +78,13 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
return $this->obj1 === $object || $this->obj2 === $object ? 'Group 1' : 'Group 2';
|
||||
}
|
||||
|
||||
public function getGroupAsObject($object)
|
||||
{
|
||||
return $this->obj1 === $object || $this->obj2 === $object
|
||||
? new DefaultChoiceListFactoryTest_Castable('Group 1')
|
||||
: new DefaultChoiceListFactoryTest_Castable('Group 2');
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->obj1 = (object) array('label' => 'A', 'index' => 'w', 'value' => 'a', 'preferred' => false, 'group' => 'Group 1', 'attr' => array());
|
||||
|
@ -199,7 +207,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D')
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesFlatTraversable()
|
||||
|
@ -208,7 +216,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
new \ArrayIterator(array('a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D'))
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesFlatValuesAsCallable()
|
||||
|
@ -247,7 +255,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
)
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesGroupedTraversable()
|
||||
|
@ -259,7 +267,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
))
|
||||
);
|
||||
|
||||
$this->assertScalarListWithGeneratedValues($list);
|
||||
$this->assertScalarListWithChoiceValues($list);
|
||||
}
|
||||
|
||||
public function testCreateFromFlippedChoicesGroupedValuesAsCallable()
|
||||
|
@ -523,33 +531,16 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertFlatViewWithCustomIndices($view);
|
||||
}
|
||||
|
||||
public function testCreateViewFlatGroupByAsArray()
|
||||
public function testCreateViewFlatGroupByOriginalStructure()
|
||||
{
|
||||
$view = $this->factory->createView(
|
||||
$this->list,
|
||||
array($this->obj2, $this->obj3),
|
||||
null, // label
|
||||
null, // index
|
||||
array(
|
||||
'Group 1' => array('A' => true, 'B' => true),
|
||||
'Group 2' => array('C' => true, 'D' => true),
|
||||
)
|
||||
);
|
||||
$list = new ArrayChoiceList(array(
|
||||
'Group 1' => array('A' => $this->obj1, 'B' => $this->obj2),
|
||||
'Group 2' => array('C' => $this->obj3, 'D' => $this->obj4),
|
||||
));
|
||||
|
||||
$this->assertGroupedView($view);
|
||||
}
|
||||
|
||||
public function testCreateViewFlatGroupByAsTraversable()
|
||||
{
|
||||
$view = $this->factory->createView(
|
||||
$this->list,
|
||||
array($this->obj2, $this->obj3),
|
||||
null, // label
|
||||
null, // index
|
||||
new \ArrayIterator(array(
|
||||
'Group 1' => array('A' => true, 'B' => true),
|
||||
'Group 2' => array('C' => true, 'D' => true),
|
||||
))
|
||||
$list,
|
||||
array($this->obj2, $this->obj3)
|
||||
);
|
||||
|
||||
$this->assertGroupedView($view);
|
||||
|
@ -581,6 +572,19 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertGroupedView($view);
|
||||
}
|
||||
|
||||
public function testCreateViewFlatGroupByObjectThatCanBeCastToString()
|
||||
{
|
||||
$view = $this->factory->createView(
|
||||
$this->list,
|
||||
array($this->obj2, $this->obj3),
|
||||
null, // label
|
||||
null, // index
|
||||
array($this, 'getGroupAsObject')
|
||||
);
|
||||
|
||||
$this->assertGroupedView($view);
|
||||
}
|
||||
|
||||
public function testCreateViewFlatGroupByAsClosure()
|
||||
{
|
||||
$obj1 = $this->obj1;
|
||||
|
@ -592,8 +596,7 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
null, // label
|
||||
null, // index
|
||||
function ($object) use ($obj1, $obj2) {
|
||||
return $obj1 === $object || $obj2 === $object ? 'Group 1'
|
||||
: 'Group 2';
|
||||
return $obj1 === $object || $obj2 === $object ? 'Group 1' : 'Group 2';
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -749,78 +752,86 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
->method('getRemainingViews')
|
||||
->will($this->returnValue($other));
|
||||
|
||||
$view = $this->factory->createView($list);
|
||||
$view = $this->factory->createView(new LegacyChoiceListAdapter($list));
|
||||
|
||||
$this->assertEquals(array(new ChoiceView('y', 'y', 'Other')), $view->choices);
|
||||
$this->assertEquals(array(new ChoiceView('x', 'x', 'Preferred')), $view->preferredChoices);
|
||||
}
|
||||
|
||||
private function assertScalarListWithGeneratedValues(ChoiceListInterface $list)
|
||||
private function assertScalarListWithChoiceValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('a', 'b', 'c', 'd'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => 'c',
|
||||
'D' => 'd',
|
||||
'a' => 'a',
|
||||
'b' => 'b',
|
||||
'c' => 'c',
|
||||
'd' => 'd',
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => 'c',
|
||||
'D' => 'd',
|
||||
), $list->getValues());
|
||||
'a' => 'A',
|
||||
'b' => 'B',
|
||||
'c' => 'C',
|
||||
'd' => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertObjectListWithGeneratedValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('0', '1', '2', '3'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => $this->obj1,
|
||||
'B' => $this->obj2,
|
||||
'C' => $this->obj3,
|
||||
'D' => $this->obj4,
|
||||
0 => $this->obj1,
|
||||
1 => $this->obj2,
|
||||
2 => $this->obj3,
|
||||
3 => $this->obj4,
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => '0',
|
||||
'B' => '1',
|
||||
'C' => '2',
|
||||
'D' => '3',
|
||||
), $list->getValues());
|
||||
0 => 'A',
|
||||
1 => 'B',
|
||||
2 => 'C',
|
||||
3 => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertScalarListWithCustomValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('a', 'b', '1', '2'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => 'c',
|
||||
'D' => 'd',
|
||||
'a' => 'a',
|
||||
'b' => 'b',
|
||||
1 => 'c',
|
||||
2 => 'd',
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => '1',
|
||||
'D' => '2',
|
||||
), $list->getValues());
|
||||
'a' => 'A',
|
||||
'b' => 'B',
|
||||
1 => 'C',
|
||||
2 => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertObjectListWithCustomValues(ChoiceListInterface $list)
|
||||
{
|
||||
$this->assertSame(array('a', 'b', '1', '2'), $list->getValues());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => $this->obj1,
|
||||
'B' => $this->obj2,
|
||||
'C' => $this->obj3,
|
||||
'D' => $this->obj4,
|
||||
'a' => $this->obj1,
|
||||
'b' => $this->obj2,
|
||||
1 => $this->obj3,
|
||||
2 => $this->obj4,
|
||||
), $list->getChoices());
|
||||
|
||||
$this->assertSame(array(
|
||||
'A' => 'a',
|
||||
'B' => 'b',
|
||||
'C' => '1',
|
||||
'D' => '2',
|
||||
), $list->getValues());
|
||||
'a' => 'A',
|
||||
'b' => 'B',
|
||||
1 => 'C',
|
||||
2 => 'D',
|
||||
), $list->getOriginalKeys());
|
||||
}
|
||||
|
||||
private function assertFlatView($view)
|
||||
|
@ -897,3 +908,18 @@ class DefaultChoiceListFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
), $view);
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultChoiceListFactoryTest_Castable
|
||||
{
|
||||
private $property;
|
||||
|
||||
public function __construct($property)
|
||||
{
|
||||
$this->property = $property;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->property;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,36 @@ class LazyChoiceListTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertSame('RESULT', $this->list->getValues());
|
||||
}
|
||||
|
||||
public function testGetStructuredValuesLoadsInnerListOnFirstCall()
|
||||
{
|
||||
$this->loader->expects($this->once())
|
||||
->method('loadChoiceList')
|
||||
->with($this->value)
|
||||
->will($this->returnValue($this->innerList));
|
||||
|
||||
$this->innerList->expects($this->exactly(2))
|
||||
->method('getStructuredValues')
|
||||
->will($this->returnValue('RESULT'));
|
||||
|
||||
$this->assertSame('RESULT', $this->list->getStructuredValues());
|
||||
$this->assertSame('RESULT', $this->list->getStructuredValues());
|
||||
}
|
||||
|
||||
public function testGetOriginalKeysLoadsInnerListOnFirstCall()
|
||||
{
|
||||
$this->loader->expects($this->once())
|
||||
->method('loadChoiceList')
|
||||
->with($this->value)
|
||||
->will($this->returnValue($this->innerList));
|
||||
|
||||
$this->innerList->expects($this->exactly(2))
|
||||
->method('getOriginalKeys')
|
||||
->will($this->returnValue('RESULT'));
|
||||
|
||||
$this->assertSame('RESULT', $this->list->getOriginalKeys());
|
||||
$this->assertSame('RESULT', $this->list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testGetChoicesForValuesForwardsCallIfListNotLoaded()
|
||||
{
|
||||
$this->loader->expects($this->exactly(2))
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Tests\ChoiceList;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\LegacyChoiceListAdapter;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class LegacyChoiceListAdapterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var LegacyChoiceListAdapter
|
||||
*/
|
||||
private $list;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject|ChoiceListInterface
|
||||
*/
|
||||
private $adaptedList;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->adaptedList = $this->getMock('Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface');
|
||||
$this->list = new LegacyChoiceListAdapter($this->adaptedList);
|
||||
}
|
||||
|
||||
public function testGetChoices()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(':a' => 'a', ':b' => 'b', ':c' => 'c'), $this->list->getChoices());
|
||||
}
|
||||
|
||||
public function testGetValues()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(':a', ':b', ':c'), $this->list->getValues());
|
||||
}
|
||||
|
||||
public function testGetStructuredValues()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(1 => ':a', 4 => ':b', 7 => ':c'), $this->list->getStructuredValues());
|
||||
}
|
||||
|
||||
public function testGetOriginalKeys()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoices')
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValues')
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(':a' => 1, ':b' => 4, ':c' => 7), $this->list->getOriginalKeys());
|
||||
}
|
||||
|
||||
public function testGetChoicesForValues()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getChoicesForValues')
|
||||
->with(array(1 => ':a', 4 => ':b', 7 => ':c'))
|
||||
->willReturn(array(1 => 'a', 4 => 'b', 7 => 'c'));
|
||||
|
||||
$this->assertSame(array(1 => 'a', 4 => 'b', 7 => 'c'), $this->list->getChoicesForValues(array(1 => ':a', 4 => ':b', 7 => ':c')));
|
||||
}
|
||||
|
||||
public function testGetValuesForChoices()
|
||||
{
|
||||
$this->adaptedList->expects($this->once())
|
||||
->method('getValuesForChoices')
|
||||
->with(array(1 => 'a', 4 => 'b', 7 => 'c'))
|
||||
->willReturn(array(1 => ':a', 4 => ':b', 7 => ':c'));
|
||||
|
||||
$this->assertSame(array(1 => ':a', 4 => ':b', 7 => ':c'), $this->list->getValuesForChoices(array(1 => 'a', 4 => 'b', 7 => 'c')));
|
||||
}
|
||||
|
||||
public function testGetAdaptedList()
|
||||
{
|
||||
$this->assertSame($this->adaptedList, $this->list->getAdaptedList());
|
||||
}
|
||||
}
|
|
@ -350,7 +350,7 @@ class CompoundFormTest extends AbstractFormTest
|
|||
->with('bar', $this->isInstanceOf('\RecursiveIteratorIterator'))
|
||||
->will($this->returnCallback(function ($data, \RecursiveIteratorIterator $iterator) use ($child, $test) {
|
||||
$test->assertInstanceOf('Symfony\Component\Form\Util\InheritDataAwareIterator', $iterator->getInnerIterator());
|
||||
$test->assertSame(array($child), iterator_to_array($iterator));
|
||||
$test->assertSame(array($child->getName() => $child), iterator_to_array($iterator));
|
||||
}));
|
||||
|
||||
$form->initialize();
|
||||
|
|
|
@ -15,6 +15,6 @@ abstract class DateTimeTestCase extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual)
|
||||
{
|
||||
self::assertEquals($expected->format('c'), $actual->format('c'));
|
||||
self::assertEquals($expected->format('U'), $actual->format('U'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
namespace Symfony\Component\Form\Tests\Extension\Core\EventListener;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\Extension\Core\EventListener\FixRadioInputListener;
|
||||
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
|
@ -26,7 +26,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->choiceList = new SimpleChoiceList(array('' => 'Empty', 0 => 'A', 1 => 'B'));
|
||||
$this->choiceList = new ArrayKeyChoiceList(array('' => 'Empty', 0 => 'A', 1 => 'B'));
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
|
@ -45,7 +45,6 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||
$listener->preSubmit($event);
|
||||
|
||||
// Indices in SimpleChoiceList are zero-based generated integers
|
||||
$this->assertEquals(array(2 => '1'), $event->getData());
|
||||
}
|
||||
|
||||
|
@ -58,7 +57,6 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||
$listener->preSubmit($event);
|
||||
|
||||
// Indices in SimpleChoiceList are zero-based generated integers
|
||||
$this->assertEquals(array(1 => '0'), $event->getData());
|
||||
}
|
||||
|
||||
|
@ -71,13 +69,12 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$listener = new FixRadioInputListener($this->choiceList, true);
|
||||
$listener->preSubmit($event);
|
||||
|
||||
// Indices in SimpleChoiceList are zero-based generated integers
|
||||
$this->assertEquals(array(0 => ''), $event->getData());
|
||||
}
|
||||
|
||||
public function testConvertEmptyStringToPlaceholderIfNotFound()
|
||||
{
|
||||
$list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
$list = new ArrayKeyChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
|
||||
$data = '';
|
||||
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||
|
@ -91,7 +88,7 @@ class FixRadioInputListenerTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testDontConvertEmptyStringToPlaceholderIfNoPlaceholderUsed()
|
||||
{
|
||||
$list = new SimpleChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
$list = new ArrayKeyChoiceList(array(0 => 'A', 1 => 'B'));
|
||||
|
||||
$data = '';
|
||||
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||
|
|
|
@ -30,7 +30,7 @@ class ChoiceTypePerformanceTest extends FormPerformanceTestCase
|
|||
$choices = range(1, 300);
|
||||
|
||||
for ($i = 0; $i < 100; ++$i) {
|
||||
$this->factory->create('choice', rand(1, 400), array(
|
||||
$this->factory->create('choice', mt_rand(1, 400), array(
|
||||
'choices' => $choices,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -186,6 +186,32 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
|
|||
}
|
||||
}
|
||||
|
||||
public function testExpandedChoicesOptionsAreFlattenedObjectChoices()
|
||||
{
|
||||
$obj1 = (object) array('id' => 1, 'name' => 'Bernhard');
|
||||
$obj2 = (object) array('id' => 2, 'name' => 'Fabien');
|
||||
$obj3 = (object) array('id' => 3, 'name' => 'Kris');
|
||||
$obj4 = (object) array('id' => 4, 'name' => 'Jon');
|
||||
$obj5 = (object) array('id' => 5, 'name' => 'Roman');
|
||||
|
||||
$form = $this->factory->create('choice', null, array(
|
||||
'expanded' => true,
|
||||
'choices' => array(
|
||||
'Symfony' => array($obj1, $obj2, $obj3),
|
||||
'Doctrine' => array($obj4, $obj5),
|
||||
),
|
||||
'choices_as_values' => true,
|
||||
'choice_name' => 'id',
|
||||
));
|
||||
|
||||
$this->assertSame(5, $form->count(), 'Each nested choice should become a new field, not the groups');
|
||||
$this->assertTrue($form->has(1));
|
||||
$this->assertTrue($form->has(2));
|
||||
$this->assertTrue($form->has(3));
|
||||
$this->assertTrue($form->has(4));
|
||||
$this->assertTrue($form->has(5));
|
||||
}
|
||||
|
||||
public function testExpandedCheckboxesAreNeverRequired()
|
||||
{
|
||||
$form = $this->factory->create('choice', null, array(
|
||||
|
|
|
@ -627,6 +627,20 @@ class DateTypeTest extends TestCase
|
|||
$this->assertFalse(isset($view->vars['date_pattern']));
|
||||
}
|
||||
|
||||
public function testDatePatternFormatWithQuotedStrings()
|
||||
{
|
||||
\Locale::setDefault('es_ES');
|
||||
|
||||
$form = $this->factory->create('date', null, array(
|
||||
// EEEE, d 'de' MMMM 'de' y
|
||||
'format' => \IntlDateFormatter::FULL,
|
||||
));
|
||||
|
||||
$view = $form->createView();
|
||||
|
||||
$this->assertEquals('{{ day }}{{ month }}{{ year }}', $view->vars['date_pattern']);
|
||||
}
|
||||
|
||||
public function testPassWidgetToView()
|
||||
{
|
||||
$form = $this->factory->create('date', null, array(
|
||||
|
|
|
@ -95,34 +95,58 @@ class JsonResponse extends Response
|
|||
*/
|
||||
public function setData($data = array())
|
||||
{
|
||||
$errorHandler = null;
|
||||
$errorHandler = set_error_handler(function () use (&$errorHandler) {
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
return;
|
||||
if (defined('HHVM_VERSION')) {
|
||||
// HHVM does not trigger any warnings and let exceptions
|
||||
// thrown from a JsonSerializable object pass through.
|
||||
// If only PHP did the same...
|
||||
$data = json_encode($data, $this->encodingOptions);
|
||||
} else {
|
||||
try {
|
||||
if (PHP_VERSION_ID < 50400) {
|
||||
// PHP 5.3 triggers annoying warnings for some
|
||||
// types that can't be serialized as JSON (INF, resources, etc.)
|
||||
// but doesn't provide the JsonSerializable interface.
|
||||
set_error_handler('var_dump', 0);
|
||||
$data = @json_encode($data, $this->encodingOptions);
|
||||
} else {
|
||||
// PHP 5.4 and up wrap exceptions thrown by JsonSerializable
|
||||
// objects in a new exception that needs to be removed.
|
||||
// Fortunately, PHP 5.5 and up do not trigger any warning anymore.
|
||||
if (PHP_VERSION_ID < 50500) {
|
||||
// Clear json_last_error()
|
||||
json_encode(null);
|
||||
$errorHandler = set_error_handler('var_dump');
|
||||
restore_error_handler();
|
||||
set_error_handler(function () use ($errorHandler) {
|
||||
if (JSON_ERROR_NONE === json_last_error()) {
|
||||
return $errorHandler && false !== call_user_func_array($errorHandler, func_get_args());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$data = json_encode($data, $this->encodingOptions);
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID < 50500) {
|
||||
restore_error_handler();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
if (PHP_VERSION_ID < 50500) {
|
||||
restore_error_handler();
|
||||
}
|
||||
if (PHP_VERSION_ID >= 50400 && 'Exception' === get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) {
|
||||
throw $e->getPrevious() ?: $e;
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($errorHandler) {
|
||||
call_user_func_array($errorHandler, func_get_args());
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
// Clear json_last_error()
|
||||
json_encode(null);
|
||||
|
||||
$this->data = json_encode($data, $this->encodingOptions);
|
||||
|
||||
restore_error_handler();
|
||||
} catch (\Exception $exception) {
|
||||
restore_error_handler();
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new \InvalidArgumentException($this->transformJsonError());
|
||||
}
|
||||
|
||||
$this->data = $data;
|
||||
|
||||
return $this->update();
|
||||
}
|
||||
|
||||
|
|
|
@ -517,10 +517,17 @@ class Request
|
|||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$content = '';
|
||||
try {
|
||||
$content = $this->getContent();
|
||||
} catch (\LogicException $e) {
|
||||
return trigger_error($e, E_USER_ERROR);
|
||||
}
|
||||
|
||||
return
|
||||
sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n".
|
||||
$this->headers."\r\n".
|
||||
$this->getContent();
|
||||
$content;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1247,15 +1247,9 @@ class Response
|
|||
{
|
||||
$status = ob_get_status(true);
|
||||
$level = count($status);
|
||||
$flags = PHP_VERSION_ID >= 50400 ? PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? PHP_OUTPUT_HANDLER_FLUSHABLE : PHP_OUTPUT_HANDLER_CLEANABLE) : -1;
|
||||
|
||||
while ($level-- > $targetLevel
|
||||
&& (!empty($status[$level]['del'])
|
||||
|| (isset($status[$level]['flags'])
|
||||
&& ($status[$level]['flags'] & PHP_OUTPUT_HANDLER_REMOVABLE)
|
||||
&& ($status[$level]['flags'] & ($flush ? PHP_OUTPUT_HANDLER_FLUSHABLE : PHP_OUTPUT_HANDLER_CLEANABLE))
|
||||
)
|
||||
)
|
||||
) {
|
||||
while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || $flags === ($s['flags'] & $flags) : $s['del'])) {
|
||||
if ($flush) {
|
||||
ob_end_flush();
|
||||
} else {
|
||||
|
|
|
@ -203,9 +203,8 @@ class JsonResponseTest extends \PHPUnit_Framework_TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @expectedException Exception
|
||||
* @expectedExceptionMessage Failed calling Symfony\Component\HttpFoundation\Tests\JsonSerializableObject::jsonSerialize()
|
||||
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php#114688
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage This error is expected
|
||||
*/
|
||||
public function testSetContentJsonSerializeError()
|
||||
{
|
||||
|
@ -224,9 +223,7 @@ if (interface_exists('JsonSerializable')) {
|
|||
{
|
||||
public function jsonSerialize()
|
||||
{
|
||||
trigger_error('This error is expected', E_USER_WARNING);
|
||||
|
||||
return array();
|
||||
throw new \Exception('This error is expected');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$bag->clearCookie('foo');
|
||||
|
||||
$this->assertContains('Set-Cookie: foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/; httponly', explode("\r\n", $bag->__toString()));
|
||||
$this->assertRegExp('#^Set-Cookie: foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/; httponly#m', $bag->__toString());
|
||||
}
|
||||
|
||||
public function testClearCookieSecureNotHttpOnly()
|
||||
|
@ -127,7 +127,7 @@ class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$bag->clearCookie('foo', '/', null, true, false);
|
||||
|
||||
$this->assertContains("Set-Cookie: foo=deleted; expires=".gmdate("D, d-M-Y H:i:s T", time() - 31536001)."; path=/; secure", explode("\r\n", $bag->__toString()));
|
||||
$this->assertRegExp('#^Set-Cookie: foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; path=/; secure#m', $bag->__toString());
|
||||
}
|
||||
|
||||
public function testReplace()
|
||||
|
|
|
@ -216,7 +216,6 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
$storage = $this->getStorage();
|
||||
|
||||
$this->assertFalse(isset($_SESSION));
|
||||
$this->assertFalse($storage->getSaveHandler()->isActive());
|
||||
$this->assertFalse($storage->isStarted());
|
||||
|
||||
|
|
|
@ -91,7 +91,6 @@ class PhpBridgeSessionStorageTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$storage = $this->getStorage();
|
||||
|
||||
$this->assertFalse(isset($_SESSION));
|
||||
$this->assertFalse($storage->getSaveHandler()->isActive());
|
||||
$this->assertFalse($storage->isStarted());
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ class FullTransformer
|
|||
|
||||
// handle unimplemented characters
|
||||
if (false !== strpos($this->notImplementedChars, $dateChars[0])) {
|
||||
throw new NotImplementedException(sprintf("Unimplemented date character '%s' in format '%s'", $dateChars[0], $this->pattern));
|
||||
throw new NotImplementedException(sprintf('Unimplemented date character "%s" in format "%s"', $dateChars[0], $this->pattern));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class JsonBundleWriterTest extends \PHPUnit_Framework_TestCase
|
|||
}
|
||||
|
||||
$this->writer = new JsonBundleWriter();
|
||||
$this->directory = sys_get_temp_dir().'/JsonBundleWriterTest/'.rand(1000, 9999);
|
||||
$this->directory = sys_get_temp_dir().'/JsonBundleWriterTest/'.mt_rand(1000, 9999);
|
||||
$this->filesystem = new Filesystem();
|
||||
|
||||
$this->filesystem->mkdir($this->directory);
|
||||
|
|
|
@ -35,7 +35,7 @@ class PhpBundleWriterTest extends \PHPUnit_Framework_TestCase
|
|||
protected function setUp()
|
||||
{
|
||||
$this->writer = new PhpBundleWriter();
|
||||
$this->directory = sys_get_temp_dir().'/PhpBundleWriterTest/'.rand(1000, 9999);
|
||||
$this->directory = sys_get_temp_dir().'/PhpBundleWriterTest/'.mt_rand(1000, 9999);
|
||||
$this->filesystem = new Filesystem();
|
||||
|
||||
$this->filesystem->mkdir($this->directory);
|
||||
|
|
|
@ -36,7 +36,7 @@ class TextBundleWriterTest extends \PHPUnit_Framework_TestCase
|
|||
protected function setUp()
|
||||
{
|
||||
$this->writer = new TextBundleWriter();
|
||||
$this->directory = sys_get_temp_dir().'/TextBundleWriterTest/'.rand(1000, 9999);
|
||||
$this->directory = sys_get_temp_dir().'/TextBundleWriterTest/'.mt_rand(1000, 9999);
|
||||
$this->filesystem = new Filesystem();
|
||||
|
||||
$this->filesystem->mkdir($this->directory);
|
||||
|
|
|
@ -33,7 +33,7 @@ class LocaleScannerTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->directory = sys_get_temp_dir().'/LocaleScannerTest/'.rand(1000, 9999);
|
||||
$this->directory = sys_get_temp_dir().'/LocaleScannerTest/'.mt_rand(1000, 9999);
|
||||
$this->filesystem = new Filesystem();
|
||||
$this->scanner = new LocaleScanner();
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ class PhpExecutableFinder
|
|||
{
|
||||
// HHVM support
|
||||
if (defined('HHVM_VERSION')) {
|
||||
return (false !== ($hhvm = getenv('PHP_BINARY')) ? $hhvm : PHP_BINARY).($includeArgs ? ' '.implode(' ', $this->findArguments()) : '');
|
||||
return (getenv('PHP_BINARY') ?: PHP_BINARY).($includeArgs ? ' '.implode(' ', $this->findArguments()) : '');
|
||||
}
|
||||
|
||||
// PHP_BINARY return the current sapi executable
|
||||
|
|
|
@ -11,21 +11,30 @@
|
|||
|
||||
namespace Symfony\Component\Process\Tests;
|
||||
|
||||
use Symfony\Component\Process\Exception\ProcessTimedOutException;
|
||||
use Symfony\Component\Process\Exception\LogicException;
|
||||
use Symfony\Component\Process\Exception\ProcessTimedOutException;
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
use Symfony\Component\Process\Pipes\PipesInterface;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Process\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
*/
|
||||
abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected static $phpBin;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
$phpBin = new PhpExecutableFinder();
|
||||
self::$phpBin = $phpBin->find();
|
||||
}
|
||||
|
||||
public function testThatProcessDoesNotThrowWarningDuringRun()
|
||||
{
|
||||
@trigger_error('Test Error', E_USER_NOTICE);
|
||||
$process = $this->getProcess("php -r 'sleep(3)'");
|
||||
$process = $this->getProcess(self::$phpBin." -r 'sleep(3)'");
|
||||
$process->run();
|
||||
$actualError = error_get_last();
|
||||
$this->assertEquals('Test Error', $actualError['message']);
|
||||
|
@ -95,7 +104,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$expectedOutputSize = PipesInterface::CHUNK_SIZE * 2 + 2;
|
||||
|
||||
$code = sprintf('echo str_repeat(\'*\', %d);', $expectedOutputSize);
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code)));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
|
||||
|
||||
$p->start();
|
||||
// Let's wait enough time for process to finish...
|
||||
|
@ -134,7 +143,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testProcessResponses($expected, $getter, $code)
|
||||
{
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code)));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
|
||||
$p->run();
|
||||
|
||||
$this->assertSame($expected, $p->$getter());
|
||||
|
@ -150,7 +159,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$expected = str_repeat(str_repeat('*', 1024), $size).'!';
|
||||
$expectedLength = (1024 * $size) + 1;
|
||||
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code)));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
|
||||
$p->setInput($expected);
|
||||
$p->run();
|
||||
|
||||
|
@ -170,7 +179,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
fwrite($stream, $expected);
|
||||
rewind($stream);
|
||||
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg($code)));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)));
|
||||
$p->setInput($stream);
|
||||
$p->run();
|
||||
|
||||
|
@ -182,7 +191,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testSetInputWhileRunningThrowsAnException()
|
||||
{
|
||||
$process = $this->getProcess('php -r "usleep(500000);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$process->start();
|
||||
try {
|
||||
$process->setInput('foobar');
|
||||
|
@ -201,7 +210,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testInvalidInput($value)
|
||||
{
|
||||
$process = $this->getProcess('php -v');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->setInput($value);
|
||||
}
|
||||
|
||||
|
@ -218,7 +227,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testValidInput($expected, $value)
|
||||
{
|
||||
$process = $this->getProcess('php -v');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->setInput($value);
|
||||
$this->assertSame($expected, $process->getInput());
|
||||
}
|
||||
|
@ -238,7 +247,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testLegacyValidInput($expected, $value)
|
||||
{
|
||||
$process = $this->getProcess('php -v');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->setInput($value);
|
||||
$this->assertSame($expected, $process->getInput());
|
||||
}
|
||||
|
@ -276,7 +285,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testCallbackIsExecutedForOutput()
|
||||
{
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('echo \'foo\';')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('echo \'foo\';')));
|
||||
|
||||
$called = false;
|
||||
$p->run(function ($type, $buffer) use (&$called) {
|
||||
|
@ -288,7 +297,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetErrorOutput()
|
||||
{
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
|
||||
|
||||
$p->run();
|
||||
$this->assertEquals(3, preg_match_all('/ERROR/', $p->getErrorOutput(), $matches));
|
||||
|
@ -301,7 +310,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
|
||||
file_put_contents($lock, 'W');
|
||||
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
|
||||
$p->start();
|
||||
while ($p->isRunning()) {
|
||||
|
@ -317,7 +326,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testFlushErrorOutput()
|
||||
{
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }')));
|
||||
|
||||
$p->run();
|
||||
$p->clearErrorOutput();
|
||||
|
@ -331,7 +340,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
|
||||
file_put_contents($lock, 'W');
|
||||
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
|
||||
$p->start();
|
||||
|
||||
|
@ -357,7 +366,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetOutput()
|
||||
{
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { echo \' foo \'; $n++; }')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { echo \' foo \'; $n++; }')));
|
||||
|
||||
$p->run();
|
||||
$this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches));
|
||||
|
@ -370,7 +379,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
|
||||
file_put_contents($lock, 'W');
|
||||
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
|
||||
$p->start();
|
||||
while ($p->isRunning()) {
|
||||
|
@ -386,7 +395,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testFlushOutput()
|
||||
{
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++;}')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++;}')));
|
||||
|
||||
$p->run();
|
||||
$p->clearOutput();
|
||||
|
@ -400,7 +409,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
|
||||
file_put_contents($lock, 'W');
|
||||
|
||||
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
$p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
|
||||
|
||||
$p->start();
|
||||
|
||||
|
@ -546,7 +555,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testStartIsNonBlocking()
|
||||
{
|
||||
$process = $this->getProcess('php -r "usleep(500000);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$start = microtime(true);
|
||||
$process->start();
|
||||
$end = microtime(true);
|
||||
|
@ -556,14 +565,14 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testUpdateStatus()
|
||||
{
|
||||
$process = $this->getProcess('php -h');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$this->assertTrue(strlen($process->getOutput()) > 0);
|
||||
}
|
||||
|
||||
public function testGetExitCodeIsNullOnStart()
|
||||
{
|
||||
$process = $this->getProcess('php -r "usleep(200000);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(200000);"');
|
||||
$this->assertNull($process->getExitCode());
|
||||
$process->start();
|
||||
$this->assertNull($process->getExitCode());
|
||||
|
@ -573,7 +582,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetExitCodeIsNullOnWhenStartingAgain()
|
||||
{
|
||||
$process = $this->getProcess('php -r "usleep(200000);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(200000);"');
|
||||
$process->run();
|
||||
$this->assertEquals(0, $process->getExitCode());
|
||||
$process->start();
|
||||
|
@ -584,14 +593,14 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetExitCode()
|
||||
{
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$this->assertSame(0, $process->getExitCode());
|
||||
}
|
||||
|
||||
public function testStatus()
|
||||
{
|
||||
$process = $this->getProcess('php -r "usleep(500000);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$this->assertFalse($process->isRunning());
|
||||
$this->assertFalse($process->isStarted());
|
||||
$this->assertFalse($process->isTerminated());
|
||||
|
@ -610,7 +619,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testStop()
|
||||
{
|
||||
$process = $this->getProcess('php -r "sleep(4);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(4);"');
|
||||
$process->start();
|
||||
$this->assertTrue($process->isRunning());
|
||||
$process->stop();
|
||||
|
@ -619,14 +628,14 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testIsSuccessful()
|
||||
{
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$this->assertTrue($process->isSuccessful());
|
||||
}
|
||||
|
||||
public function testIsSuccessfulOnlyAfterTerminated()
|
||||
{
|
||||
$process = $this->getProcess('php -r "sleep(1);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(1);"');
|
||||
$process->start();
|
||||
while ($process->isRunning()) {
|
||||
$this->assertFalse($process->isSuccessful());
|
||||
|
@ -638,7 +647,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testIsNotSuccessful()
|
||||
{
|
||||
$process = $this->getProcess('php -r "usleep(500000);throw new \Exception(\'BOUM\');"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(500000);throw new \Exception(\'BOUM\');"');
|
||||
$process->start();
|
||||
$this->assertTrue($process->isRunning());
|
||||
$process->wait();
|
||||
|
@ -651,7 +660,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$this->markTestSkipped('Windows does not support POSIX signals');
|
||||
}
|
||||
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$this->assertFalse($process->hasBeenSignaled());
|
||||
}
|
||||
|
@ -662,7 +671,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$this->markTestSkipped('Windows does not support POSIX signals');
|
||||
}
|
||||
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$this->assertFalse($process->hasBeenSignaled());
|
||||
}
|
||||
|
@ -673,7 +682,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$this->markTestSkipped('Windows does not support POSIX signals');
|
||||
}
|
||||
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$this->assertEquals(0, $process->getTermSignal());
|
||||
}
|
||||
|
@ -684,7 +693,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$this->markTestSkipped('Windows does not support POSIX signals');
|
||||
}
|
||||
|
||||
$process = $this->getProcess('php -r "sleep(4);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(4);"');
|
||||
$process->start();
|
||||
$process->stop();
|
||||
$this->assertTrue($process->hasBeenSignaled());
|
||||
|
@ -699,7 +708,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
// SIGTERM is only defined if pcntl extension is present
|
||||
$termSignal = defined('SIGTERM') ? SIGTERM : 15;
|
||||
|
||||
$process = $this->getProcess('php -r "sleep(4);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(4);"');
|
||||
$process->start();
|
||||
$process->stop();
|
||||
|
||||
|
@ -728,7 +737,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testRestart()
|
||||
{
|
||||
$process1 = $this->getProcess('php -r "echo getmypid();"');
|
||||
$process1 = $this->getProcess(self::$phpBin.' -r "echo getmypid();"');
|
||||
$process1->run();
|
||||
$process2 = $process1->restart();
|
||||
|
||||
|
@ -750,7 +759,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
// Sleep doesn't work as it will allow the process to handle signals and close
|
||||
// file handles from the other end.
|
||||
$process = $this->getProcess('php -r "while (true) {}"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "while (true) {}"');
|
||||
$process->start();
|
||||
|
||||
// PHP will deadlock when it tries to cleanup $process
|
||||
|
@ -759,7 +768,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
public function testRunProcessWithTimeout()
|
||||
{
|
||||
$timeout = 0.5;
|
||||
$process = $this->getProcess('php -r "usleep(600000);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(600000);"');
|
||||
$process->setTimeout($timeout);
|
||||
$start = microtime(true);
|
||||
try {
|
||||
|
@ -781,13 +790,13 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testCheckTimeoutOnNonStartedProcess()
|
||||
{
|
||||
$process = $this->getProcess('php -r "sleep(3);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
|
||||
$process->checkTimeout();
|
||||
}
|
||||
|
||||
public function testCheckTimeoutOnTerminatedProcess()
|
||||
{
|
||||
$process = $this->getProcess('php -v');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$process->checkTimeout();
|
||||
}
|
||||
|
@ -796,7 +805,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
$timeout = 0.5;
|
||||
$precision = 100000;
|
||||
$process = $this->getProcess('php -r "sleep(3);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
|
||||
$process->setTimeout($timeout);
|
||||
$start = microtime(true);
|
||||
|
||||
|
@ -818,7 +827,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testIdleTimeout()
|
||||
{
|
||||
$process = $this->getProcess('php -r "sleep(3);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
|
||||
$process->setTimeout(10);
|
||||
$process->setIdleTimeout(0.5);
|
||||
|
||||
|
@ -835,7 +844,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testIdleTimeoutNotExceededWhenOutputIsSent()
|
||||
{
|
||||
$process = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 30; while ($n--) {echo "foo\n"; usleep(100000); }')));
|
||||
$process = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 30; while ($n--) {echo "foo\n"; usleep(100000); }')));
|
||||
$process->setTimeout(2);
|
||||
$process->setIdleTimeout(1);
|
||||
|
||||
|
@ -851,7 +860,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testStartAfterATimeout()
|
||||
{
|
||||
$process = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 1000; while ($n--) {echo \'\'; usleep(1000); }')));
|
||||
$process = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 1000; while ($n--) {echo \'\'; usleep(1000); }')));
|
||||
$process->setTimeout(0.1);
|
||||
|
||||
try {
|
||||
|
@ -866,7 +875,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetPid()
|
||||
{
|
||||
$process = $this->getProcess('php -r "usleep(500000);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$process->start();
|
||||
$this->assertGreaterThan(0, $process->getPid());
|
||||
$process->wait();
|
||||
|
@ -874,13 +883,13 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetPidIsNullBeforeStart()
|
||||
{
|
||||
$process = $this->getProcess('php -r "sleep(1);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(1);"');
|
||||
$this->assertNull($process->getPid());
|
||||
}
|
||||
|
||||
public function testGetPidIsNullAfterRun()
|
||||
{
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->run();
|
||||
$this->assertNull($process->getPid());
|
||||
}
|
||||
|
@ -925,7 +934,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
public function testSignalProcessNotRunning()
|
||||
{
|
||||
$this->verifyPosixIsEnabled();
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$process->signal(SIGHUP);
|
||||
}
|
||||
|
||||
|
@ -934,7 +943,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testMethodsThatNeedARunningProcess($method)
|
||||
{
|
||||
$process = $this->getProcess('php -m');
|
||||
$process = $this->getProcess(self::$phpBin.' -v');
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\LogicException', sprintf('Process must be started before calling %s.', $method));
|
||||
$process->{$method}();
|
||||
}
|
||||
|
@ -955,7 +964,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testMethodsThatNeedATerminatedProcess($method)
|
||||
{
|
||||
$process = $this->getProcess('php -r "sleep(1);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(1);"');
|
||||
$process->start();
|
||||
try {
|
||||
$process->{$method}();
|
||||
|
@ -997,7 +1006,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$this->markTestSkipped('POSIX signals do not work on Windows');
|
||||
}
|
||||
|
||||
$process = $this->getProcess('php -r "sleep(3);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
|
||||
$process->start();
|
||||
$process->signal(-4);
|
||||
}
|
||||
|
@ -1011,14 +1020,14 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
$this->markTestSkipped('POSIX signals do not work on Windows');
|
||||
}
|
||||
|
||||
$process = $this->getProcess('php -r "sleep(3);"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "sleep(3);"');
|
||||
$process->start();
|
||||
$process->signal('Céphalopodes');
|
||||
}
|
||||
|
||||
public function testDisableOutputDisablesTheOutput()
|
||||
{
|
||||
$p = $this->getProcess('php -r "usleep(500000);"');
|
||||
$p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$this->assertFalse($p->isOutputDisabled());
|
||||
$p->disableOutput();
|
||||
$this->assertTrue($p->isOutputDisabled());
|
||||
|
@ -1028,7 +1037,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testDisableOutputWhileRunningThrowsException()
|
||||
{
|
||||
$p = $this->getProcess('php -r "usleep(500000);"');
|
||||
$p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$p->start();
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Disabling output while the process is running is not possible.');
|
||||
$p->disableOutput();
|
||||
|
@ -1036,7 +1045,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testEnableOutputWhileRunningThrowsException()
|
||||
{
|
||||
$p = $this->getProcess('php -r "usleep(500000);"');
|
||||
$p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$p->disableOutput();
|
||||
$p->start();
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\RuntimeException', 'Enabling output while the process is running is not possible.');
|
||||
|
@ -1045,7 +1054,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testEnableOrDisableOutputAfterRunDoesNotThrowException()
|
||||
{
|
||||
$p = $this->getProcess('php -r "usleep(500000);"');
|
||||
$p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$p->disableOutput();
|
||||
$p->start();
|
||||
$p->wait();
|
||||
|
@ -1081,7 +1090,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testStartWithACallbackAndDisabledOutput($startMethod, $exception, $exceptionMessage)
|
||||
{
|
||||
$p = $this->getProcess('php -r "usleep(500000);"');
|
||||
$p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$p->disableOutput();
|
||||
$this->setExpectedException($exception, $exceptionMessage);
|
||||
$p->{$startMethod}(function () {});
|
||||
|
@ -1101,7 +1110,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testGetOutputWhileDisabled($fetchMethod)
|
||||
{
|
||||
$p = $this->getProcess('php -r "usleep(500000);"');
|
||||
$p = $this->getProcess(self::$phpBin.' -r "usleep(500000);"');
|
||||
$p->disableOutput();
|
||||
$p->start();
|
||||
$this->setExpectedException('Symfony\Component\Process\Exception\LogicException', 'Output has been disabled.');
|
||||
|
|
|
@ -102,7 +102,7 @@ class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
|||
$this->markTestSkipped('Cannot test when open_basedir is set');
|
||||
}
|
||||
|
||||
$this->iniSet('open_basedir', dirname(PHP_BINARY).PATH_SEPARATOR.'/');
|
||||
$this->iniSet('open_basedir', dirname(PHP_BINARY).(!defined('HHVM_VERSION') ? PATH_SEPARATOR.'/' : ''));
|
||||
|
||||
$finder = new ExecutableFinder();
|
||||
$result = $finder->find($this->getPhpBinaryName());
|
||||
|
@ -125,7 +125,7 @@ class ExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
|||
}
|
||||
|
||||
$this->setPath('');
|
||||
$this->iniSet('open_basedir', PHP_BINARY.PATH_SEPARATOR.'/');
|
||||
$this->iniSet('open_basedir', PHP_BINARY.(!defined('HHVM_VERSION') ? PATH_SEPARATOR.'/' : ''));
|
||||
|
||||
$finder = new ExecutableFinder();
|
||||
$result = $finder->find($this->getPhpBinaryName(), false);
|
||||
|
|
|
@ -53,10 +53,10 @@ class PhpExecutableFinderTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$f = new PhpExecutableFinder();
|
||||
|
||||
$current = $f->find();
|
||||
$current = getenv('PHP_BINARY') ?: PHP_BINARY;
|
||||
|
||||
$this->assertEquals($f->find(), $current.' --php', '::find() returns the executable PHP');
|
||||
$this->assertEquals($f->find(false), $current, '::find() returns the executable PHP');
|
||||
$this->assertEquals($current.' --php', $f->find(), '::find() returns the executable PHP');
|
||||
$this->assertEquals($current, $f->find(false), '::find() returns the executable PHP');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -150,7 +150,7 @@ class SimpleProcessTest extends AbstractProcessTest
|
|||
public function testStopTerminatesProcessCleanly()
|
||||
{
|
||||
try {
|
||||
$process = $this->getProcess('php -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process->run(function () use ($process) {
|
||||
$process->stop();
|
||||
});
|
||||
|
@ -164,7 +164,7 @@ class SimpleProcessTest extends AbstractProcessTest
|
|||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
|
||||
try {
|
||||
$process = $this->getProcess('php -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process->run(function () use ($process) {
|
||||
if ($process->isRunning()) {
|
||||
$process->signal(defined('SIGKILL') ? SIGKILL : 9);
|
||||
|
@ -180,7 +180,7 @@ class SimpleProcessTest extends AbstractProcessTest
|
|||
$this->expectExceptionIfPHPSigchild('Symfony\Component\Process\Exception\RuntimeException', 'This PHP has been compiled with --enable-sigchild. The process can not be signaled.');
|
||||
|
||||
try {
|
||||
$process = $this->getProcess('php -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process = $this->getProcess(self::$phpBin.' -r "echo \'foo\'; sleep(1); echo \'bar\';"');
|
||||
$process->run(function () use ($process) {
|
||||
if ($process->isRunning()) {
|
||||
$process->signal(defined('SIGTERM') ? SIGTERM : 15);
|
||||
|
|
|
@ -48,7 +48,7 @@ class Route
|
|||
foreach ($data as $key => $value) {
|
||||
$method = 'set'.str_replace('_', '', $key);
|
||||
if (!method_exists($this, $method)) {
|
||||
throw new \BadMethodCallException(sprintf("Unknown property '%s' on annotation '%s'.", $key, get_class($this)));
|
||||
throw new \BadMethodCallException(sprintf('Unknown property "%s" on annotation "%s".', $key, get_class($this)));
|
||||
}
|
||||
$this->$method($value);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ class PhpGeneratorDumperTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$this->routeCollection = new RouteCollection();
|
||||
$this->generatorDumper = new PhpGeneratorDumper($this->routeCollection);
|
||||
$this->testTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.php';
|
||||
$this->testTmpFilepath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'php_generator.'.$this->getName().'.php';
|
||||
@unlink($this->testTmpFilepath);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Symfony\Component\Security\Core\Exception;
|
|||
*/
|
||||
class AccessDeniedException extends \RuntimeException
|
||||
{
|
||||
public function __construct($message = 'Access Denied', \Exception $previous = null)
|
||||
public function __construct($message = 'Access Denied.', \Exception $previous = null)
|
||||
{
|
||||
parent::__construct($message, 403, $previous);
|
||||
}
|
||||
|
|
|
@ -162,7 +162,8 @@ class SwitchUserListener implements ListenerInterface
|
|||
}
|
||||
|
||||
if (null !== $this->dispatcher) {
|
||||
$switchEvent = new SwitchUserEvent($request, $original->getUser());
|
||||
$user = $this->provider->refreshUser($original->getUser());
|
||||
$switchEvent = new SwitchUserEvent($request, $user);
|
||||
$this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
|
||||
namespace Symfony\Component\Security\Http\Tests\Firewall;
|
||||
|
||||
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
|
||||
use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
|
||||
use Symfony\Component\Security\Http\SecurityEvents;
|
||||
|
||||
class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
@ -100,6 +102,62 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase
|
|||
$listener->handle($this->event);
|
||||
}
|
||||
|
||||
public function testExitUserDispatchesEventWithRefreshedUser()
|
||||
{
|
||||
$originalUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
|
||||
$refreshedUser = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
|
||||
$this
|
||||
->userProvider
|
||||
->expects($this->any())
|
||||
->method('refreshUser')
|
||||
->with($originalUser)
|
||||
->willReturn($refreshedUser);
|
||||
$originalToken = $this->getToken();
|
||||
$originalToken
|
||||
->expects($this->any())
|
||||
->method('getUser')
|
||||
->willReturn($originalUser);
|
||||
$role = $this
|
||||
->getMockBuilder('Symfony\Component\Security\Core\Role\SwitchUserRole')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$role->expects($this->any())->method('getSource')->willReturn($originalToken);
|
||||
$this
|
||||
->tokenStorage
|
||||
->expects($this->any())
|
||||
->method('getToken')
|
||||
->willReturn($this->getToken(array($role)));
|
||||
$this
|
||||
->request
|
||||
->expects($this->any())
|
||||
->method('get')
|
||||
->with('_switch_user')
|
||||
->willReturn('_exit');
|
||||
$this
|
||||
->request
|
||||
->expects($this->any())
|
||||
->method('getUri')
|
||||
->willReturn('/');
|
||||
$this
|
||||
->request
|
||||
->query
|
||||
->expects($this->any())
|
||||
->method('all')
|
||||
->will($this->returnValue(array()));
|
||||
|
||||
$dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||
$dispatcher
|
||||
->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with(SecurityEvents::SWITCH_USER, $this->callback(function (SwitchUserEvent $event) use ($refreshedUser) {
|
||||
return $event->getTargetUser() === $refreshedUser;
|
||||
}))
|
||||
;
|
||||
|
||||
$listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', $dispatcher);
|
||||
$listener->handle($this->event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException
|
||||
*/
|
||||
|
|
|
@ -35,16 +35,16 @@ class Groups
|
|||
public function __construct(array $data)
|
||||
{
|
||||
if (!isset($data['value']) || !$data['value']) {
|
||||
throw new InvalidArgumentException(sprintf("Parameter of annotation '%s' cannot be empty.", get_class($this)));
|
||||
throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" cannot be empty.', get_class($this)));
|
||||
}
|
||||
|
||||
if (!is_array($data['value'])) {
|
||||
throw new InvalidArgumentException(sprintf("Parameter of annotation '%s' must be an array of strings.", get_class($this)));
|
||||
throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" must be an array of strings.', get_class($this)));
|
||||
}
|
||||
|
||||
foreach ($data['value'] as $group) {
|
||||
if (!is_string($group)) {
|
||||
throw new InvalidArgumentException(sprintf("Parameter of annotation '%s' must be an array of strings.", get_class($this)));
|
||||
throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" must be an array of strings.', get_class($this)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -137,12 +137,12 @@ class StopwatchEventTest extends \PHPUnit_Framework_TestCase
|
|||
public function testStartTime()
|
||||
{
|
||||
$event = new StopwatchEvent(microtime(true) * 1000);
|
||||
$this->assertTrue($event->getStartTime() < 0.5);
|
||||
$this->assertLessThanOrEqual(0.5, $event->getStartTime());
|
||||
|
||||
$event = new StopwatchEvent(microtime(true) * 1000);
|
||||
$event->start();
|
||||
$event->stop();
|
||||
$this->assertTrue($event->getStartTime() < 1);
|
||||
$this->assertLessThanOrEqual(1, $event->getStartTime());
|
||||
|
||||
$event = new StopwatchEvent(microtime(true) * 1000);
|
||||
$event->start();
|
||||
|
|
|
@ -28,7 +28,7 @@ class CacheLoaderTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
public function testLoad()
|
||||
{
|
||||
$dir = sys_get_temp_dir().DIRECTORY_SEPARATOR.rand(111111, 999999);
|
||||
$dir = sys_get_temp_dir().DIRECTORY_SEPARATOR.mt_rand(111111, 999999);
|
||||
mkdir($dir, 0777, true);
|
||||
|
||||
$loader = new ProjectTemplateLoader($varLoader = new ProjectTemplateLoaderVar(), $dir);
|
||||
|
|
|
@ -60,7 +60,7 @@ class CallbackValidator extends ConstraintValidator
|
|||
call_user_func($method, $object, $this->context);
|
||||
} elseif (null !== $object) {
|
||||
if (!method_exists($object, $method)) {
|
||||
throw new ConstraintDefinitionException(sprintf('Method "%s" targeted by Callback constraint does not exist', $method));
|
||||
throw new ConstraintDefinitionException(sprintf('Method "%s" targeted by Callback constraint does not exist in class %s', $method, get_class($object)));
|
||||
}
|
||||
|
||||
$reflMethod = new \ReflectionMethod($object, $method);
|
||||
|
|
|
@ -24,6 +24,7 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
|||
*
|
||||
* @see http://en.wikipedia.org/wiki/Bank_card_number
|
||||
* @see http://www.regular-expressions.info/creditcard.html
|
||||
* @see http://www.barclaycard.co.uk/business/files/Ranges_and_Rules_September_2014.pdf
|
||||
*/
|
||||
class CardSchemeValidator extends ConstraintValidator
|
||||
{
|
||||
|
@ -64,10 +65,13 @@ class CardSchemeValidator extends ConstraintValidator
|
|||
'LASER' => array(
|
||||
'/^(6304|670[69]|6771)[0-9]{12,15}$/',
|
||||
),
|
||||
// Maestro cards begin with either 5018, 5020, 5038, 5893, 6304, 6759, 6761, 6762, 6763 or 0604
|
||||
// They have between 12 and 19 digits.
|
||||
// Maestro international cards begin with 675900..675999 and have between 12 and 19 digits.
|
||||
// Maestro UK cards begin with either 500000..509999 or 560000..699999 and have between 12 and 19 digits.
|
||||
'MAESTRO' => array(
|
||||
'/^(5018|5020|5038|6304|6759|6761|676[23]|0604)[0-9]{8,15}$/',
|
||||
'/^(6759[0-9]{2})[0-9]{6,13}$/',
|
||||
'/^(50[0-9]{4})[0-9]{6,13}$/',
|
||||
'/^5[6-9][0-9]{10,17}$/',
|
||||
'/^6[0-9]{11,18}$/',
|
||||
),
|
||||
// All MasterCard numbers start with the numbers 51 through 55. All have 16 digits.
|
||||
'MASTERCARD' => array(
|
||||
|
|
|
@ -25,8 +25,6 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
|||
class EmailValidator extends ConstraintValidator
|
||||
{
|
||||
/**
|
||||
* isStrict
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isStrict;
|
||||
|
@ -81,7 +79,7 @@ class EmailValidator extends ConstraintValidator
|
|||
|
||||
return;
|
||||
}
|
||||
} elseif (!preg_match('/.+\@.+\..+/', $value)) {
|
||||
} elseif (!preg_match('/^.+\@\S+\.\S+$/', $value)) {
|
||||
if ($this->context instanceof ExecutionContextInterface) {
|
||||
$this->context->buildViolation($constraint->message)
|
||||
->setParameter('{{ value }}', $this->formatValue($value))
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</trans-unit>
|
||||
<trans-unit id="10">
|
||||
<source>This field is missing.</source>
|
||||
<target>Questo campo è manca.</target>
|
||||
<target>Questo campo è mancante.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="11">
|
||||
<source>This value is not a valid date.</source>
|
||||
|
|
|
@ -97,8 +97,10 @@ class CardSchemeValidatorTest extends AbstractConstraintValidatorTest
|
|||
array('LASER', '6771656738314582216'),
|
||||
array('MAESTRO', '6759744069209'),
|
||||
array('MAESTRO', '5020507657408074712'),
|
||||
array('MAESTRO', '5612559223580173965'),
|
||||
array('MAESTRO', '6759744069209'),
|
||||
array('MAESTRO', '6759744069209'),
|
||||
array('MAESTRO', '6594371785970435599'),
|
||||
array('MASTERCARD', '5555555555554444'),
|
||||
array('MASTERCARD', '5105105105105100'),
|
||||
array('VISA', '4111111111111111'),
|
||||
|
|
|
@ -91,6 +91,7 @@ class EmailValidatorTest extends AbstractConstraintValidatorTest
|
|||
array('example'),
|
||||
array('example@'),
|
||||
array('example@localhost'),
|
||||
array('foo@example.com bar'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue