Merge branch '2.7'
* 2.7: (29 commits) [Validator] Added missing Hungarian translation remove usage of deprecated class Fix merge Fix merge CS: fixes [Translation][Extractor] Allow extracting an array of files besides extracting a directory [VarDumper] Fix dumping ThrowingCasterException [Console][Table] Add support for colspan/rowspan + multiple header lines Translator component has default domain for null implemented no need to have default translation domain logic in 3 different places Displays friendly message if the event does not have any registered listeners [VarDumper] Ctrl+click toggles-all and fix IE8 support Implemented check on interface implementation [Form] [TwigBridge] Bootstrap layout whitespace control |Validator] Add PHPUnit hint in AbstractConstraintValidatorTest [VarDumper] implement expand all on ALT+click [WebProfilerBundle] Fixed collapsed profiler menu icons [travis] Kill tests when a new commit has been pushed fixed CS Change behavior to mirror hash_equals() returning early if there is a length mismatch CS fixing ... Conflicts: src/Symfony/Bridge/Twig/composer.json src/Symfony/Bundle/FrameworkBundle/composer.json src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml src/Symfony/Bundle/SecurityBundle/Resources/config/security_acl.xml src/Symfony/Bundle/SecurityBundle/Resources/config/security_acl_dbal.xml src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml src/Symfony/Bundle/SecurityBundle/Resources/config/security_rememberme.xml src/Symfony/Bundle/TwigBundle/Extension/AssetsExtension.php
This commit is contained in:
commit
af6dcb233a
|
@ -1,7 +1,8 @@
|
||||||
phpunit.xml
|
.php_cs.cache
|
||||||
|
autoload.php
|
||||||
composer.lock
|
composer.lock
|
||||||
composer.phar
|
composer.phar
|
||||||
autoload.php
|
|
||||||
package*.tar
|
package*.tar
|
||||||
packages.json
|
packages.json
|
||||||
|
phpunit.xml
|
||||||
/vendor/
|
/vendor/
|
||||||
|
|
22
.php_cs
22
.php_cs
|
@ -3,4 +3,26 @@
|
||||||
return Symfony\CS\Config\Config::create()
|
return Symfony\CS\Config\Config::create()
|
||||||
->setUsingLinter(false)
|
->setUsingLinter(false)
|
||||||
->setUsingCache(true)
|
->setUsingCache(true)
|
||||||
|
->finder(
|
||||||
|
Symfony\CS\Finder\DefaultFinder::create()
|
||||||
|
->in(__DIR__)
|
||||||
|
->exclude(array(
|
||||||
|
// directories containing files with content that is autogenerated by `var_export`, which breaks CS in output code
|
||||||
|
'src/Symfony/Component/DependencyInjection/Tests/Fixtures',
|
||||||
|
'src/Symfony/Component/Routing/Tests/Fixtures/dumper',
|
||||||
|
// fixture templates
|
||||||
|
'src/Symfony/Component/Templating/Tests/Fixtures/templates',
|
||||||
|
// resource templates
|
||||||
|
'src/Symfony/Bundle/FrameworkBundle/Resources/views/Form',
|
||||||
|
))
|
||||||
|
// file content autogenerated by `var_export`
|
||||||
|
->notPath('src/Symfony/Component/Translation/Tests/fixtures/resources.php')
|
||||||
|
// autogenerated xmls
|
||||||
|
->notPath('src/Symfony/Component/Console/Tests/Fixtures/application_1.xml')
|
||||||
|
->notPath('src/Symfony/Component/Console/Tests/Fixtures/application_2.xml')
|
||||||
|
// yml
|
||||||
|
->notPath('src/Symfony/Component/Yaml/Tests/Fixtures/sfTests.yml')
|
||||||
|
// test template
|
||||||
|
->notPath('src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom/_name_entry_label.html.php')
|
||||||
|
)
|
||||||
;
|
;
|
||||||
|
|
|
@ -24,6 +24,8 @@ env:
|
||||||
- SYMFONY_DEPRECATIONS_HELPER=weak
|
- SYMFONY_DEPRECATIONS_HELPER=weak
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then git fetch origin "refs/pull/$TRAVIS_PULL_REQUEST/merge"; else git fetch origin "$TRAVIS_BRANCH"; fi;
|
||||||
|
- if [[ "$TRAVIS_COMMIT" != `git rev-parse FETCH_HEAD` ]]; then echo "Pull request or branch commit hash has changed, aborting!"; exit 1; fi;
|
||||||
- travis_retry sudo apt-get install parallel
|
- travis_retry sudo apt-get install parallel
|
||||||
- composer self-update
|
- composer self-update
|
||||||
- if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then phpenv config-rm xdebug.ini; fi;
|
- if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then phpenv config-rm xdebug.ini; fi;
|
||||||
|
|
|
@ -7,6 +7,7 @@ CHANGELOG
|
||||||
* added LogoutUrlExtension (provides `logout_url` and `logout_path`)
|
* added LogoutUrlExtension (provides `logout_url` and `logout_path`)
|
||||||
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
|
* added an HttpFoundation extension (provides the `absolute_url` and the `relative_path` functions)
|
||||||
* added AssetExtension (provides the `asset` and `asset_version` functions)
|
* added AssetExtension (provides the `asset` and `asset_version` functions)
|
||||||
|
* Added possibility to extract translation messages from a file or files besides extracting from a directory
|
||||||
|
|
||||||
2.5.0
|
2.5.0
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -90,19 +90,11 @@ class TranslationExtension extends \Twig_Extension
|
||||||
|
|
||||||
public function trans($message, array $arguments = array(), $domain = null, $locale = null)
|
public function trans($message, array $arguments = array(), $domain = null, $locale = null)
|
||||||
{
|
{
|
||||||
if (null === $domain) {
|
|
||||||
$domain = 'messages';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->translator->trans($message, $arguments, $domain, $locale);
|
return $this->translator->trans($message, $arguments, $domain, $locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null)
|
public function transchoice($message, $count, array $arguments = array(), $domain = null, $locale = null)
|
||||||
{
|
{
|
||||||
if (null === $domain) {
|
|
||||||
$domain = 'messages';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->translator->transChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale);
|
return $this->translator->transChoice($message, $count, array_merge(array('%count%' => $count), $arguments), $domain, $locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
{% block form_widget_simple -%}
|
{% block form_widget_simple -%}
|
||||||
{% if type is not defined or 'file' != type %}
|
{% if type is not defined or 'file' != type %}
|
||||||
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) %}
|
{%- set attr = attr|merge({class: (attr.class|default('') ~ ' form-control')|trim}) -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{- parent() -}}
|
{{- parent() -}}
|
||||||
{%- endblock form_widget_simple %}
|
{%- endblock form_widget_simple %}
|
||||||
|
@ -42,48 +42,48 @@
|
||||||
{% block datetime_widget -%}
|
{% block datetime_widget -%}
|
||||||
{% if widget == 'single_text' %}
|
{% if widget == 'single_text' %}
|
||||||
{{- block('form_widget_simple') -}}
|
{{- block('form_widget_simple') -}}
|
||||||
{% else %}
|
{% else -%}
|
||||||
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) %}
|
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) -%}
|
||||||
<div {{ block('widget_container_attributes') }}>
|
<div {{ block('widget_container_attributes') }}>
|
||||||
{{ form_errors(form.date) }}
|
{{- form_errors(form.date) -}}
|
||||||
{{ form_errors(form.time) }}
|
{{- form_errors(form.time) -}}
|
||||||
{{ form_widget(form.date, { datetime: true } ) }}
|
{{- form_widget(form.date, { datetime: true } ) -}}
|
||||||
{{ form_widget(form.time, { datetime: true } ) }}
|
{{- form_widget(form.time, { datetime: true } ) -}}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
{%- endblock datetime_widget %}
|
{%- endblock datetime_widget %}
|
||||||
|
|
||||||
{% block date_widget -%}
|
{% block date_widget -%}
|
||||||
{% if widget == 'single_text' %}
|
{% if widget == 'single_text' %}
|
||||||
{{- block('form_widget_simple') -}}
|
{{- block('form_widget_simple') -}}
|
||||||
{% else %}
|
{% else -%}
|
||||||
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) %}
|
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) -%}
|
||||||
{% if datetime is not defined or not datetime %}
|
{% if datetime is not defined or not datetime -%}
|
||||||
<div {{ block('widget_container_attributes') -}}>
|
<div {{ block('widget_container_attributes') -}}>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
{{ date_pattern|replace({
|
{{- date_pattern|replace({
|
||||||
'{{ year }}': form_widget(form.year),
|
'{{ year }}': form_widget(form.year),
|
||||||
'{{ month }}': form_widget(form.month),
|
'{{ month }}': form_widget(form.month),
|
||||||
'{{ day }}': form_widget(form.day),
|
'{{ day }}': form_widget(form.day),
|
||||||
})|raw }}
|
})|raw -}}
|
||||||
{% if datetime is not defined or not datetime %}
|
{% if datetime is not defined or not datetime -%}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endblock date_widget %}
|
{%- endblock date_widget %}
|
||||||
|
|
||||||
{% block time_widget -%}
|
{% block time_widget -%}
|
||||||
{% if widget == 'single_text' %}
|
{% if widget == 'single_text' %}
|
||||||
{{- block('form_widget_simple') -}}
|
{{- block('form_widget_simple') -}}
|
||||||
{% else %}
|
{% else -%}
|
||||||
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) %}
|
{% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) -%}
|
||||||
{% if datetime is not defined or false == datetime %}
|
{% if datetime is not defined or false == datetime -%}
|
||||||
<div {{ block('widget_container_attributes') -}}>
|
<div {{ block('widget_container_attributes') -}}>
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
{{ form_widget(form.hour) }}:{{ form_widget(form.minute) }}{% if with_seconds %}:{{ form_widget(form.second) }}{% endif %}
|
{{- form_widget(form.hour) }}:{{ form_widget(form.minute) }}{% if with_seconds %}:{{ form_widget(form.second) }}{% endif %}
|
||||||
{% if datetime is not defined or false == datetime %}
|
{% if datetime is not defined or false == datetime -%}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{%- endif -%}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endblock time_widget %}
|
{%- endblock time_widget %}
|
||||||
|
|
||||||
|
@ -93,57 +93,57 @@
|
||||||
{%- endblock %}
|
{%- endblock %}
|
||||||
|
|
||||||
{% block choice_widget_expanded -%}
|
{% block choice_widget_expanded -%}
|
||||||
{% if '-inline' in label_attr.class|default('') %}
|
{% if '-inline' in label_attr.class|default('') -%}
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
{% for child in form %}
|
{%- for child in form %}
|
||||||
{{ form_widget(child, {
|
{{- form_widget(child, {
|
||||||
parent_label_class: label_attr.class|default(''),
|
parent_label_class: label_attr.class|default(''),
|
||||||
}) }}
|
}) -}}
|
||||||
{% endfor %}
|
{% endfor -%}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{%- else -%}
|
||||||
<div {{ block('widget_container_attributes') }}>
|
<div {{ block('widget_container_attributes') }}>
|
||||||
{% for child in form %}
|
{%- for child in form %}
|
||||||
{{ form_widget(child, {
|
{{- form_widget(child, {
|
||||||
parent_label_class: label_attr.class|default(''),
|
parent_label_class: label_attr.class|default(''),
|
||||||
}) }}
|
}) -}}
|
||||||
{% endfor %}
|
{% endfor -%}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
{%- endblock choice_widget_expanded %}
|
{%- endblock choice_widget_expanded %}
|
||||||
|
|
||||||
{% block checkbox_widget -%}
|
{% block checkbox_widget -%}
|
||||||
{% set parent_label_class = parent_label_class|default('') %}
|
{% set parent_label_class = parent_label_class|default('') -%}
|
||||||
{% if 'checkbox-inline' in parent_label_class %}
|
{% if 'checkbox-inline' in parent_label_class %}
|
||||||
{{ form_label(form, null, { widget: parent() }) }}
|
{{- form_label(form, null, { widget: parent() }) -}}
|
||||||
{% else %}
|
{% else -%}
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
{{ form_label(form, null, { widget: parent() }) }}
|
{{- form_label(form, null, { widget: parent() }) -}}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
{%- endblock checkbox_widget %}
|
{%- endblock checkbox_widget %}
|
||||||
|
|
||||||
{% block radio_widget -%}
|
{% block radio_widget -%}
|
||||||
{% set parent_label_class = parent_label_class|default('') %}
|
{%- set parent_label_class = parent_label_class|default('') -%}
|
||||||
{% if 'radio-inline' in parent_label_class %}
|
{% if 'radio-inline' in parent_label_class %}
|
||||||
{{ form_label(form, null, { widget: parent() }) }}
|
{{- form_label(form, null, { widget: parent() }) -}}
|
||||||
{% else %}
|
{% else -%}
|
||||||
<div class="radio">
|
<div class="radio">
|
||||||
{{ form_label(form, null, { widget: parent() }) }}
|
{{- form_label(form, null, { widget: parent() }) -}}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{%- endif %}
|
||||||
{%- endblock radio_widget %}
|
{%- endblock radio_widget %}
|
||||||
|
|
||||||
{# Labels #}
|
{# Labels #}
|
||||||
|
|
||||||
{% block form_label -%}
|
{% block form_label -%}
|
||||||
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' control-label')|trim}) %}
|
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' control-label')|trim}) -%}
|
||||||
{{- parent() -}}
|
{{- parent() -}}
|
||||||
{%- endblock form_label %}
|
{%- endblock form_label %}
|
||||||
|
|
||||||
{% block choice_label %}
|
{% block choice_label -%}
|
||||||
{# remove the checkbox-inline and radio-inline class, it's only useful for embed labels #}
|
{# remove the checkbox-inline and radio-inline class, it's only useful for embed labels #}
|
||||||
{% set label_attr = label_attr|merge({class: label_attr.class|default('')|replace({'checkbox-inline': '', 'radio-inline': ''})|trim}) %}
|
{%- set label_attr = label_attr|merge({class: label_attr.class|default('')|replace({'checkbox-inline': '', 'radio-inline': ''})|trim}) -%}
|
||||||
{{- block('form_label') -}}
|
{{- block('form_label') -}}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -168,8 +168,8 @@
|
||||||
{% set label = name|humanize %}
|
{% set label = name|humanize %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
|
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
|
||||||
{{ widget|raw }}
|
{{- widget|raw -}}
|
||||||
{{ label is not sameas(false) ? label|trans({}, translation_domain) }}
|
{{- label is not sameas(false) ? label|trans({}, translation_domain) -}}
|
||||||
</label>
|
</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock checkbox_radio_label %}
|
{% endblock checkbox_radio_label %}
|
||||||
|
@ -178,9 +178,9 @@
|
||||||
|
|
||||||
{% block form_row -%}
|
{% block form_row -%}
|
||||||
<div class="form-group{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
|
<div class="form-group{% if (not compound or force_error|default(false)) and not valid %} has-error{% endif %}">
|
||||||
{{ form_label(form) }}
|
{{- form_label(form) -}}
|
||||||
{{ form_widget(form) }}
|
{{- form_widget(form) -}}
|
||||||
{{ form_errors(form) }}
|
{{- form_errors(form) -}}
|
||||||
</div>
|
</div>
|
||||||
{%- endblock form_row %}
|
{%- endblock form_row %}
|
||||||
|
|
||||||
|
@ -192,35 +192,35 @@
|
||||||
|
|
||||||
{% block choice_row -%}
|
{% block choice_row -%}
|
||||||
{% set force_error = true %}
|
{% set force_error = true %}
|
||||||
{{ block('form_row') }}
|
{{- block('form_row') }}
|
||||||
{%- endblock choice_row %}
|
{%- endblock choice_row %}
|
||||||
|
|
||||||
{% block date_row -%}
|
{% block date_row -%}
|
||||||
{% set force_error = true %}
|
{% set force_error = true %}
|
||||||
{{ block('form_row') }}
|
{{- block('form_row') }}
|
||||||
{%- endblock date_row %}
|
{%- endblock date_row %}
|
||||||
|
|
||||||
{% block time_row -%}
|
{% block time_row -%}
|
||||||
{% set force_error = true %}
|
{% set force_error = true %}
|
||||||
{{ block('form_row') }}
|
{{- block('form_row') }}
|
||||||
{%- endblock time_row %}
|
{%- endblock time_row %}
|
||||||
|
|
||||||
{% block datetime_row -%}
|
{% block datetime_row -%}
|
||||||
{% set force_error = true %}
|
{% set force_error = true %}
|
||||||
{{ block('form_row') }}
|
{{- block('form_row') }}
|
||||||
{%- endblock datetime_row %}
|
{%- endblock datetime_row %}
|
||||||
|
|
||||||
{% block checkbox_row -%}
|
{% block checkbox_row -%}
|
||||||
<div class="form-group{% if not valid %} has-error{% endif %}">
|
<div class="form-group{% if not valid %} has-error{% endif %}">
|
||||||
{{ form_widget(form) }}
|
{{- form_widget(form) -}}
|
||||||
{{ form_errors(form) }}
|
{{- form_errors(form) -}}
|
||||||
</div>
|
</div>
|
||||||
{%- endblock checkbox_row %}
|
{%- endblock checkbox_row %}
|
||||||
|
|
||||||
{% block radio_row -%}
|
{% block radio_row -%}
|
||||||
<div class="form-group{% if not valid %} has-error{% endif %}">
|
<div class="form-group{% if not valid %} has-error{% endif %}">
|
||||||
{{ form_widget(form) }}
|
{{- form_widget(form) -}}
|
||||||
{{ form_errors(form) }}
|
{{- form_errors(form) -}}
|
||||||
</div>
|
</div>
|
||||||
{%- endblock radio_row %}
|
{%- endblock radio_row %}
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@
|
||||||
{% if form.parent %}<span class="help-block">{% else %}<div class="alert alert-danger">{% endif %}
|
{% if form.parent %}<span class="help-block">{% else %}<div class="alert alert-danger">{% endif %}
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
{%- for error in errors -%}
|
{%- for error in errors -%}
|
||||||
<li><span class="glyphicon glyphicon-exclamation-sign"></span> {{ error.message }}</li>
|
<li><span class="glyphicon glyphicon-exclamation-sign"></span>{{ error.message }}</li>
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
</ul>
|
</ul>
|
||||||
{% if form.parent %}</span>{% else %}</div>{% endif %}
|
{% if form.parent %}</span>{% else %}</div>{% endif %}
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
<?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\Bridge\Twig\Tests\Extension;
|
||||||
|
|
||||||
|
use Symfony\Bridge\Twig\Extension\FormExtension;
|
||||||
|
use Symfony\Bridge\Twig\Form\TwigRenderer;
|
||||||
|
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
|
||||||
|
use Symfony\Bridge\Twig\Extension\TranslationExtension;
|
||||||
|
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
|
||||||
|
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\Form\Tests\AbstractBootstrap3LayoutTest;
|
||||||
|
|
||||||
|
class FormExtensionBootstrap3LayoutTest extends AbstractBootstrap3LayoutTest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var FormExtension
|
||||||
|
*/
|
||||||
|
protected $extension;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$rendererEngine = new TwigRendererEngine(array(
|
||||||
|
'bootstrap_3_layout.html.twig',
|
||||||
|
'custom_widgets.html.twig',
|
||||||
|
));
|
||||||
|
$renderer = new TwigRenderer($rendererEngine, $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface'));
|
||||||
|
|
||||||
|
$this->extension = new FormExtension($renderer);
|
||||||
|
|
||||||
|
$loader = new StubFilesystemLoader(array(
|
||||||
|
__DIR__.'/../../Resources/views/Form',
|
||||||
|
__DIR__.'/Fixtures/templates/form',
|
||||||
|
));
|
||||||
|
|
||||||
|
$environment = new \Twig_Environment($loader, array('strict_variables' => true));
|
||||||
|
$environment->addExtension(new TranslationExtension(new StubTranslator()));
|
||||||
|
$environment->addExtension($this->extension);
|
||||||
|
|
||||||
|
$this->extension->initRuntime($environment);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
|
||||||
|
$this->extension = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderForm(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderEnctype(FormView $view)
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'enctype');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderLabel(FormView $view, $label = null, array $vars = array())
|
||||||
|
{
|
||||||
|
if ($label !== null) {
|
||||||
|
$vars += array('label' => $label);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'label', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderErrors(FormView $view)
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'errors');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderWidget(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'widget', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderRow(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'row', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderRest(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->searchAndRenderBlock($view, 'rest', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderStart(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form_start', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderEnd(FormView $view, array $vars = array())
|
||||||
|
{
|
||||||
|
return (string) $this->extension->renderer->renderBlock($view, 'form_end', $vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setTheme(FormView $view, array $themes)
|
||||||
|
{
|
||||||
|
$this->extension->renderer->setTheme($view, $themes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
<h1>{{ 'Hi!'|trans }}</h1>
|
|
@ -83,4 +83,42 @@ class TwigExtractorTest extends \PHPUnit_Framework_TestCase
|
||||||
$extractor = new TwigExtractor($twig);
|
$extractor = new TwigExtractor($twig);
|
||||||
$extractor->extract(__DIR__.'/../Fixtures', new MessageCatalogue('en'));
|
$extractor->extract(__DIR__.'/../Fixtures', new MessageCatalogue('en'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider resourceProvider
|
||||||
|
*/
|
||||||
|
public function testExtractWithFiles($resource)
|
||||||
|
{
|
||||||
|
$loader = new \Twig_Loader_Array(array());
|
||||||
|
$twig = new \Twig_Environment($loader, array(
|
||||||
|
'strict_variables' => true,
|
||||||
|
'debug' => true,
|
||||||
|
'cache' => false,
|
||||||
|
'autoescape' => false,
|
||||||
|
));
|
||||||
|
$twig->addExtension(new TranslationExtension($this->getMock('Symfony\Component\Translation\TranslatorInterface')));
|
||||||
|
|
||||||
|
$extractor = new TwigExtractor($twig);
|
||||||
|
$catalogue = new MessageCatalogue('en');
|
||||||
|
$extractor->extract($resource, $catalogue);
|
||||||
|
|
||||||
|
$this->assertTrue($catalogue->has('Hi!', 'messages'));
|
||||||
|
$this->assertEquals('Hi!', $catalogue->get('Hi!', 'messages'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function resourceProvider()
|
||||||
|
{
|
||||||
|
$directory = __DIR__.'/../Fixtures/extractor/';
|
||||||
|
|
||||||
|
return array(
|
||||||
|
array($directory.'with_translations.html.twig'),
|
||||||
|
array(array($directory.'with_translations.html.twig')),
|
||||||
|
array(array(new \SplFileInfo($directory.'with_translations.html.twig'))),
|
||||||
|
array(new \ArrayObject(array($directory.'with_translations.html.twig'))),
|
||||||
|
array(new \ArrayObject(array(new \SplFileInfo($directory.'with_translations.html.twig')))),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
namespace Symfony\Bridge\Twig\Translation;
|
namespace Symfony\Bridge\Twig\Translation;
|
||||||
|
|
||||||
use Symfony\Component\Finder\Finder;
|
use Symfony\Component\Finder\Finder;
|
||||||
|
use Symfony\Component\Translation\Extractor\AbstractFileExtractor;
|
||||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||||
use Symfony\Component\Translation\MessageCatalogue;
|
use Symfony\Component\Translation\MessageCatalogue;
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||||
* @author Michel Salib <michelsalib@hotmail.com>
|
* @author Michel Salib <michelsalib@hotmail.com>
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
*/
|
*/
|
||||||
class TwigExtractor implements ExtractorInterface
|
class TwigExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Default domain for found messages.
|
* Default domain for found messages.
|
||||||
|
@ -52,11 +53,9 @@ class TwigExtractor implements ExtractorInterface
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function extract($directory, MessageCatalogue $catalogue)
|
public function extract($resource, MessageCatalogue $catalogue)
|
||||||
{
|
{
|
||||||
// load any existing translation files
|
$files = $this->extractFiles($resource);
|
||||||
$finder = new Finder();
|
|
||||||
$files = $finder->files()->name('*.twig')->sortByName()->in($directory);
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
try {
|
try {
|
||||||
$this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
|
$this->extractTemplate(file_get_contents($file->getPathname()), $catalogue);
|
||||||
|
@ -89,4 +88,26 @@ class TwigExtractor implements ExtractorInterface
|
||||||
|
|
||||||
$visitor->disable();
|
$visitor->disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function canBeExtracted($file)
|
||||||
|
{
|
||||||
|
return $this->isFile($file) && 'twig' === pathinfo($file, PATHINFO_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|array $directory
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function extractFromDirectory($directory)
|
||||||
|
{
|
||||||
|
$finder = new Finder();
|
||||||
|
|
||||||
|
return $finder->files()->name('*.twig')->in($directory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
2.7.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Added possibility to extract translation messages from a file or files besides extracting from a directory
|
||||||
|
|
||||||
2.6.0
|
2.6.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
|
@ -58,14 +58,28 @@ EOF
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
|
$dispatcher = $this->getEventDispatcher();
|
||||||
|
|
||||||
if ($event = $input->getArgument('event')) {
|
if ($event = $input->getArgument('event')) {
|
||||||
|
if (!$dispatcher->hasListeners($event)) {
|
||||||
|
$formatter = $this->getHelperSet()->get('formatter');
|
||||||
|
|
||||||
|
$formattedBlock = $formatter->formatBlock(
|
||||||
|
sprintf('[NOTE] The event "%s" does not have any registered listeners.', $event),
|
||||||
|
'fg=yellow',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
$output->writeln($formattedBlock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$options = array('event' => $event);
|
$options = array('event' => $event);
|
||||||
} else {
|
} else {
|
||||||
$options = array();
|
$options = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
$dispatcher = $this->getEventDispatcher();
|
|
||||||
|
|
||||||
$helper = new DescriptorHelper();
|
$helper = new DescriptorHelper();
|
||||||
$options['format'] = $input->getOption('format');
|
$options['format'] = $input->getOption('format');
|
||||||
$options['raw_text'] = $input->getOption('raw');
|
$options['raw_text'] = $input->getOption('raw');
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
$required = false;
|
$required = false;
|
||||||
endif; ?>
|
endif; ?>
|
||||||
<?php echo $view['form']->block($form, 'widget_attributes', array(
|
<?php echo $view['form']->block($form, 'widget_attributes', array(
|
||||||
'required' => $required
|
'required' => $required,
|
||||||
)) ?>
|
)) ?>
|
||||||
<?php if ($multiple): ?> multiple="multiple"<?php endif ?>
|
<?php if ($multiple): ?> multiple="multiple"<?php endif ?>
|
||||||
>
|
>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : "hidden")) ?>
|
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'hidden')) ?>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : "number")) ?>
|
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'number')) ?>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : "text")) ?>
|
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'text')) ?>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : "password")) ?>
|
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'password')) ?>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : "text")) ?> %
|
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'text')) ?> %
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : "search")) ?>
|
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'search')) ?>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : "url")) ?>
|
<?php echo $view['form']->block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'url')) ?>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
This template is used for translation message extraction tests
|
This template is used for translation message extraction tests
|
||||||
<?php echo $view['translator']->trans('single-quoted key') ?>
|
<?php echo $view['translator']->trans('single-quoted key') ?>
|
||||||
<?php echo $view['translator']->trans("double-quoted key") ?>
|
<?php echo $view['translator']->trans('double-quoted key') ?>
|
||||||
<?php echo $view['translator']->trans(<<<EOF
|
<?php echo $view['translator']->trans(<<<EOF
|
||||||
heredoc key
|
heredoc key
|
||||||
EOF
|
EOF
|
||||||
|
@ -15,11 +15,11 @@ EOF
|
||||||
<?php echo $view['translator']->trans(
|
<?php echo $view['translator']->trans(
|
||||||
'single-quoted key with whitespace and nonescaped \$\n\' sequences'
|
'single-quoted key with whitespace and nonescaped \$\n\' sequences'
|
||||||
) ?>
|
) ?>
|
||||||
<?php echo $view['translator']->trans( <<<EOF
|
<?php echo $view['translator']->trans(<<<EOF
|
||||||
heredoc key with whitespace and escaped \$\n sequences
|
heredoc key with whitespace and escaped \$\n sequences
|
||||||
EOF
|
EOF
|
||||||
) ?>
|
) ?>
|
||||||
<?php echo $view['translator']->trans( <<<'EOF'
|
<?php echo $view['translator']->trans(<<<'EOF'
|
||||||
nowdoc key with whitespace and nonescaped \$\n sequences
|
nowdoc key with whitespace and nonescaped \$\n sequences
|
||||||
EOF
|
EOF
|
||||||
) ?>
|
) ?>
|
||||||
|
|
|
@ -17,7 +17,12 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||||
|
|
||||||
class PhpExtractorTest extends TestCase
|
class PhpExtractorTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testExtraction()
|
/**
|
||||||
|
* @dataProvider resourcesProvider
|
||||||
|
*
|
||||||
|
* @param array|string $resource
|
||||||
|
*/
|
||||||
|
public function testExtraction($resource)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
$extractor = new PhpExtractor();
|
$extractor = new PhpExtractor();
|
||||||
|
@ -25,7 +30,7 @@ class PhpExtractorTest extends TestCase
|
||||||
$catalogue = new MessageCatalogue('en');
|
$catalogue = new MessageCatalogue('en');
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
$extractor->extract(__DIR__.'/../Fixtures/Resources/views/', $catalogue);
|
$extractor->extract($resource, $catalogue);
|
||||||
|
|
||||||
$expectedHeredoc = <<<EOF
|
$expectedHeredoc = <<<EOF
|
||||||
heredoc key with whitespace and escaped \$\n sequences
|
heredoc key with whitespace and escaped \$\n sequences
|
||||||
|
@ -50,4 +55,28 @@ EOF;
|
||||||
|
|
||||||
$this->assertEquals($expectedCatalogue, $actualCatalogue);
|
$this->assertEquals($expectedCatalogue, $actualCatalogue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function resourcesProvider()
|
||||||
|
{
|
||||||
|
$directory = __DIR__.'/../Fixtures/Resources/views/';
|
||||||
|
$splFiles = array();
|
||||||
|
foreach (new \DirectoryIterator($directory) as $fileInfo) {
|
||||||
|
if ($fileInfo->isDot()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('translation.html.php' === $fileInfo->getBasename()) {
|
||||||
|
$phpFile = $fileInfo->getPathname();
|
||||||
|
}
|
||||||
|
$splFiles[] = $fileInfo->getFileInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
array($directory),
|
||||||
|
array($phpFile),
|
||||||
|
array(glob($directory.'*')),
|
||||||
|
array($splFiles),
|
||||||
|
array(new \ArrayObject(glob($directory.'*'))),
|
||||||
|
array(new \ArrayObject($splFiles)),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
namespace Symfony\Bundle\FrameworkBundle\Translation;
|
namespace Symfony\Bundle\FrameworkBundle\Translation;
|
||||||
|
|
||||||
use Symfony\Component\Finder\Finder;
|
use Symfony\Component\Finder\Finder;
|
||||||
|
use Symfony\Component\Translation\Extractor\AbstractFileExtractor;
|
||||||
use Symfony\Component\Translation\MessageCatalogue;
|
use Symfony\Component\Translation\MessageCatalogue;
|
||||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||||
*
|
*
|
||||||
* @author Michel Salib <michelsalib@hotmail.com>
|
* @author Michel Salib <michelsalib@hotmail.com>
|
||||||
*/
|
*/
|
||||||
class PhpExtractor implements ExtractorInterface
|
class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface
|
||||||
{
|
{
|
||||||
const MESSAGE_TOKEN = 300;
|
const MESSAGE_TOKEN = 300;
|
||||||
|
|
||||||
|
@ -54,11 +55,9 @@ class PhpExtractor implements ExtractorInterface
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function extract($directory, MessageCatalogue $catalog)
|
public function extract($resource, MessageCatalogue $catalog)
|
||||||
{
|
{
|
||||||
// load any existing translation files
|
$files = $this->extractFiles($resource);
|
||||||
$finder = new Finder();
|
|
||||||
$files = $finder->files()->name('*.php')->in($directory);
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$this->parseTokens(token_get_all(file_get_contents($file)), $catalog);
|
$this->parseTokens(token_get_all(file_get_contents($file)), $catalog);
|
||||||
}
|
}
|
||||||
|
@ -174,4 +173,28 @@ class PhpExtractor implements ExtractorInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function canBeExtracted($file)
|
||||||
|
{
|
||||||
|
return $this->isFile($file) && 'php' === pathinfo($file, PATHINFO_EXTENSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|array $directory
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function extractFromDirectory($directory)
|
||||||
|
{
|
||||||
|
$finder = new Finder();
|
||||||
|
|
||||||
|
return $finder->files()->name('*.php')->in($directory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ interface SecurityFactoryInterface
|
||||||
/**
|
/**
|
||||||
* Defines the position at which the provider is called.
|
* Defines the position at which the provider is called.
|
||||||
* Possible values: pre_auth, form, http, and remember_me.
|
* Possible values: pre_auth, form, http, and remember_me.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getPosition();
|
public function getPosition();
|
||||||
|
|
|
@ -43,10 +43,10 @@
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.encoder_factory.generic" class="Symfony\Component\Security\Core\Encoder\EncoderFactory" public="false">
|
<service id="security.encoder_factory.generic" class="Symfony\Component\Security\Core\Encoder\EncoderFactory" public="false">
|
||||||
<argument type="collection"></argument>
|
<argument type="collection" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.encoder_factory" alias="security.encoder_factory.generic"></service>
|
<service id="security.encoder_factory" alias="security.encoder_factory.generic" />
|
||||||
|
|
||||||
<service id="security.user_password_encoder.generic" class="Symfony\Component\Security\Core\Encoder\UserPasswordEncoder" public="false">
|
<service id="security.user_password_encoder.generic" class="Symfony\Component\Security\Core\Encoder\UserPasswordEncoder" public="false">
|
||||||
<argument type="service" id="security.encoder_factory"></argument>
|
<argument type="service" id="security.encoder_factory"></argument>
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
|
|
||||||
<!-- Authorization related services -->
|
<!-- Authorization related services -->
|
||||||
<service id="security.access.decision_manager" class="Symfony\Component\Security\Core\Authorization\AccessDecisionManager" public="false">
|
<service id="security.access.decision_manager" class="Symfony\Component\Security\Core\Authorization\AccessDecisionManager" public="false">
|
||||||
<argument type="collection"></argument>
|
<argument type="collection" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.role_hierarchy" class="Symfony\Component\Security\Core\Role\RoleHierarchy" public="false">
|
<service id="security.role_hierarchy" class="Symfony\Component\Security\Core\Role\RoleHierarchy" public="false">
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||||
|
|
||||||
<services>
|
<services>
|
||||||
<service id="security.acl.object_identity_retrieval_strategy" class="Symfony\Component\Security\Acl\Domain\ObjectIdentityRetrievalStrategy" public="false"></service>
|
<service id="security.acl.object_identity_retrieval_strategy" class="Symfony\Component\Security\Acl\Domain\ObjectIdentityRetrievalStrategy" public="false" />
|
||||||
|
|
||||||
<service id="security.acl.security_identity_retrieval_strategy" class="Symfony\Component\Security\Acl\Domain\SecurityIdentityRetrievalStrategy" public="false">
|
<service id="security.acl.security_identity_retrieval_strategy" class="Symfony\Component\Security\Acl\Domain\SecurityIdentityRetrievalStrategy" public="false">
|
||||||
<argument type="service" id="security.role_hierarchy" />
|
<argument type="service" id="security.role_hierarchy" />
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
</call>
|
</call>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.acl.permission.map" class="Symfony\Component\Security\Acl\Permission\BasicPermissionMap" public="false"></service>
|
<service id="security.acl.permission.map" class="Symfony\Component\Security\Acl\Permission\BasicPermissionMap" public="false" />
|
||||||
|
|
||||||
<service id="security.acl.voter.basic_permissions" class="Symfony\Component\Security\Acl\Voter\AclVoter" public="false">
|
<service id="security.acl.voter.basic_permissions" class="Symfony\Component\Security\Acl\Voter\AclVoter" public="false">
|
||||||
<tag name="monolog.logger" channel="security" />
|
<tag name="monolog.logger" channel="security" />
|
||||||
|
|
|
@ -42,7 +42,5 @@
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.acl.cache.doctrine.cache_impl" alias="doctrine.orm.default_result_cache" public="false" />
|
<service id="security.acl.cache.doctrine.cache_impl" alias="doctrine.orm.default_result_cache" public="false" />
|
||||||
|
|
||||||
<service id="security.acl.permission.map" class="Symfony\Component\Security\Acl\Permission\BasicPermissionMap" public="false"></service>
|
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
<service id="security.context_listener" class="Symfony\Component\Security\Http\Firewall\ContextListener" public="false">
|
<service id="security.context_listener" class="Symfony\Component\Security\Http\Firewall\ContextListener" public="false">
|
||||||
<tag name="monolog.logger" channel="security" />
|
<tag name="monolog.logger" channel="security" />
|
||||||
<argument type="service" id="security.token_storage" />
|
<argument type="service" id="security.token_storage" />
|
||||||
<argument type="collection"></argument>
|
<argument type="collection" />
|
||||||
<argument /> <!-- Provider Key -->
|
<argument /> <!-- Provider Key -->
|
||||||
<argument type="service" id="logger" on-invalid="null" />
|
<argument type="service" id="logger" on-invalid="null" />
|
||||||
<argument type="service" id="event_dispatcher" on-invalid="null"/>
|
<argument type="service" id="event_dispatcher" on-invalid="null"/>
|
||||||
|
@ -50,7 +50,9 @@
|
||||||
<argument type="service" id="security.logout.success_handler" />
|
<argument type="service" id="security.logout.success_handler" />
|
||||||
<argument /> <!-- Options -->
|
<argument /> <!-- Options -->
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.logout.handler.session" class="Symfony\Component\Security\Http\Logout\SessionLogoutHandler" public="false" />
|
<service id="security.logout.handler.session" class="Symfony\Component\Security\Http\Logout\SessionLogoutHandler" public="false" />
|
||||||
|
|
||||||
<service id="security.logout.handler.cookie_clearing" class="Symfony\Component\Security\Http\Logout\CookieClearingLogoutHandler" public="false" abstract="true" />
|
<service id="security.logout.handler.cookie_clearing" class="Symfony\Component\Security\Http\Logout\CookieClearingLogoutHandler" public="false" abstract="true" />
|
||||||
|
|
||||||
<service id="security.logout.success_handler" class="Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler" public="false" abstract="true">
|
<service id="security.logout.success_handler" class="Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler" public="false" abstract="true">
|
||||||
|
@ -71,7 +73,7 @@
|
||||||
<argument />
|
<argument />
|
||||||
<argument type="service" id="security.authentication.success_handler" />
|
<argument type="service" id="security.authentication.success_handler" />
|
||||||
<argument type="service" id="security.authentication.failure_handler" />
|
<argument type="service" id="security.authentication.failure_handler" />
|
||||||
<argument type="collection"></argument>
|
<argument type="collection" />
|
||||||
<argument type="service" id="logger" on-invalid="null" />
|
<argument type="service" id="logger" on-invalid="null" />
|
||||||
<argument type="service" id="event_dispatcher" on-invalid="null" />
|
<argument type="service" id="event_dispatcher" on-invalid="null" />
|
||||||
</service>
|
</service>
|
||||||
|
@ -103,8 +105,7 @@
|
||||||
<service id="security.authentication.listener.form"
|
<service id="security.authentication.listener.form"
|
||||||
class="Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener"
|
class="Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener"
|
||||||
parent="security.authentication.listener.abstract"
|
parent="security.authentication.listener.abstract"
|
||||||
abstract="true">
|
abstract="true" />
|
||||||
</service>
|
|
||||||
|
|
||||||
<service id="security.authentication.listener.simple_form"
|
<service id="security.authentication.listener.simple_form"
|
||||||
class="Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener"
|
class="Symfony\Component\Security\Http\Firewall\SimpleFormAuthenticationListener"
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<argument type="service" id="security.user_checker" />
|
<argument type="service" id="security.user_checker" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service id="security.rememberme.token.provider.in_memory" class="Symfony\Component\Security\Core\Authentication\RememberMe\InMemoryTokenProvider" public="false"/>
|
<service id="security.rememberme.token.provider.in_memory" class="Symfony\Component\Security\Core\Authentication\RememberMe\InMemoryTokenProvider" public="false" />
|
||||||
|
|
||||||
<service id="security.authentication.rememberme.services.abstract" abstract="true" public="false">
|
<service id="security.authentication.rememberme.services.abstract" abstract="true" public="false">
|
||||||
<tag name="monolog.logger" channel="security" />
|
<tag name="monolog.logger" channel="security" />
|
||||||
|
@ -40,8 +40,7 @@
|
||||||
<service id="security.authentication.rememberme.services.simplehash"
|
<service id="security.authentication.rememberme.services.simplehash"
|
||||||
class="Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices"
|
class="Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices"
|
||||||
parent="security.authentication.rememberme.services.abstract"
|
parent="security.authentication.rememberme.services.abstract"
|
||||||
abstract="true">
|
abstract="true" />
|
||||||
</service>
|
|
||||||
|
|
||||||
<service id="security.rememberme.response_listener" class="Symfony\Component\Security\Http\RememberMe\ResponseListener">
|
<service id="security.rememberme.response_listener" class="Symfony\Component\Security\Http\RememberMe\ResponseListener">
|
||||||
<tag name="kernel.event_subscriber" />
|
<tag name="kernel.event_subscriber" />
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
<li class="minimize">
|
<li class="minimize">
|
||||||
<a href="javascript:void(0);" title="Minimize toolbar" onclick="return toggleMenuPanels();">
|
<a href="javascript:void(0);" title="Minimize toolbar" onclick="return toggleMenuPanels();">
|
||||||
<span class="label">
|
<span class="label">
|
||||||
<span class="icon"><svg width="30" height="33" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 30 33" enable-background="new 0 0 30 33" xml:space="preserve"><path fill="#3F3F3F" d="M15 5C8.4 5 3 10.4 3 17c0 6.6 5.4 12 12 12s12-5.4 12-12C27 10.4 21.6 5 15 5z M19.1 21.5l-1.8 1.8L10.9 17 l6.3-6.3l1.8 1.8L14.6 17L19.1 21.5z"/></svg></span>
|
<span class="icon"><svg id="minimizePanelIcon" width="30" height="33" xmlns="http://www.w3.org/2000/svg" version="1.1" x="0px" y="0px" viewBox="0 0 30 33" enable-background="new 0 0 30 33" xml:space="preserve"><path fill="#3F3F3F" d="M15 5C8.4 5 3 10.4 3 17c0 6.6 5.4 12 12 12s12-5.4 12-12C27 10.4 21.6 5 15 5z M19.1 21.5l-1.8 1.8L10.9 17 l6.3-6.3l1.8 1.8L14.6 17L19.1 21.5z"/></svg></span>
|
||||||
<strong>Minimize</strong>
|
<strong>Minimize</strong>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -63,9 +63,7 @@
|
||||||
<script>//<![CDATA[
|
<script>//<![CDATA[
|
||||||
|
|
||||||
function toggleMenuPanels(state, doSave) {
|
function toggleMenuPanels(state, doSave) {
|
||||||
var leftIconPath = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAhCAYAAADOHBvaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4tJREFUeNrkl19IU1Ecx7fZJN2arhq2JUWJlEZL1MAm1B582GBErMJqtabzRRAqFAYa9OfFFx+KQEG3MkYRZkkEJUUwctVSKCJWJojL1ZiydJvLtNXW98AW1znv7t0CHzrw5Xe3nXM/O/f8zvf8LjcajXJWo/E4q9T+P/CaNMZw29rahBMTE3LyoaKi4m1zc/M865swSS6bzZbT09NzfG5urjYUCikikYiQ+ntWVlZQKBQ+F4lE/Var9Ta+CmcK5hsMhpNer/fiwsLCFiYzycnJGZfJZOctFss9uj+wInhwcDDfbDb3+Hy+I+msoVQqNZtMpnNlZWUhxuChoaENHR0djwOBwN5MEkgsFtsGBgY0uPzOJKtzu7q6rmcKJW12dlaJpbqGy7WpwPyWlpZGj8dzkMX9B+l+dLlcda2trbrEHbQEPDY2Jh0dHTWxgF5AxqsRz9J1cjqdlxDWrwTO7u3tNWK7SFhAL8e221WE7pU6Ytk2t7e311JnTQWLJycntWyhpCmVShXCKboBMJyjCKJlzgVzKJiamtrBAKoH1JoAvU+2MN2g6enp3QgboRnqjHl2u70kHA7zU0APpQMlze/357vd7gKyhang7GAwKEsx1gLoAwp0E8JdJtB4w1LK4sw4OAtWl51inBGwAxT/9iLUQb+ZgsHgJ4I5hYWFAQZjbYBrKPB+hGNM4DweL1pUVBRMzOpweXm5WyAQ/GIAfwj4GbZwiUTyIy8vby7eLw4mQH9paamX4VO7kgTeTTeguLjYg0AOjAgVTD58UygUb1i41l84ogGhka4z+rwi9p3MQHwajeYRjrNFlvBbiDfoOmFtQzU1NU/J5JKBA3w+/71er3/J8hA6kSKpOPX19c9w+YH4VDIwqRbG1Wr1HZVK5eX8o6bVaj9XV1cTk3HFcinpsUjs7AWKNwvWO5gpFI93pqmpyYxLB0neVBUIcaI90OHOzs7TfX19ErZA8niNRuNXnU53M2apTmiBSc0lgEoh9cjIiBYV5i6c1YxKYblc/rOhoeEdIin2nkCfoHk2VSYpV7ZCVdB+h8OxDyocHh4WoEJZskRwvUhVVVUIcldWVtrx1XPoNfQFWkynvCWzzIe2QSXQTmg7Od5QT+WinuagliaFnI8kJvQxJpJIATo34zJ8WyR/YF2sfBFDpKCPHyqLMUeajSVniJq9mYKXjUtwPdY34a7W+/EfAQYAZM5kh2zoNWsAAAAASUVORK5CYII=",
|
var menu = document.getElementById('navigation'), savedState = Sfjs.getPreference('menu/displayState'),
|
||||||
rightIconPath = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAhCAYAAADOHBvaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4tJREFUeNrsl11IU2EYx91ytrnpmmy4TYNkqGhEJGiiabuQ2EAiZ1kZW9NtF4pgoBB40weJeCHVjReygVmuIhP6gLoJJNQGadhiJcLa2sb8KN2nrprbel7YYh7WzjnOsIsO/Hnes533/Z33PB/nOZRIJJK2GwflP/ifBg8MDGTOzs4eQeOCggJjb2+vH4aRvwGmyeXyZq/Xe9rv99eGQqHs+D+pVKqfxWJNZ2VlPdRoNPfFYnEgVTBNpVI1Op3OG4FAQETkDul0uo3P518dHh6+B6dB0uC5uTlWf3//zcXFRfV2fMjlcsfUarVGIpG4yYCZDQ0Nz10ulziVAGKz2W+7u7ulNTU1q0TAdKVSOWi1Wlt2InqFQuFTvV5/HoYbW+ICc116T0/PBQLQl0TBEB8nYddtKF6SgXNMJtM1nLUuTUxMSMFeIQqfn5+/vLCwIPgTOL2vr++sx+PJS7LGEEBvowHY60ThkII8iHIVDDMSgbMtFssZnDXkkKOS2AkZuM1mk4HhJAJzV1ZWDuHMZ4DGE8AVeODl5eVin8+XiwVT7HZ7rtvt3kfg5hPB74I5lWxSMBikTU5OlsSYMTAVHoWQRJYg+COA8+PgT8Dokk2CkiuM+fk3mMFg0EiAQ6AWgC3FfoCbOA5GlfRuGQwE3bPFxyKRyAvFPkIQeg6gY3HQerRpvIn5+fkerI9DUN58PB4vsA1oJ5hneFAmk7lZVlZmj704YuAwSrfCwkInzvyhBNBbRHxTWlqK3IJeGJvYdHLBQm9w5rfBNUqyUHRUVVW9A7Ma3eSWlwRK7np4/w6azWYWzjp6UDNRqEAg+DEyMtJJo9Eew+k37I59oI+tra2vIMjw1momkQFpCoViGqAfYOhJVLnQs7dWV1ePy2SyLzvV1EEjsCSVSh/A0BzfkWC3hpxv6Ojo0NbV1a2lCgW/eru6ulBRmQKt4TYCoIMg2ejo6EWdTpcXDodJQ5uamr62t7ffgSHy63tQgEjrkwkqBp0wGo2NWq32MNgMIsCioqJN6DRN5eXl43D6AsUNaJ1Ml7kXFRvQUVDtzMzMMYPBsB/EcjgcVEx7E66oqFivrKx0gFBKvkYuA6FY+b6d9hbVVTboAKgkKtTmcqHgM6G/TuNwOBvRFPmMmg3QJ5Alvlik0tCng1Bu50TznRV9Iuj4iaoeKkDRAPIlA6b67UTBlFvSi+zaR9svAQYA6+V18DvfH/8AAAAASUVORK5CYII=",
|
|
||||||
menu = document.getElementById('navigation'), savedState = Sfjs.getPreference('menu/displayState'),
|
|
||||||
displayState, elem, className;
|
displayState, elem, className;
|
||||||
|
|
||||||
if (null === savedState) {
|
if (null === savedState) {
|
||||||
|
@ -84,13 +82,9 @@
|
||||||
if ('block' === displayState) {
|
if ('block' === displayState) {
|
||||||
Sfjs.removeClass(menu, 'collapsed-menu');
|
Sfjs.removeClass(menu, 'collapsed-menu');
|
||||||
Sfjs.removeClass(menu.parentNode.parentNode, 'collapsed-menu-parents');
|
Sfjs.removeClass(menu.parentNode.parentNode, 'collapsed-menu-parents');
|
||||||
|
|
||||||
document.getElementById('minimizePanelIcon').src = leftIconPath;
|
|
||||||
} else {
|
} else {
|
||||||
Sfjs.addClass(menu, 'collapsed-menu');
|
Sfjs.addClass(menu, 'collapsed-menu');
|
||||||
Sfjs.addClass(menu.parentNode.parentNode, 'collapsed-menu-parents');
|
Sfjs.addClass(menu.parentNode.parentNode, 'collapsed-menu-parents');
|
||||||
|
|
||||||
document.getElementById('minimizePanelIcon').src = rightIconPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doSave) {
|
if (doSave) {
|
||||||
|
|
|
@ -400,9 +400,9 @@ td.main, td.menu {
|
||||||
.collapsed-menu {
|
.collapsed-menu {
|
||||||
width: 60px !important;
|
width: 60px !important;
|
||||||
}
|
}
|
||||||
.collapsed-menu span :not(.icon) {
|
.collapsed-menu span.label > :not(.icon) {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.collapsed-menu span.icon img {
|
.collapsed-menu #minimizePanelIcon {
|
||||||
display: inline !important;
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class A
|
class A
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
trait TFoo
|
trait TFoo
|
||||||
{
|
{
|
||||||
|
|
|
@ -114,7 +114,7 @@ class ExprBuilderTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->assertFinalizedValueIs('new_value', $test);
|
$this->assertFinalizedValueIs('new_value', $test);
|
||||||
|
|
||||||
$test = $this->getTestBuilder()
|
$test = $this->getTestBuilder()
|
||||||
->ifNotInArray(array('foo', 'bar', 'value_from_config' ))
|
->ifNotInArray(array('foo', 'bar', 'value_from_config'))
|
||||||
->then($this->returnClosure('new_value'))
|
->then($this->returnClosure('new_value'))
|
||||||
->end();
|
->end();
|
||||||
$this->assertFinalizedValueIs('new_value', $test);
|
$this->assertFinalizedValueIs('new_value', $test);
|
||||||
|
|
|
@ -18,6 +18,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||||
*
|
*
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
* @author Саша Стаменковић <umpirsky@gmail.com>
|
* @author Саша Стаменковић <umpirsky@gmail.com>
|
||||||
|
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||||
*/
|
*/
|
||||||
class Table
|
class Table
|
||||||
{
|
{
|
||||||
|
@ -139,7 +140,12 @@ class Table
|
||||||
|
|
||||||
public function setHeaders(array $headers)
|
public function setHeaders(array $headers)
|
||||||
{
|
{
|
||||||
$this->headers = array_values($headers);
|
$headers = array_values($headers);
|
||||||
|
if (!empty($headers) && !is_array($headers[0])) {
|
||||||
|
$headers = array($headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->headers = $headers;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -174,30 +180,6 @@ class Table
|
||||||
|
|
||||||
$this->rows[] = array_values($row);
|
$this->rows[] = array_values($row);
|
||||||
|
|
||||||
end($this->rows);
|
|
||||||
$rowKey = key($this->rows);
|
|
||||||
reset($this->rows);
|
|
||||||
|
|
||||||
foreach ($row as $key => $cellValue) {
|
|
||||||
if (!strstr($cellValue, "\n")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$lines = explode("\n", $cellValue);
|
|
||||||
$this->rows[$rowKey][$key] = $lines[0];
|
|
||||||
unset($lines[0]);
|
|
||||||
|
|
||||||
foreach ($lines as $lineKey => $line) {
|
|
||||||
$nextRowKey = $rowKey + $lineKey + 1;
|
|
||||||
|
|
||||||
if (isset($this->rows[$nextRowKey])) {
|
|
||||||
$this->rows[$nextRowKey][$key] = $line;
|
|
||||||
} else {
|
|
||||||
$this->rows[$nextRowKey] = array($key => $line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,10 +204,16 @@ class Table
|
||||||
*/
|
*/
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
|
$this->calculateNumberOfColumns();
|
||||||
|
$this->rows = $this->buildTableRows($this->rows);
|
||||||
|
$this->headers = $this->buildTableRows($this->headers);
|
||||||
|
|
||||||
$this->renderRowSeparator();
|
$this->renderRowSeparator();
|
||||||
$this->renderRow($this->headers, $this->style->getCellHeaderFormat());
|
|
||||||
if (!empty($this->headers)) {
|
if (!empty($this->headers)) {
|
||||||
$this->renderRowSeparator();
|
foreach ($this->headers as $header) {
|
||||||
|
$this->renderRow($header, $this->style->getCellHeaderFormat());
|
||||||
|
$this->renderRowSeparator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
foreach ($this->rows as $row) {
|
foreach ($this->rows as $row) {
|
||||||
if ($row instanceof TableSeparator) {
|
if ($row instanceof TableSeparator) {
|
||||||
|
@ -248,7 +236,7 @@ class Table
|
||||||
*/
|
*/
|
||||||
private function renderRowSeparator()
|
private function renderRowSeparator()
|
||||||
{
|
{
|
||||||
if (0 === $count = $this->getNumberOfColumns()) {
|
if (0 === $count = $this->numberOfColumns) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +275,7 @@ class Table
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->renderColumnSeparator();
|
$this->renderColumnSeparator();
|
||||||
for ($column = 0, $count = $this->getNumberOfColumns(); $column < $count; $column++) {
|
foreach ($this->getRowColumns($row) as $column) {
|
||||||
$this->renderCell($row, $column, $cellFormat);
|
$this->renderCell($row, $column, $cellFormat);
|
||||||
$this->renderColumnSeparator();
|
$this->renderColumnSeparator();
|
||||||
}
|
}
|
||||||
|
@ -305,38 +293,215 @@ class Table
|
||||||
{
|
{
|
||||||
$cell = isset($row[$column]) ? $row[$column] : '';
|
$cell = isset($row[$column]) ? $row[$column] : '';
|
||||||
$width = $this->getColumnWidth($column);
|
$width = $this->getColumnWidth($column);
|
||||||
|
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||||
|
// add the width of the following columns(numbers of colspan).
|
||||||
|
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) {
|
||||||
|
$width += $this->getColumnSeparatorWidth() + $this->getColumnWidth($nextColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// str_pad won't work properly with multi-byte strings, we need to fix the padding
|
// str_pad won't work properly with multi-byte strings, we need to fix the padding
|
||||||
if (function_exists('mb_strwidth') && false !== $encoding = mb_detect_encoding($cell)) {
|
if (function_exists('mb_strwidth') && false !== $encoding = mb_detect_encoding($cell)) {
|
||||||
$width += strlen($cell) - mb_strwidth($cell, $encoding);
|
$width += strlen($cell) - mb_strwidth($cell, $encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
$width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
|
if ($cell instanceof TableSeparator) {
|
||||||
|
$this->output->write(sprintf($this->style->getBorderFormat(), str_repeat($this->style->getHorizontalBorderChar(), $width)));
|
||||||
$content = sprintf($this->style->getCellRowContentFormat(), $cell);
|
} else {
|
||||||
|
$width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
|
||||||
$this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType())));
|
$content = sprintf($this->style->getCellRowContentFormat(), $cell);
|
||||||
|
$this->output->write(sprintf($cellFormat, str_pad($content, $width, $this->style->getPaddingChar(), $this->style->getPadType())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets number of columns for this table.
|
* Calculate number of columns for this table.
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
*/
|
||||||
private function getNumberOfColumns()
|
private function calculateNumberOfColumns()
|
||||||
{
|
{
|
||||||
if (null !== $this->numberOfColumns) {
|
if (null !== $this->numberOfColumns) {
|
||||||
return $this->numberOfColumns;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$columns = array(count($this->headers));
|
$columns = array(0);
|
||||||
foreach ($this->rows as $row) {
|
foreach (array_merge($this->headers, $this->rows) as $row) {
|
||||||
$columns[] = count($row);
|
if ($row instanceof TableSeparator) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$columns[] = $this->getNumberOfColumns($row);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->numberOfColumns = max($columns);
|
return $this->numberOfColumns = max($columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildTableRows($rows)
|
||||||
|
{
|
||||||
|
$unmergedRows = array();
|
||||||
|
for ($rowKey = 0; $rowKey < count($rows); $rowKey++) {
|
||||||
|
$rows = $this->fillNextRows($rows, $rowKey);
|
||||||
|
|
||||||
|
// Remove any new line breaks and replace it with a new line
|
||||||
|
foreach ($rows[$rowKey] as $column => $cell) {
|
||||||
|
$rows[$rowKey] = $this->fillCells($rows[$rowKey], $column);
|
||||||
|
if (!strstr($cell, "\n")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$lines = explode("\n", $cell);
|
||||||
|
foreach ($lines as $lineKey => $line) {
|
||||||
|
if ($cell instanceof TableCell) {
|
||||||
|
$line = new TableCell($line, array('colspan' => $cell->getColspan()));
|
||||||
|
}
|
||||||
|
if (0 === $lineKey) {
|
||||||
|
$rows[$rowKey][$column] = $line;
|
||||||
|
} else {
|
||||||
|
$unmergedRows[$rowKey][$lineKey][$column] = $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$tableRows = array();
|
||||||
|
foreach ($rows as $rowKey => $row) {
|
||||||
|
$tableRows[] = $row;
|
||||||
|
if (isset($unmergedRows[$rowKey])) {
|
||||||
|
$tableRows = array_merge($tableRows, $unmergedRows[$rowKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tableRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill rows that contains rowspan > 1.
|
||||||
|
*
|
||||||
|
* @param array $rows
|
||||||
|
* @param array $line
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function fillNextRows($rows, $line)
|
||||||
|
{
|
||||||
|
$unmergedRows = array();
|
||||||
|
foreach ($rows[$line] as $column => $cell) {
|
||||||
|
if ($cell instanceof TableCell && $cell->getRowspan() > 1) {
|
||||||
|
$nbLines = $cell->getRowspan()-1;
|
||||||
|
$lines = array($cell);
|
||||||
|
if (strstr($cell, "\n")) {
|
||||||
|
$lines = explode("\n", $cell);
|
||||||
|
$nbLines = count($lines) > $nbLines ? substr_count($cell, "\n") : $nbLines;
|
||||||
|
|
||||||
|
$rows[$line][$column] = new TableCell($lines[0], array('colspan' => $cell->getColspan()));
|
||||||
|
unset($lines[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a two dimensional array (rowspan x colspan)
|
||||||
|
$unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, ''), $unmergedRows);
|
||||||
|
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
|
||||||
|
$value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : '';
|
||||||
|
$unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) {
|
||||||
|
// we need to know if $unmergedRow will be merged or inserted into $rows
|
||||||
|
if (isset($rows[$unmergedRowKey]) && is_array($rows[$unmergedRowKey]) && ($this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns)) {
|
||||||
|
foreach ($unmergedRow as $cellKey => $cell) {
|
||||||
|
// insert cell into row at cellKey position
|
||||||
|
array_splice($rows[$unmergedRowKey], $cellKey, 0, array($cell));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$row = $this->copyRow($rows, $unmergedRowKey-1);
|
||||||
|
foreach ($unmergedRow as $column => $cell) {
|
||||||
|
if (!empty($cell)) {
|
||||||
|
$row[$column] = $unmergedRow[$column];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array_splice($rows, $unmergedRowKey, 0, array($row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill cells for a row that contains colspan > 1.
|
||||||
|
*
|
||||||
|
* @param array $row
|
||||||
|
* @param array $column
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function fillCells($row, $column)
|
||||||
|
{
|
||||||
|
$cell = $row[$column];
|
||||||
|
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||||
|
foreach (range($column + 1, $column + $cell->getColspan() - 1) as $position) {
|
||||||
|
// insert empty value into rows at column position
|
||||||
|
array_splice($row, $position, 0, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $rows
|
||||||
|
* @param int $line
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function copyRow($rows, $line)
|
||||||
|
{
|
||||||
|
$row = $rows[$line];
|
||||||
|
foreach ($row as $cellKey => $cellValue) {
|
||||||
|
$row[$cellKey] = '';
|
||||||
|
if ($cellValue instanceof TableCell) {
|
||||||
|
$row[$cellKey] = new TableCell('', array('colspan' => $cellValue->getColspan()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets number of columns by row.
|
||||||
|
*
|
||||||
|
* @param array $row
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function getNumberOfColumns(array $row)
|
||||||
|
{
|
||||||
|
$columns = count($row);
|
||||||
|
foreach ($row as $column) {
|
||||||
|
$columns += $column instanceof TableCell ? ($column->getColspan()-1) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets list of columns for the given row.
|
||||||
|
*
|
||||||
|
* @param array $row
|
||||||
|
*
|
||||||
|
* @return array()
|
||||||
|
*/
|
||||||
|
private function getRowColumns($row)
|
||||||
|
{
|
||||||
|
$columns = range(0, $this->numberOfColumns-1);
|
||||||
|
foreach ($row as $cellKey => $cell) {
|
||||||
|
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||||
|
// exclude grouped columns.
|
||||||
|
$columns = array_diff($columns, range($cellKey+1, $cellKey + $cell->getColspan()-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $columns;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets column width.
|
* Gets column width.
|
||||||
*
|
*
|
||||||
|
@ -350,8 +515,7 @@ class Table
|
||||||
return $this->columnWidths[$column];
|
return $this->columnWidths[$column];
|
||||||
}
|
}
|
||||||
|
|
||||||
$lengths = array($this->getCellWidth($this->headers, $column));
|
foreach (array_merge($this->headers, $this->rows) as $row) {
|
||||||
foreach ($this->rows as $row) {
|
|
||||||
if ($row instanceof TableSeparator) {
|
if ($row instanceof TableSeparator) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -362,6 +526,18 @@ class Table
|
||||||
return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
|
return $this->columnWidths[$column] = max($lengths) + strlen($this->style->getCellRowContentFormat()) - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets column width.
|
||||||
|
*
|
||||||
|
* @param int $column
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function getColumnSeparatorWidth()
|
||||||
|
{
|
||||||
|
return strlen(sprintf($this->style->getBorderFormat(), $this->style->getVerticalBorderChar()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets cell width.
|
* Gets cell width.
|
||||||
*
|
*
|
||||||
|
@ -372,7 +548,17 @@ class Table
|
||||||
*/
|
*/
|
||||||
private function getCellWidth(array $row, $column)
|
private function getCellWidth(array $row, $column)
|
||||||
{
|
{
|
||||||
return isset($row[$column]) ? Helper::strlenWithoutDecoration($this->output->getFormatter(), $row[$column]) : 0;
|
if (isset($row[$column])) {
|
||||||
|
$cell = $row[$column];
|
||||||
|
if ($cell instanceof TableCell && $cell->getColspan() > 1) {
|
||||||
|
// we assume that cell value will be across more than one column.
|
||||||
|
$cell = substr($cell, 0, strlen($cell)/$cell->getColspan());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?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\Console\Helper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||||
|
*/
|
||||||
|
class TableCell
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $options = array(
|
||||||
|
'rowspan' => 1,
|
||||||
|
'colspan' => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function __construct($value = '', array $options = array())
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
|
||||||
|
// check option names
|
||||||
|
if ($diff = array_diff(array_keys($options), array_keys($this->options))) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->options = array_merge($this->options, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cell value.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets number of colspan.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getColspan()
|
||||||
|
{
|
||||||
|
return (int) $this->options['colspan'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets number of rowspan.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRowspan()
|
||||||
|
{
|
||||||
|
return (int) $this->options['rowspan'];
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,14 @@ namespace Symfony\Component\Console\Helper;
|
||||||
*
|
*
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
*/
|
*/
|
||||||
class TableSeparator
|
class TableSeparator extends TableCell
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @param string $value
|
||||||
|
* @param array $options
|
||||||
|
*/
|
||||||
|
public function __construct(array $options = array())
|
||||||
|
{
|
||||||
|
parent::__construct('', $options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Tests\Helper;
|
||||||
use Symfony\Component\Console\Helper\Table;
|
use Symfony\Component\Console\Helper\Table;
|
||||||
use Symfony\Component\Console\Helper\TableStyle;
|
use Symfony\Component\Console\Helper\TableStyle;
|
||||||
use Symfony\Component\Console\Helper\TableSeparator;
|
use Symfony\Component\Console\Helper\TableSeparator;
|
||||||
|
use Symfony\Component\Console\Helper\TableCell;
|
||||||
use Symfony\Component\Console\Output\StreamOutput;
|
use Symfony\Component\Console\Output\StreamOutput;
|
||||||
|
|
||||||
class TableTest extends \PHPUnit_Framework_TestCase
|
class TableTest extends \PHPUnit_Framework_TestCase
|
||||||
|
@ -250,6 +251,214 @@ TABLE
|
||||||
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
|
| 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens |
|
||||||
+----------------------------------+----------------------+-----------------+
|
+----------------------------------+----------------------+-----------------+
|
||||||
|
|
||||||
|
TABLE
|
||||||
|
),
|
||||||
|
'Cell with colspan' => array(
|
||||||
|
array('ISBN', 'Title', 'Author'),
|
||||||
|
array(
|
||||||
|
array('99921-58-10-7', 'Divine Comedy', 'Dante Alighieri'),
|
||||||
|
new TableSeparator(),
|
||||||
|
array(new TableCell('Divine Comedy(Dante Alighieri)', array('colspan' => 3))),
|
||||||
|
new TableSeparator(),
|
||||||
|
array(
|
||||||
|
new TableCell('Arduino: A Quick-Start Guide', array('colspan' => 2)),
|
||||||
|
'Mark Schmidt',
|
||||||
|
),
|
||||||
|
new TableSeparator(),
|
||||||
|
array(
|
||||||
|
'9971-5-0210-0',
|
||||||
|
new TableCell("A Tale of \nTwo Cities", array('colspan' => 2)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'default',
|
||||||
|
<<<TABLE
|
||||||
|
+----------------+---------------+-----------------+
|
||||||
|
| ISBN | Title | Author |
|
||||||
|
+----------------+---------------+-----------------+
|
||||||
|
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
|
||||||
|
+----------------+---------------+-----------------+
|
||||||
|
| Divine Comedy(Dante Alighieri) |
|
||||||
|
+----------------+---------------+-----------------+
|
||||||
|
| Arduino: A Quick-Start Guide | Mark Schmidt |
|
||||||
|
+----------------+---------------+-----------------+
|
||||||
|
| 9971-5-0210-0 | A Tale of |
|
||||||
|
| | Two Cities |
|
||||||
|
+----------------+---------------+-----------------+
|
||||||
|
|
||||||
|
TABLE
|
||||||
|
),
|
||||||
|
'Cell with rowspan' => array(
|
||||||
|
array('ISBN', 'Title', 'Author'),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
new TableCell('9971-5-0210-0', array('rowspan' => 3)),
|
||||||
|
'Divine Comedy',
|
||||||
|
'Dante Alighieri',
|
||||||
|
),
|
||||||
|
array('A Tale of Two Cities', 'Charles Dickens'),
|
||||||
|
array("The Lord of \nthe Rings", "J. R. \nR. Tolkien"),
|
||||||
|
new TableSeparator(),
|
||||||
|
array('80-902734-1-6', new TableCell("And Then \nThere \nWere None", array('rowspan' => 3)), 'Agatha Christie'),
|
||||||
|
array('80-902734-1-7', 'Test'),
|
||||||
|
),
|
||||||
|
'default',
|
||||||
|
<<<TABLE
|
||||||
|
+---------------+----------------------+-----------------+
|
||||||
|
| ISBN | Title | Author |
|
||||||
|
+---------------+----------------------+-----------------+
|
||||||
|
| 9971-5-0210-0 | Divine Comedy | Dante Alighieri |
|
||||||
|
| | A Tale of Two Cities | Charles Dickens |
|
||||||
|
| | The Lord of | J. R. |
|
||||||
|
| | the Rings | R. Tolkien |
|
||||||
|
+---------------+----------------------+-----------------+
|
||||||
|
| 80-902734-1-6 | And Then | Agatha Christie |
|
||||||
|
| 80-902734-1-7 | There | Test |
|
||||||
|
| | Were None | |
|
||||||
|
+---------------+----------------------+-----------------+
|
||||||
|
|
||||||
|
TABLE
|
||||||
|
),
|
||||||
|
'Cell with rowspan and colspan' => array(
|
||||||
|
array('ISBN', 'Title', 'Author'),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
new TableCell('9971-5-0210-0', array('rowspan' => 2, 'colspan' => 2)),
|
||||||
|
'Dante Alighieri',
|
||||||
|
),
|
||||||
|
array('Charles Dickens'),
|
||||||
|
new TableSeparator(),
|
||||||
|
array(
|
||||||
|
'Dante Alighieri',
|
||||||
|
new TableCell('9971-5-0210-0', array('rowspan' => 3, 'colspan' => 2)),
|
||||||
|
),
|
||||||
|
array('J. R. R. Tolkien'),
|
||||||
|
array('J. R. R'),
|
||||||
|
),
|
||||||
|
'default',
|
||||||
|
<<<TABLE
|
||||||
|
+------------------+--------+-----------------+
|
||||||
|
| ISBN | Title | Author |
|
||||||
|
+------------------+--------+-----------------+
|
||||||
|
| 9971-5-0210-0 | Dante Alighieri |
|
||||||
|
| | Charles Dickens |
|
||||||
|
+------------------+--------+-----------------+
|
||||||
|
| Dante Alighieri | 9971-5-0210-0 |
|
||||||
|
| J. R. R. Tolkien | |
|
||||||
|
| J. R. R | |
|
||||||
|
+------------------+--------+-----------------+
|
||||||
|
|
||||||
|
TABLE
|
||||||
|
),
|
||||||
|
'Cell with rowspan and colspan contains new line break' => array(
|
||||||
|
array('ISBN', 'Title', 'Author'),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
|
||||||
|
'Dante Alighieri',
|
||||||
|
),
|
||||||
|
array('Charles Dickens'),
|
||||||
|
new TableSeparator(),
|
||||||
|
array(
|
||||||
|
'Dante Alighieri',
|
||||||
|
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
|
||||||
|
),
|
||||||
|
array('Charles Dickens'),
|
||||||
|
new TableSeparator(),
|
||||||
|
array(
|
||||||
|
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
|
||||||
|
new TableCell("Dante \nAlighieri", array('rowspan' => 2, 'colspan' => 1)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'default',
|
||||||
|
<<<TABLE
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
| ISBN | Title | Author |
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
| 9971 | Dante Alighieri |
|
||||||
|
| -5- | Charles Dickens |
|
||||||
|
| 021 | |
|
||||||
|
| 0-0 | |
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
| Dante Alighieri | 9971 |
|
||||||
|
| Charles Dickens | -5- |
|
||||||
|
| | 021 |
|
||||||
|
| | 0-0 |
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
| 9971 | Dante |
|
||||||
|
| -5- | Alighieri |
|
||||||
|
| 021 | |
|
||||||
|
| 0-0 | |
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
|
||||||
|
TABLE
|
||||||
|
),
|
||||||
|
'Cell with rowspan and colspan without using TableSeparator' => array(
|
||||||
|
array('ISBN', 'Title', 'Author'),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
|
||||||
|
'Dante Alighieri',
|
||||||
|
),
|
||||||
|
array('Charles Dickens'),
|
||||||
|
array(
|
||||||
|
'Dante Alighieri',
|
||||||
|
new TableCell("9971\n-5-\n021\n0-0", array('rowspan' => 2, 'colspan' => 2)),
|
||||||
|
),
|
||||||
|
array('Charles Dickens'),
|
||||||
|
),
|
||||||
|
'default',
|
||||||
|
<<<TABLE
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
| ISBN | Title | Author |
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
| 9971 | Dante Alighieri |
|
||||||
|
| -5- | Charles Dickens |
|
||||||
|
| 021 | |
|
||||||
|
| 0-0 | |
|
||||||
|
| Dante Alighieri | 9971 |
|
||||||
|
| Charles Dickens | -5- |
|
||||||
|
| | 021 |
|
||||||
|
| | 0-0 |
|
||||||
|
+-----------------+-------+-----------------+
|
||||||
|
|
||||||
|
TABLE
|
||||||
|
),
|
||||||
|
'Cell with rowspan and colspan with separator inside a rowspan' => array(
|
||||||
|
array('ISBN', 'Author'),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
new TableCell("9971-5-0210-0", array('rowspan' => 3, 'colspan' => 1)),
|
||||||
|
'Dante Alighieri',
|
||||||
|
),
|
||||||
|
array(new TableSeparator()),
|
||||||
|
array('Charles Dickens'),
|
||||||
|
),
|
||||||
|
'default',
|
||||||
|
<<<TABLE
|
||||||
|
+---------------+-----------------+
|
||||||
|
| ISBN | Author |
|
||||||
|
+---------------+-----------------+
|
||||||
|
| 9971-5-0210-0 | Dante Alighieri |
|
||||||
|
| |-----------------|
|
||||||
|
| | Charles Dickens |
|
||||||
|
+---------------+-----------------+
|
||||||
|
|
||||||
|
TABLE
|
||||||
|
),
|
||||||
|
'Multiple header lines' => array(
|
||||||
|
array(
|
||||||
|
array(new TableCell('Main title', array('colspan' => 3))),
|
||||||
|
array('ISBN', 'Title', 'Author'),
|
||||||
|
),
|
||||||
|
array(),
|
||||||
|
'default',
|
||||||
|
<<<TABLE
|
||||||
|
+------+-------+--------+
|
||||||
|
| Main title |
|
||||||
|
+------+-------+--------+
|
||||||
|
| ISBN | Title | Author |
|
||||||
|
+------+-------+--------+
|
||||||
|
|
||||||
TABLE
|
TABLE
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -826,7 +826,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
$bagClass
|
$bagClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* $class
|
* $class.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -10,7 +10,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container
|
* Container.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectServiceContainer
|
* ProjectServiceContainer.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Dependency Injection Component.
|
* by the Symfony Dependency Injection Component.
|
||||||
|
|
|
@ -36,7 +36,8 @@ class FilePathsIteratorTest extends RealIteratorTestCase
|
||||||
return array(
|
return array(
|
||||||
array(
|
array(
|
||||||
$tmpDir,
|
$tmpDir,
|
||||||
array( // paths
|
array(
|
||||||
|
// paths
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'.git' => $tmpDir.DIRECTORY_SEPARATOR.'.git',
|
$tmpDir.DIRECTORY_SEPARATOR.'.git' => $tmpDir.DIRECTORY_SEPARATOR.'.git',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => $tmpDir.DIRECTORY_SEPARATOR.'test.py',
|
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => $tmpDir.DIRECTORY_SEPARATOR.'test.py',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'foo' => $tmpDir.DIRECTORY_SEPARATOR.'foo',
|
$tmpDir.DIRECTORY_SEPARATOR.'foo' => $tmpDir.DIRECTORY_SEPARATOR.'foo',
|
||||||
|
@ -44,7 +45,8 @@ class FilePathsIteratorTest extends RealIteratorTestCase
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'test.php' => $tmpDir.DIRECTORY_SEPARATOR.'test.php',
|
$tmpDir.DIRECTORY_SEPARATOR.'test.php' => $tmpDir.DIRECTORY_SEPARATOR.'test.php',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'toto' => $tmpDir.DIRECTORY_SEPARATOR.'toto',
|
$tmpDir.DIRECTORY_SEPARATOR.'toto' => $tmpDir.DIRECTORY_SEPARATOR.'toto',
|
||||||
),
|
),
|
||||||
array( // subPaths
|
array(
|
||||||
|
// subPaths
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'.git' => '',
|
$tmpDir.DIRECTORY_SEPARATOR.'.git' => '',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => '',
|
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => '',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'foo' => '',
|
$tmpDir.DIRECTORY_SEPARATOR.'foo' => '',
|
||||||
|
@ -52,7 +54,8 @@ class FilePathsIteratorTest extends RealIteratorTestCase
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'test.php' => '',
|
$tmpDir.DIRECTORY_SEPARATOR.'test.php' => '',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'toto' => '',
|
$tmpDir.DIRECTORY_SEPARATOR.'toto' => '',
|
||||||
),
|
),
|
||||||
array( // subPathnames
|
array(
|
||||||
|
// subPathnames
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'.git' => '.git',
|
$tmpDir.DIRECTORY_SEPARATOR.'.git' => '.git',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => 'test.py',
|
$tmpDir.DIRECTORY_SEPARATOR.'test.py' => 'test.py',
|
||||||
$tmpDir.DIRECTORY_SEPARATOR.'foo' => 'foo',
|
$tmpDir.DIRECTORY_SEPARATOR.'foo' => 'foo',
|
||||||
|
|
|
@ -57,7 +57,7 @@ abstract class BaseType extends AbstractType
|
||||||
$uniqueBlockPrefix = '_'.$blockName;
|
$uniqueBlockPrefix = '_'.$blockName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$translationDomain) {
|
if (null === $translationDomain) {
|
||||||
$translationDomain = $view->parent->vars['translation_domain'];
|
$translationDomain = $view->parent->vars['translation_domain'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,10 +81,6 @@ abstract class BaseType extends AbstractType
|
||||||
}
|
}
|
||||||
$blockPrefixes[] = $uniqueBlockPrefix;
|
$blockPrefixes[] = $uniqueBlockPrefix;
|
||||||
|
|
||||||
if (!$translationDomain) {
|
|
||||||
$translationDomain = 'messages';
|
|
||||||
}
|
|
||||||
|
|
||||||
$view->vars = array_replace($view->vars, array(
|
$view->vars = array_replace($view->vars, array(
|
||||||
'form' => $view,
|
'form' => $view,
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,13 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the Symfony package.
|
* This file is part of the Symfony package.
|
||||||
*
|
*
|
||||||
* (c) Fabien Potencier <fabien@symfony.com>
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
*
|
*
|
||||||
* For the full copyright and license information, please view the LICENSE
|
* For the full copyright and license information, please view the LICENSE
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Symfony\Component\Form\Tests;
|
namespace Symfony\Component\Form\Tests;
|
||||||
|
|
||||||
|
|
|
@ -92,9 +92,15 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
|
||||||
'attr' => array('class' => 'my&class'),
|
'attr' => array('class' => 'my&class'),
|
||||||
), $vars));
|
), $vars));
|
||||||
|
|
||||||
$xpath = trim($xpath).'
|
if (!isset($vars['id'])) {
|
||||||
[@id="my&id"]
|
$xpath = trim($xpath).'
|
||||||
|
[@id="my&id"]';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($vars['attr']['class'])) {
|
||||||
|
$xpath .= '
|
||||||
[@class="my&class"]';
|
[@class="my&class"]';
|
||||||
|
}
|
||||||
|
|
||||||
$this->assertMatchesXpath($html, $xpath);
|
$this->assertMatchesXpath($html, $xpath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
<?php
|
<?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;
|
namespace Symfony\Component\Form\Tests;
|
||||||
|
|
||||||
use Symfony\Component\Form\CallbackTransformer;
|
use Symfony\Component\Form\CallbackTransformer;
|
||||||
|
@ -30,8 +39,8 @@ class CallbackTransformerTest extends \PHPUnit_Framework_TestCase
|
||||||
public function invalidCallbacksProvider()
|
public function invalidCallbacksProvider()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array( null, function () {} ),
|
array(null, function () {}),
|
||||||
array( function () {}, null ),
|
array(function () {}, null),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ abstract class BaseTypeTest extends \Symfony\Component\Form\Test\TypeTestCase
|
||||||
->getForm()
|
->getForm()
|
||||||
->createView();
|
->createView();
|
||||||
|
|
||||||
$this->assertEquals('messages', $view['child']->vars['translation_domain']);
|
$this->assertNull($view['child']->vars['translation_domain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPassLabelToView()
|
public function testPassLabelToView()
|
||||||
|
|
|
@ -212,13 +212,13 @@ class ParameterBagTest extends \PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
$this->assertFalse($bag->filter('dec', '', false, FILTER_VALIDATE_INT, array(
|
$this->assertFalse($bag->filter('dec', '', false, FILTER_VALIDATE_INT, array(
|
||||||
'flags' => FILTER_FLAG_ALLOW_HEX,
|
'flags' => FILTER_FLAG_ALLOW_HEX,
|
||||||
'options' => array('min_range' => 1, 'max_range' => 0xff))
|
'options' => array('min_range' => 1, 'max_range' => 0xff),
|
||||||
), '->filter() gets a value of parameter as integer between boundaries');
|
)), '->filter() gets a value of parameter as integer between boundaries');
|
||||||
|
|
||||||
$this->assertFalse($bag->filter('hex', '', false, FILTER_VALIDATE_INT, array(
|
$this->assertFalse($bag->filter('hex', '', false, FILTER_VALIDATE_INT, array(
|
||||||
'flags' => FILTER_FLAG_ALLOW_HEX,
|
'flags' => FILTER_FLAG_ALLOW_HEX,
|
||||||
'options' => array('min_range' => 1, 'max_range' => 0xff))
|
'options' => array('min_range' => 1, 'max_range' => 0xff),
|
||||||
), '->filter() gets a value of parameter as integer between boundaries');
|
)), '->filter() gets a value of parameter as integer between boundaries');
|
||||||
|
|
||||||
$this->assertEquals(array('bang'), $bag->filter('array', '', false), '->filter() gets a value of parameter as an array');
|
$this->assertEquals(array('bang'), $bag->filter('array', '', false), '->filter() gets a value of parameter as an array');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the Symfony package.
|
* This file is part of the Symfony package.
|
||||||
*
|
*
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
namespace Symfony\Component\Intl\Tests\Collator;
|
namespace Symfony\Component\Intl\Tests\Collator;
|
||||||
|
|
||||||
use Symfony\Component\Intl\Collator\Collator;
|
use Symfony\Component\Intl\Collator\Collator;
|
||||||
use Symfony\Component\Intl\Locale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test case for Collator implementations.
|
* Test case for Collator implementations.
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
namespace Symfony\Component\Intl\Tests\Collator\Verification;
|
namespace Symfony\Component\Intl\Tests\Collator\Verification;
|
||||||
|
|
||||||
use Symfony\Component\Intl\Locale;
|
|
||||||
use Symfony\Component\Intl\Tests\Collator\AbstractCollatorTest;
|
use Symfony\Component\Intl\Tests\Collator\AbstractCollatorTest;
|
||||||
use Symfony\Component\Intl\Util\IntlTestHelper;
|
use Symfony\Component\Intl\Util\IntlTestHelper;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
namespace Symfony\Component\Intl\Tests\NumberFormatter;
|
namespace Symfony\Component\Intl\Tests\NumberFormatter;
|
||||||
|
|
||||||
use Symfony\Component\Intl\Globals\IntlGlobals;
|
use Symfony\Component\Intl\Globals\IntlGlobals;
|
||||||
use Symfony\Component\Intl\Locale;
|
|
||||||
use Symfony\Component\Intl\NumberFormatter\NumberFormatter;
|
use Symfony\Component\Intl\NumberFormatter\NumberFormatter;
|
||||||
use Symfony\Component\Intl\Util\IntlTestHelper;
|
use Symfony\Component\Intl\Util\IntlTestHelper;
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
use Symfony\Component\Routing\RequestContext;
|
use Symfony\Component\Routing\RequestContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {$options['class']}
|
* {$options['class']}.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Routing Component.
|
* by the Symfony Routing Component.
|
||||||
|
|
|
@ -5,7 +5,7 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
use Symfony\Component\Routing\RequestContext;
|
use Symfony\Component\Routing\RequestContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectUrlMatcher
|
* ProjectUrlMatcher.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Routing Component.
|
* by the Symfony Routing Component.
|
||||||
|
|
|
@ -5,7 +5,7 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
use Symfony\Component\Routing\RequestContext;
|
use Symfony\Component\Routing\RequestContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectUrlMatcher
|
* ProjectUrlMatcher.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Routing Component.
|
* by the Symfony Routing Component.
|
||||||
|
|
|
@ -5,7 +5,7 @@ use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||||
use Symfony\Component\Routing\RequestContext;
|
use Symfony\Component\Routing\RequestContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectUrlMatcher
|
* ProjectUrlMatcher.
|
||||||
*
|
*
|
||||||
* This class has been auto-generated
|
* This class has been auto-generated
|
||||||
* by the Symfony Routing Component.
|
* by the Symfony Routing Component.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Symfony\Component\Routing\RouteCollection;
|
use Symfony\Component\Routing\RouteCollection;
|
||||||
use Symfony\Component\Routing\Route;
|
use Symfony\Component\Routing\Route;
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,12 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface
|
||||||
throw new \InvalidArgumentException('You must at least add one authentication provider.');
|
throw new \InvalidArgumentException('You must at least add one authentication provider.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($providers as $provider) {
|
||||||
|
if (!$provider instanceof AuthenticationProviderInterface) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Provider "%s" must implement the AuthenticationProviderInterface.', get_class($provider)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->providers = $providers;
|
$this->providers = $providers;
|
||||||
$this->eraseCredentials = (bool) $eraseCredentials;
|
$this->eraseCredentials = (bool) $eraseCredentials;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,16 @@ class AuthenticationProviderManagerTest extends \PHPUnit_Framework_TestCase
|
||||||
new AuthenticationProviderManager(array());
|
new AuthenticationProviderManager(array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testAuthenticateWithProvidersWithIncorrectInterface()
|
||||||
|
{
|
||||||
|
new AuthenticationProviderManager(array(
|
||||||
|
new \stdClass(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
public function testAuthenticateWhenNoProviderSupportsToken()
|
public function testAuthenticateWhenNoProviderSupportsToken()
|
||||||
{
|
{
|
||||||
$manager = new AuthenticationProviderManager(array(
|
$manager = new AuthenticationProviderManager(array(
|
||||||
|
|
|
@ -38,29 +38,56 @@ class StringUtils
|
||||||
*/
|
*/
|
||||||
public static function equals($knownString, $userInput)
|
public static function equals($knownString, $userInput)
|
||||||
{
|
{
|
||||||
$knownString = (string) $knownString;
|
// Avoid making unnecessary duplications of secret data
|
||||||
$userInput = (string) $userInput;
|
if (!is_string($knownString)) {
|
||||||
|
$knownString = (string) $knownString;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_string($userInput)) {
|
||||||
|
$userInput = (string) $userInput;
|
||||||
|
}
|
||||||
|
|
||||||
if (function_exists('hash_equals')) {
|
if (function_exists('hash_equals')) {
|
||||||
return hash_equals($knownString, $userInput);
|
return hash_equals($knownString, $userInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
$knownLen = strlen($knownString);
|
$knownLen = self::safeStrlen($knownString);
|
||||||
$userLen = strlen($userInput);
|
$userLen = self::safeStrlen($userInput);
|
||||||
|
|
||||||
// Extend the known string to avoid uninitialized string offsets
|
if ($userLen !== $knownLen) {
|
||||||
$knownString .= $userInput;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the result to the difference between the lengths
|
$result = 0;
|
||||||
$result = $knownLen - $userLen;
|
|
||||||
|
|
||||||
// Note that we ALWAYS iterate over the user-supplied length
|
for ($i = 0; $i < $knownLen; $i++) {
|
||||||
// This is to mitigate leaking length information
|
|
||||||
for ($i = 0; $i < $userLen; $i++) {
|
|
||||||
$result |= (ord($knownString[$i]) ^ ord($userInput[$i]));
|
$result |= (ord($knownString[$i]) ^ ord($userInput[$i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// They are only identical strings if $result is exactly 0...
|
// They are only identical strings if $result is exactly 0...
|
||||||
return 0 === $result;
|
return 0 === $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes in a string.
|
||||||
|
*
|
||||||
|
* @param string $string The string whose length we wish to obtain
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function safeStrlen($string)
|
||||||
|
{
|
||||||
|
// Premature optimization
|
||||||
|
// Since this cannot be changed at runtime, we can cache it
|
||||||
|
static $funcExists = null;
|
||||||
|
if (null === $funcExists) {
|
||||||
|
$funcExists = function_exists('mb_strlen');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($funcExists) {
|
||||||
|
return mb_strlen($string, '8bit');
|
||||||
|
}
|
||||||
|
|
||||||
|
return strlen($string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices
|
||||||
throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_class($user)));
|
throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_class($user)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true !== StringUtils::equals($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) {
|
if (true !== StringUtils::equals($this->generateCookieHash($class, $username, $expires, $user->getPassword()), $hash)) {
|
||||||
throw new AuthenticationException('The cookie\'s hash is invalid.');
|
throw new AuthenticationException('The cookie\'s hash is invalid.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?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\Translation\Extractor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class used by classes that extract translation messages from files.
|
||||||
|
*
|
||||||
|
* @author Marcos D. Sánchez <marcosdsanchez@gmail.com>
|
||||||
|
*/
|
||||||
|
abstract class AbstractFileExtractor
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param string|array $resource files, a file or a directory
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function extractFiles($resource)
|
||||||
|
{
|
||||||
|
if (is_array($resource) || $resource instanceof \Traversable) {
|
||||||
|
$files = array();
|
||||||
|
foreach ($resource as $file) {
|
||||||
|
if ($this->canBeExtracted($file)) {
|
||||||
|
$files[] = $this->toSplFileInfo($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (is_file($resource)) {
|
||||||
|
$files = $this->canBeExtracted($resource) ? array($this->toSplFileInfo($resource)) : array();
|
||||||
|
} else {
|
||||||
|
$files = $this->extractFromDirectory($resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @return \SplFileInfo
|
||||||
|
*/
|
||||||
|
private function toSplFileInfo($file)
|
||||||
|
{
|
||||||
|
return ($file instanceof \SplFileInfo) ? $file : new \SplFileInfo($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isFile($file)
|
||||||
|
{
|
||||||
|
if (!is_file($file)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The "%s" file does not exist.', $file));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
abstract protected function canBeExtracted($file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|array $resource files, a file or a directory
|
||||||
|
*
|
||||||
|
* @return array files to be extracted
|
||||||
|
*/
|
||||||
|
abstract protected function extractFromDirectory($resource);
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ namespace Symfony\Component\Translation\Extractor;
|
||||||
use Symfony\Component\Translation\MessageCatalogue;
|
use Symfony\Component\Translation\MessageCatalogue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts translation messages from a template directory to the catalogue.
|
* Extracts translation messages from a directory or files to the catalogue.
|
||||||
* New found messages are injected to the catalogue using the prefix.
|
* New found messages are injected to the catalogue using the prefix.
|
||||||
*
|
*
|
||||||
* @author Michel Salib <michelsalib@hotmail.com>
|
* @author Michel Salib <michelsalib@hotmail.com>
|
||||||
|
@ -22,12 +22,12 @@ use Symfony\Component\Translation\MessageCatalogue;
|
||||||
interface ExtractorInterface
|
interface ExtractorInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Extracts translation messages from a template directory to the catalogue.
|
* Extracts translation messages from files, a file or a directory to the catalogue.
|
||||||
*
|
*
|
||||||
* @param string $directory The path to look into
|
* @param string|array $resource files, a file or a directory
|
||||||
* @param MessageCatalogue $catalogue The catalogue
|
* @param MessageCatalogue $catalogue The catalogue
|
||||||
*/
|
*/
|
||||||
public function extract($directory, MessageCatalogue $catalogue);
|
public function extract($resource, MessageCatalogue $catalogue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the prefix that should be used for new found messages.
|
* Sets the prefix that should be used for new found messages.
|
||||||
|
|
|
@ -346,7 +346,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $locale
|
* @param string $locale
|
||||||
* @param bool $forceRefresh
|
* @param bool $forceRefresh
|
||||||
*/
|
*/
|
||||||
private function initializeCacheCatalogue($locale, $forceRefresh = false)
|
private function initializeCacheCatalogue($locale, $forceRefresh = false)
|
||||||
{
|
{
|
||||||
|
@ -358,29 +358,7 @@ class Translator implements TranslatorInterface, TranslatorBagInterface
|
||||||
$cache = new ConfigCache($this->cacheDir.'/catalogue.'.$locale.'.php', $this->debug);
|
$cache = new ConfigCache($this->cacheDir.'/catalogue.'.$locale.'.php', $this->debug);
|
||||||
if ($forceRefresh || !$cache->isFresh()) {
|
if ($forceRefresh || !$cache->isFresh()) {
|
||||||
$this->initializeCatalogue($locale);
|
$this->initializeCatalogue($locale);
|
||||||
|
$fallbackContent = $this->getFallbackContent($this->catalogues[$locale]);
|
||||||
$fallbackContent = '';
|
|
||||||
$current = '';
|
|
||||||
$replacementPattern = '/[^a-z0-9_]/i';
|
|
||||||
foreach ($this->computeFallbackLocales($locale) as $fallback) {
|
|
||||||
$fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback));
|
|
||||||
$currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current));
|
|
||||||
|
|
||||||
$fallbackContent .= sprintf(<<<EOF
|
|
||||||
\$catalogue%s = new MessageCatalogue('%s', %s);
|
|
||||||
\$catalogue%s->addFallbackCatalogue(\$catalogue%s);
|
|
||||||
|
|
||||||
|
|
||||||
EOF
|
|
||||||
,
|
|
||||||
$fallbackSuffix,
|
|
||||||
$fallback,
|
|
||||||
var_export($this->catalogues[$fallback]->all(), true),
|
|
||||||
$currentSuffix,
|
|
||||||
$fallbackSuffix
|
|
||||||
);
|
|
||||||
$current = $fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
$content = sprintf(<<<EOF
|
$content = sprintf(<<<EOF
|
||||||
<?php
|
<?php
|
||||||
|
@ -408,7 +386,7 @@ EOF
|
||||||
|
|
||||||
$catalogue = include $cache;
|
$catalogue = include $cache;
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Old cache returns only the catalogue, without resourcesHash
|
* Old cache returns only the catalogue, without resourcesHash
|
||||||
*/
|
*/
|
||||||
$resourcesHash = null;
|
$resourcesHash = null;
|
||||||
|
@ -423,6 +401,51 @@ EOF
|
||||||
$this->catalogues[$locale] = $catalogue;
|
$this->catalogues[$locale] = $catalogue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getFallbackContent(MessageCatalogue $catalogue)
|
||||||
|
{
|
||||||
|
if (!$this->debug) {
|
||||||
|
// merge all fallback catalogues messages into $catalogue
|
||||||
|
$fallbackCatalogue = $catalogue->getFallbackCatalogue();
|
||||||
|
$messages = $catalogue->all();
|
||||||
|
while ($fallbackCatalogue) {
|
||||||
|
$messages = array_replace_recursive($fallbackCatalogue->all(), $messages);
|
||||||
|
$fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();
|
||||||
|
}
|
||||||
|
foreach ($messages as $domain => $domainMessages) {
|
||||||
|
$catalogue->add($domainMessages, $domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$fallbackContent = '';
|
||||||
|
$current = '';
|
||||||
|
$replacementPattern = '/[^a-z0-9_]/i';
|
||||||
|
$fallbackCatalogue = $catalogue->getFallbackCatalogue();
|
||||||
|
while ($fallbackCatalogue) {
|
||||||
|
$fallback = $fallbackCatalogue->getLocale();
|
||||||
|
$fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback));
|
||||||
|
$currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current));
|
||||||
|
|
||||||
|
$fallbackContent .= sprintf(<<<EOF
|
||||||
|
\$catalogue%s = new MessageCatalogue('%s', %s);
|
||||||
|
\$catalogue%s->addFallbackCatalogue(\$catalogue%s);
|
||||||
|
|
||||||
|
EOF
|
||||||
|
,
|
||||||
|
$fallbackSuffix,
|
||||||
|
$fallback,
|
||||||
|
var_export($fallbackCatalogue->all(), true),
|
||||||
|
$currentSuffix,
|
||||||
|
$fallbackSuffix
|
||||||
|
);
|
||||||
|
$current = $fallbackCatalogue->getLocale();
|
||||||
|
$fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fallbackContent;
|
||||||
|
}
|
||||||
|
|
||||||
private function getResourcesHash($locale)
|
private function getResourcesHash($locale)
|
||||||
{
|
{
|
||||||
if (!isset($this->resources[$locale])) {
|
if (!isset($this->resources[$locale])) {
|
||||||
|
|
|
@ -302,6 +302,10 @@
|
||||||
<source>An empty file is not allowed.</source>
|
<source>An empty file is not allowed.</source>
|
||||||
<target>Üres fájl nem megengedett.</target>
|
<target>Üres fájl nem megengedett.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="79">
|
||||||
|
<source>The host could not be resolved.</source>
|
||||||
|
<target>Az állomásnevet nem lehet feloldani.</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
@ -244,7 +244,7 @@ abstract class AbstractConstraintValidatorTest extends \PHPUnit_Framework_TestCa
|
||||||
|
|
||||||
protected function assertNoViolation()
|
protected function assertNoViolation()
|
||||||
{
|
{
|
||||||
$this->assertCount(0, $this->context->getViolations());
|
$this->assertSame(0, $violationsCount = count($this->context->getViolations()), sprintf('0 violation expected. Got %u.', $violationsCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -417,7 +417,7 @@ class ConstraintViolationAssertion
|
||||||
|
|
||||||
$violations = iterator_to_array($this->context->getViolations());
|
$violations = iterator_to_array($this->context->getViolations());
|
||||||
|
|
||||||
\PHPUnit_Framework_Assert::assertCount(count($expected), $violations);
|
\PHPUnit_Framework_Assert::assertSame($expectedCount = count($expected), $violationsCount = count($violations), sprintf('%u violation(s) expected. Got %u.', $expectedCount, $violationsCount));
|
||||||
|
|
||||||
reset($violations);
|
reset($violations);
|
||||||
|
|
||||||
|
|
|
@ -71,27 +71,17 @@ class ExceptionCaster
|
||||||
{
|
{
|
||||||
$b = (array) $a["\0Exception\0previous"];
|
$b = (array) $a["\0Exception\0previous"];
|
||||||
|
|
||||||
array_splice($b["\0Exception\0trace"], count($a["\0Exception\0trace"]));
|
|
||||||
|
|
||||||
$t = static::$traceArgs;
|
|
||||||
static::$traceArgs = false;
|
|
||||||
$b = static::castException($a["\0Exception\0previous"], $b, $stub, $isNested);
|
|
||||||
static::$traceArgs = $t;
|
|
||||||
|
|
||||||
if (empty($a["\0*\0message"])) {
|
|
||||||
$a["\0*\0message"] = "Unexpected exception thrown from a caster: ".get_class($a["\0Exception\0previous"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($b["\0*\0message"])) {
|
if (isset($b["\0*\0message"])) {
|
||||||
$a["\0~\0message"] = $b["\0*\0message"];
|
$a["\0~\0message"] = $b["\0*\0message"];
|
||||||
}
|
}
|
||||||
if (isset($b["\0*\0file"])) {
|
|
||||||
$a["\0~\0file"] = $b["\0*\0file"];
|
if (isset($a["\0Exception\0trace"])) {
|
||||||
}
|
$b["\0Exception\0trace"][0] += array(
|
||||||
if (isset($b["\0*\0line"])) {
|
'file' => $b["\0*\0file"],
|
||||||
$a["\0~\0line"] = $b["\0*\0line"];
|
'line' => $b["\0*\0line"],
|
||||||
}
|
);
|
||||||
if (isset($b["\0Exception\0trace"])) {
|
array_splice($b["\0Exception\0trace"], -1 - count($a["\0Exception\0trace"]));
|
||||||
|
static::filterTrace($b["\0Exception\0trace"], false);
|
||||||
$a["\0~\0trace"] = $b["\0Exception\0trace"];
|
$a["\0~\0trace"] = $b["\0Exception\0trace"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,30 +59,30 @@ class PdoCaster
|
||||||
|
|
||||||
public static function castPdo(\PDO $c, array $a, Stub $stub, $isNested)
|
public static function castPdo(\PDO $c, array $a, Stub $stub, $isNested)
|
||||||
{
|
{
|
||||||
$a = array();
|
$attr = array();
|
||||||
$errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
|
$errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
|
||||||
$c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
$c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
foreach (self::$pdoAttributes as $attr => $values) {
|
foreach (self::$pdoAttributes as $k => $v) {
|
||||||
if (!isset($attr[0])) {
|
if (!isset($k[0])) {
|
||||||
$attr = $values;
|
$k = $v;
|
||||||
$values = array();
|
$v = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$a[$attr] = 'ERRMODE' === $attr ? $errmode : $c->getAttribute(constant("PDO::ATTR_{$attr}"));
|
$attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(constant('PDO::ATTR_'.$k));
|
||||||
if ($values && isset($values[$a[$attr]])) {
|
if ($v && isset($v[$attr[$k]])) {
|
||||||
$a[$attr] = new ConstStub($values[$a[$attr]], $a[$attr]);
|
$attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]);
|
||||||
}
|
}
|
||||||
} catch (\Exception $m) {
|
} catch (\Exception $e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$m = "\0~\0";
|
$m = "\0~\0";
|
||||||
$a = (array) $c + array(
|
$a += array(
|
||||||
$m.'inTransaction' => method_exists($c, 'inTransaction'),
|
$m.'inTransaction' => method_exists($c, 'inTransaction'),
|
||||||
$m.'errorInfo' => $c->errorInfo(),
|
$m.'errorInfo' => $c->errorInfo(),
|
||||||
$m.'attributes' => $a,
|
$m.'attributes' => $attr,
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($a[$m.'inTransaction']) {
|
if ($a[$m.'inTransaction']) {
|
||||||
|
|
|
@ -288,7 +288,7 @@ abstract class AbstractCloner implements ClonerInterface
|
||||||
$a = $cast;
|
$a = $cast;
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$a["\0~\0⚠"] = new ThrowingCasterException($callback, $e);
|
$a[(Stub::TYPE_OBJECT === $stub->type ? "\0~\0" : '').'⚠'] = new ThrowingCasterException($callback, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $a;
|
return $a;
|
||||||
|
|
|
@ -115,23 +115,52 @@ Sfdump = window.Sfdump || (function (doc) {
|
||||||
|
|
||||||
var refStyle = doc.createElement('style'),
|
var refStyle = doc.createElement('style'),
|
||||||
rxEsc = /([.*+?^${}()|\[\]\/\\])/g,
|
rxEsc = /([.*+?^${}()|\[\]\/\\])/g,
|
||||||
idRx = /\bsf-dump-\d+-ref[012]\w+\b/;
|
idRx = /\bsf-dump-\d+-ref[012]\w+\b/,
|
||||||
|
addEventListener = function (e, n, cb) {
|
||||||
|
e.addEventListener(n, cb, false);
|
||||||
|
};
|
||||||
|
|
||||||
doc.documentElement.firstChild.appendChild(refStyle);
|
doc.documentElement.firstChild.appendChild(refStyle);
|
||||||
|
|
||||||
function toggle(a) {
|
if (!doc.addEventListener) {
|
||||||
var s = a.nextSibling || {};
|
addEventListener = function (element, eventName, callback) {
|
||||||
|
element.attachEvent('on' + eventName, function (e) {
|
||||||
|
e.preventDefault = function () {e.returnValue = false;};
|
||||||
|
e.target = e.srcElement;
|
||||||
|
callback(e);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if ('sf-dump-compact' == s.className) {
|
function toggle(a, recursive) {
|
||||||
a.lastChild.innerHTML = '▼';
|
var s = a.nextSibling || {}, oldClass = s.className, arrow, newClass;
|
||||||
s.className = 'sf-dump-expanded';
|
|
||||||
} else if ('sf-dump-expanded' == s.className) {
|
if ('sf-dump-compact' == oldClass) {
|
||||||
a.lastChild.innerHTML = '▶';
|
arrow = '▼';
|
||||||
s.className = 'sf-dump-compact';
|
newClass = 'sf-dump-expanded';
|
||||||
|
} else if ('sf-dump-expanded' == oldClass) {
|
||||||
|
arrow = '▶';
|
||||||
|
newClass = 'sf-dump-compact';
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.lastChild.innerHTML = arrow;
|
||||||
|
s.className = newClass;
|
||||||
|
|
||||||
|
if (recursive) {
|
||||||
|
try {
|
||||||
|
a = s.querySelectorAll('.'+oldClass);
|
||||||
|
for (s = 0; s < a.length; ++s) {
|
||||||
|
if (a[s].className !== newClass) {
|
||||||
|
a[s].className = newClass;
|
||||||
|
a[s].previousSibling.lastChild.innerHTML = arrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -139,7 +168,7 @@ return function (root) {
|
||||||
root = doc.getElementById(root);
|
root = doc.getElementById(root);
|
||||||
|
|
||||||
function a(e, f) {
|
function a(e, f) {
|
||||||
root.addEventListener(e, function (e) {
|
addEventListener(root, e, function (e) {
|
||||||
if ('A' == e.target.tagName) {
|
if ('A' == e.target.tagName) {
|
||||||
f(e.target, e);
|
f(e.target, e);
|
||||||
} else if ('A' == e.target.parentNode.tagName) {
|
} else if ('A' == e.target.parentNode.tagName) {
|
||||||
|
@ -147,20 +176,23 @@ return function (root) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
root.addEventListener('mouseover', function (e) {
|
addEventListener(root, 'mouseover', function (e) {
|
||||||
if ('' != refStyle.innerHTML) {
|
if ('' != refStyle.innerHTML) {
|
||||||
refStyle.innerHTML = '';
|
refStyle.innerHTML = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
a('mouseover', function (a) {
|
a('mouseover', function (a) {
|
||||||
if (a = idRx.exec(a.className)) {
|
if (a = idRx.exec(a.className)) {
|
||||||
refStyle.innerHTML = 'pre.sf-dump .'+a[0]+'{background-color: #B729D9; color: #FFF !important; border-radius: 2px}';
|
try {
|
||||||
|
refStyle.innerHTML = 'pre.sf-dump .'+a[0]+'{background-color: #B729D9; color: #FFF !important; border-radius: 2px}';
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
a('click', function (a, e) {
|
a('click', function (a, e) {
|
||||||
if (/\bsf-dump-toggle\b/.test(a.className)) {
|
if (/\bsf-dump-toggle\b/.test(a.className)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!toggle(a)) {
|
if (!toggle(a, e.ctrlKey)) {
|
||||||
var r = doc.getElementById(a.getAttribute('href').substr(1)),
|
var r = doc.getElementById(a.getAttribute('href').substr(1)),
|
||||||
s = r.previousSibling,
|
s = r.previousSibling,
|
||||||
f = r.parentNode,
|
f = r.parentNode,
|
||||||
|
@ -174,9 +206,19 @@ return function (root) {
|
||||||
r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\$1'), 'mg'), t[0]);
|
r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\$1'), 'mg'), t[0]);
|
||||||
}
|
}
|
||||||
if ('sf-dump-compact' == r.className) {
|
if ('sf-dump-compact' == r.className) {
|
||||||
toggle(s);
|
toggle(s, e.ctrlKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (doc.getSelection) {
|
||||||
|
try {
|
||||||
|
doc.getSelection().removeAllRanges();
|
||||||
|
} catch (e) {
|
||||||
|
doc.getSelection().empty();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doc.selection.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -210,6 +252,7 @@ return function (root) {
|
||||||
} else {
|
} else {
|
||||||
a.innerHTML += ' ';
|
a.innerHTML += ' ';
|
||||||
}
|
}
|
||||||
|
a.title = (a.title ? a.title+'\n' : '')+'[Ctrl+click] Expand all children';
|
||||||
a.innerHTML += '<span>▼</span>';
|
a.innerHTML += '<span>▼</span>';
|
||||||
a.className += ' sf-dump-toggle';
|
a.className += ' sf-dump-toggle';
|
||||||
if ('sf-dump' != elt.parentNode.className) {
|
if ('sf-dump' != elt.parentNode.className) {
|
||||||
|
|
|
@ -16,21 +16,12 @@ namespace Symfony\Component\VarDumper\Exception;
|
||||||
*/
|
*/
|
||||||
class ThrowingCasterException extends \Exception
|
class ThrowingCasterException extends \Exception
|
||||||
{
|
{
|
||||||
private $caster;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param callable $caster The failing caster
|
* @param callable $caster The failing caster
|
||||||
* @param \Exception $prev The exception thrown from the caster
|
* @param \Exception $prev The exception thrown from the caster
|
||||||
*/
|
*/
|
||||||
public function __construct($caster, \Exception $prev)
|
public function __construct($caster, \Exception $prev)
|
||||||
{
|
{
|
||||||
if (is_array($caster)) {
|
parent::__construct('Unexpected exception thrown from a caster: '.get_class($prev), 0, $prev);
|
||||||
if (isset($caster[0]) && is_object($caster[0])) {
|
|
||||||
$caster[0] = get_class($caster[0]);
|
|
||||||
}
|
|
||||||
$caster = implode('::', $caster);
|
|
||||||
}
|
|
||||||
$this->caster = $caster;
|
|
||||||
parent::__construct(null, 0, $prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,58 @@ EOTXT
|
||||||
error_code: XML_ERROR_NONE
|
error_code: XML_ERROR_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EOTXT
|
||||||
|
,
|
||||||
|
$out
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testThrowingCaster()
|
||||||
|
{
|
||||||
|
$out = fopen('php://memory', 'r+b');
|
||||||
|
|
||||||
|
$dumper = new CliDumper();
|
||||||
|
$dumper->setColors(false);
|
||||||
|
$cloner = new VarCloner();
|
||||||
|
$cloner->addCasters(array(
|
||||||
|
':stream' => function () {
|
||||||
|
throw new \Exception('Foobar');
|
||||||
|
},
|
||||||
|
));
|
||||||
|
$line = __LINE__ - 3;
|
||||||
|
$file = __FILE__;
|
||||||
|
$ref = (int) $out;
|
||||||
|
|
||||||
|
$data = $cloner->cloneVar($out);
|
||||||
|
$dumper->dump($data, $out);
|
||||||
|
rewind($out);
|
||||||
|
$out = stream_get_contents($out);
|
||||||
|
|
||||||
|
$this->assertStringMatchesFormat(
|
||||||
|
<<<EOTXT
|
||||||
|
:stream {@{$ref}
|
||||||
|
wrapper_type: "PHP"
|
||||||
|
stream_type: "MEMORY"
|
||||||
|
mode: "w+b"
|
||||||
|
unread_bytes: 0
|
||||||
|
seekable: true
|
||||||
|
uri: "php://memory"
|
||||||
|
timed_out: false
|
||||||
|
blocked: true
|
||||||
|
eof: false
|
||||||
|
options: []
|
||||||
|
⚠: Symfony\Component\VarDumper\Exception\ThrowingCasterException {#%d
|
||||||
|
#message: "Unexpected exception thrown from a caster: Exception"
|
||||||
|
message: "Foobar"
|
||||||
|
trace: array:1 [
|
||||||
|
0 => array:2 [
|
||||||
|
"call" => "%s{closure}()"
|
||||||
|
"file" => "{$file}:{$line}"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EOTXT
|
EOTXT
|
||||||
,
|
,
|
||||||
$out
|
$out
|
||||||
|
|
Reference in New Issue