merged branch bschussek/form-debugger (PR #9082)
This PR was merged into the master branch. Discussion ---------- [Form] Implemented form debugger Same as #9021 (kudos to @digitalkaoz!), with some added caramel. | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - **Note:** Please keep in mind that this is a first version only. Not all features (especially UX/UI-wise) that I'd like to see are in there, but it's good enough for a first merge. Commits -------89509d9
[Form] Improved form debuggerf56c577
[HttpKernel] Extracted value exporting logic of DataCollector into a separate ValueExporter class56d78ed
[Form] Decoupled methods of ResolvedFormType so that they can be overridden individually by decoratorsa994a5d
[Form] Merged subsriber/collector, also collect valid forms1972a91
[Form] Added form debug collector
This commit is contained in:
commit
55de9d9746
@ -218,6 +218,7 @@ class FrameworkExtension extends Extension
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$loader->load('form_debug.xml');
|
||||||
$loader->load('profiling.xml');
|
$loader->load('profiling.xml');
|
||||||
$loader->load('collectors.xml');
|
$loader->load('collectors.xml');
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
<parameter key="data_collector.time.class">Symfony\Component\HttpKernel\DataCollector\TimeDataCollector</parameter>
|
<parameter key="data_collector.time.class">Symfony\Component\HttpKernel\DataCollector\TimeDataCollector</parameter>
|
||||||
<parameter key="data_collector.memory.class">Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector</parameter>
|
<parameter key="data_collector.memory.class">Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector</parameter>
|
||||||
<parameter key="data_collector.router.class">Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector</parameter>
|
<parameter key="data_collector.router.class">Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector</parameter>
|
||||||
|
<parameter key="data_collector.form.class">Symfony\Component\Form\Extension\DataCollector\FormDataCollector</parameter>
|
||||||
|
<parameter key="data_collector.form.extractor.class">Symfony\Component\Form\Extension\DataCollector\FormDataExtractor</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
|
|
||||||
<services>
|
<services>
|
||||||
@ -53,5 +55,13 @@
|
|||||||
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController"/>
|
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController"/>
|
||||||
<tag name="data_collector" template="@WebProfiler/Collector/router.html.twig" id="router" priority="255" />
|
<tag name="data_collector" template="@WebProfiler/Collector/router.html.twig" id="router" priority="255" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service id="data_collector.form.extractor" class="%data_collector.form.extractor.class%" />
|
||||||
|
|
||||||
|
<service id="data_collector.form" class="%data_collector.form.class%">
|
||||||
|
<tag name="data_collector" template="@WebProfiler/Collector/form.html.twig" id="form" priority="255" />
|
||||||
|
<argument type="service" id="data_collector.form.extractor" />
|
||||||
|
</service>
|
||||||
|
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
|
||||||
|
<container xmlns="http://symfony.com/schema/dic/services"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||||
|
|
||||||
|
<parameters>
|
||||||
|
<parameter key="form.resolved_type_factory.data_collector_proxy.class">Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeFactoryDataCollectorProxy</parameter>
|
||||||
|
<parameter key="form.type_extension.form.data_collector.class">Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension</parameter>
|
||||||
|
</parameters>
|
||||||
|
|
||||||
|
<services>
|
||||||
|
<service id="form.resolved_type_factory" class="%form.resolved_type_factory.data_collector_proxy.class%">
|
||||||
|
<argument type="service">
|
||||||
|
<service class="%form.resolved_type_factory.class%" />
|
||||||
|
</argument>
|
||||||
|
<argument type="service" id="data_collector.form" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<!-- DataCollectorTypeExtension -->
|
||||||
|
<service id="form.type_extension.form.data_collector" class="%form.type_extension.form.data_collector.class%">
|
||||||
|
<tag name="form.type_extension" alias="form" />
|
||||||
|
<argument type="service" id="data_collector.form" />
|
||||||
|
</service>
|
||||||
|
</services>
|
||||||
|
</container>
|
@ -0,0 +1,345 @@
|
|||||||
|
{% extends '@WebProfiler/Profiler/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% from _self import form_tree_entry, form_tree_details %}
|
||||||
|
|
||||||
|
{% block toolbar %}
|
||||||
|
{% if collector.data|length %}
|
||||||
|
{% set icon %}
|
||||||
|
<img width="20" height="28" alt="Forms" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAYAAAB836/YAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpDNkE1RUQ2RjBFMzcxMUUzOEIyQkVBRkQ5QzNENTIxMyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpDNkE1RUQ3MDBFMzcxMUUzOEIyQkVBRkQ5QzNENTIxMyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkM2QTVFRDZEMEUzNzExRTM4QjJCRUFGRDlDM0Q1MjEzIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkM2QTVFRDZFMEUzNzExRTM4QjJCRUFGRDlDM0Q1MjEzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+fkaAkgAAAQtJREFUeNpi/P//PwM1ARMDlQGLg4MDgsPCAqb//PnDwMzMDGJ+//v3L4oGqDgnSBxZPdwMLJa4ggioQRzoklBxVySh3SguBOICGOffv38TgNQuIny2C6oeRDEim8Fob28PjxVgBIEk/zMyMhIVXqAIZYQo/o81UlhZWcGYWIBNLQta+PACKS1iDYSGJy9OA4Fe+EBKUsKWhlmwpMtZZCS/NHzJ5iFFCRuN7wXEEtQ0sJDirIfGrwBiLiL0HSbWwLPoWQkH2I0tu+KKlOVk+BSngclALEnNMHSldqTMJtOcCFwGNlDbhZ1Y1LwhwpwTuAz0waI4gxIXPqC2lzuoYeAPalajjIO+ogcIMAAaCkonoOPIhQAAAABJRU5ErkJggg=="/>
|
||||||
|
<span class="sf-toolbar-status sf-toolbar-status-{% if collector.data.nb_errors %}red{% else %}green{% endif %}">{% if collector.data.nb_errors %}{{ collector.data.nb_errors }}{% else %}{{ collector.data.forms|length }}{% endif %}</span>
|
||||||
|
{% endset %}
|
||||||
|
|
||||||
|
{% include '@WebProfiler/Profiler/toolbar_item.html.twig' with { 'link': profiler_url } %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block menu %}
|
||||||
|
<span class="label">
|
||||||
|
<span class="icon"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAYAAAB836/YAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh3ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAIpJREFUeNrslFEKgDAMQ1PpzrX7n6mF+KMfTjvnnKBgYD+heaQUJjlnRFJVunvpwd0lykyoqIRFXhWoqgSwvkgEwGV2my+CctYgaMumlXu0A6aUmsNHs1oaZiatQDM7BXL4ynelB550cFgDcmRD6eTwsaP0NmQrkP+Vv3vlv+G1hrwDfN8HOxw4DwC6ITLy7UIfRQAAAABJRU5ErkJggg==" alt=""/></span>
|
||||||
|
<strong>Forms</strong>
|
||||||
|
{% if collector.data.forms|length %}
|
||||||
|
<span class="count"><span>{{ collector.data.forms|length }}</span></span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block panel %}
|
||||||
|
<style type="text/css">
|
||||||
|
.window {
|
||||||
|
/*background: #F6F6F6;*/
|
||||||
|
margin: -30px -40px -40px;
|
||||||
|
}
|
||||||
|
.tree {
|
||||||
|
width: 230px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
#content .tree h2 {
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 5px 7px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.tree li {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.tree a {
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
padding: 5px 7px;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #313131;
|
||||||
|
}
|
||||||
|
.tree ul ul a {
|
||||||
|
padding-left: 22px;
|
||||||
|
}
|
||||||
|
.tree ul ul ul a {
|
||||||
|
padding-left: 37px;
|
||||||
|
}
|
||||||
|
.tree ul ul ul ul a {
|
||||||
|
padding-left: 52px;
|
||||||
|
}
|
||||||
|
.tree ul ul ul ul ul a {
|
||||||
|
padding-left: 67px;
|
||||||
|
}
|
||||||
|
.tree a:hover {
|
||||||
|
background: #dfdfdf;
|
||||||
|
}
|
||||||
|
.tree a.active, a.active:hover {
|
||||||
|
background: #dfdfdf;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #313131;
|
||||||
|
}
|
||||||
|
.tree-details {
|
||||||
|
border-left: 1px solid #dfdfdf;
|
||||||
|
background: white;
|
||||||
|
margin-left: 250px;
|
||||||
|
padding: 30px 40px 40px;
|
||||||
|
}
|
||||||
|
.form-type {
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
{% if collector.data.forms|length %}
|
||||||
|
<div class="window">
|
||||||
|
<div class="tree">
|
||||||
|
<h2>Forms</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for formName, formData in collector.data.forms %}
|
||||||
|
{{ form_tree_entry(formName, formData) }}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for formName, formData in collector.data.forms %}
|
||||||
|
{{ form_tree_details(formName, formData) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p><em>No forms were submitted for this request.</em></p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function TabView() {
|
||||||
|
var _activeLink = null,
|
||||||
|
_activeView = null;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
var links = document.querySelectorAll('.tree a'),
|
||||||
|
views = document.querySelectorAll('.tree-details'),
|
||||||
|
i,
|
||||||
|
l;
|
||||||
|
|
||||||
|
for (i = 0, l = links.length; i < l; ++i) {
|
||||||
|
(function () {
|
||||||
|
var link = links[i];
|
||||||
|
|
||||||
|
link.addEventListener('click', function (e) {
|
||||||
|
var href = link.getAttribute('href'),
|
||||||
|
targetId = href.substr(href.indexOf('#') + 1),
|
||||||
|
view = document.getElementById(targetId);
|
||||||
|
|
||||||
|
if (view) {
|
||||||
|
if (null !== _activeLink) {
|
||||||
|
Sfjs.removeClass(_activeLink, 'active');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== _activeView) {
|
||||||
|
Sfjs.addClass(_activeView, 'hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
Sfjs.addClass(link, 'active');
|
||||||
|
Sfjs.removeClass(view, 'hidden');
|
||||||
|
|
||||||
|
_activeLink = link;
|
||||||
|
_activeView = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, l = views.length; i < l; ++i) {
|
||||||
|
Sfjs.addClass(views[i], 'hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (links.length > 0) {
|
||||||
|
Sfjs.addClass(links[0], 'active');
|
||||||
|
_activeLink = links[0];
|
||||||
|
|
||||||
|
if (views.length > 0) {
|
||||||
|
Sfjs.removeClass(views[0], 'hidden');
|
||||||
|
_activeView = views[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tabView = new TabView();
|
||||||
|
|
||||||
|
tabView.init();
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% macro form_tree_entry(name, data) %}
|
||||||
|
<li>
|
||||||
|
<a href="#details_{{ data.view_vars.id|default("") }}">{{ name }}</a>
|
||||||
|
|
||||||
|
{% if data.children|length > 1 %}
|
||||||
|
<ul>
|
||||||
|
{% for childName, childData in data.children %}
|
||||||
|
{{ _self.form_tree_entry(childName, childData) }}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro form_tree_details(name, data) %}
|
||||||
|
<div class="tree-details" id="details_{{ data.view_vars.id|default("") }}">
|
||||||
|
<h2>
|
||||||
|
{{ name }}
|
||||||
|
{% if data.type_class is defined %}
|
||||||
|
<span class="form-type">[<abbr title="{{ data.type_class }}">{{ data.type }}</abbr>]</span>
|
||||||
|
{% endif %}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{% if data.errors is defined and data.errors|length > 0 %}
|
||||||
|
<h3>Errors</h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th width="50%">Message</th>
|
||||||
|
<th>Cause</th>
|
||||||
|
</tr>
|
||||||
|
{% for error in data.errors %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ error.message }}</td>
|
||||||
|
<td><em>Unknown.</em></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if data.default_data is defined %}
|
||||||
|
<h3>Default Data</h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th width="180">Model Format</th>
|
||||||
|
<td>
|
||||||
|
{% if data.default_data.model is defined %}
|
||||||
|
<pre>{{ data.default_data.model }}</pre>
|
||||||
|
{% else %}
|
||||||
|
<em>same as normalized format</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Normalized Format</th>
|
||||||
|
<td><pre>{{ data.default_data.norm }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>View Format</th>
|
||||||
|
<td>
|
||||||
|
{% if data.default_data.view is defined %}
|
||||||
|
<pre>{{ data.default_data.view }}</pre>
|
||||||
|
{% else %}
|
||||||
|
<em>same as normalized format</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if data.submitted_data is defined %}
|
||||||
|
<h3>Submitted Data</h3>
|
||||||
|
|
||||||
|
{% if data.submitted_data.norm is defined %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th width="180">View Format</th>
|
||||||
|
<td>
|
||||||
|
{% if data.submitted_data.view is defined %}
|
||||||
|
<pre>{{ data.submitted_data.view }}</pre>
|
||||||
|
{% else %}
|
||||||
|
<em>same as normalized format</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Normalized Format</th>
|
||||||
|
<td><pre>{{ data.submitted_data.norm }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Model Format</th>
|
||||||
|
<td>
|
||||||
|
{% if data.submitted_data.model is defined %}
|
||||||
|
<pre>{{ data.submitted_data.model }}</pre>
|
||||||
|
{% else %}
|
||||||
|
<em>same as normalized format</em>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p><em>This form was not submitted.</em></p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if data.passed_options is defined %}
|
||||||
|
<h3>Passed Options</h3>
|
||||||
|
|
||||||
|
{% if data.passed_options|length %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th width="180">Option</th>
|
||||||
|
<th>Passed Value</th>
|
||||||
|
<th>Resolved Value</th>
|
||||||
|
</tr>
|
||||||
|
{% for option, value in data.passed_options %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ option }}</th>
|
||||||
|
<td><pre>{{ value }}</pre></td>
|
||||||
|
<td>
|
||||||
|
{% if data.resolved_options[option] is sameas(value) %}
|
||||||
|
<em>same as passed value</em>
|
||||||
|
{% else %}
|
||||||
|
<pre>{{ data.resolved_options[option] }}</pre>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p><em>No options where passed when constructing this form.</em></p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if data.resolved_options is defined %}
|
||||||
|
<h3>Resolved Options</h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th width="180">Option</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
{% for option, value in data.resolved_options %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ option }}</th>
|
||||||
|
<td><pre>{{ value }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h3>View Variables</h3>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th width="180">Variable</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
{% for variable, value in data.view_vars %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ variable }}</th>
|
||||||
|
<td><pre>{{ value }}</pre></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for childName, childData in data.children %}
|
||||||
|
{{ _self.form_tree_details(childName, childData) }}
|
||||||
|
{% endfor %}
|
||||||
|
{% endmacro %}
|
@ -63,6 +63,9 @@ table th, table td {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
}
|
}
|
||||||
|
table td em {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
fieldset {
|
fieldset {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@ -70,6 +73,9 @@ abbr {
|
|||||||
border-bottom: 1px dotted #000;
|
border-bottom: 1px dotted #000;
|
||||||
cursor: help;
|
cursor: help;
|
||||||
}
|
}
|
||||||
|
pre, code {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
.clear {
|
.clear {
|
||||||
clear: both;
|
clear: both;
|
||||||
height: 0;
|
height: 0;
|
||||||
|
@ -412,7 +412,16 @@ class Button implements \IteratorAggregate, FormInterface
|
|||||||
$parent = $this->parent->createView();
|
$parent = $this->parent->createView();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->config->getType()->createView($this, $parent);
|
|
||||||
|
$type = $this->config->getType();
|
||||||
|
$options = $this->config->getOptions();
|
||||||
|
|
||||||
|
$view = $type->createView($this, $parent);
|
||||||
|
|
||||||
|
$type->buildView($view, $this, $options);
|
||||||
|
$type->finishView($view, $this, $options);
|
||||||
|
|
||||||
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Symfony\Component\Form\AbstractExtension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension for collecting data of the forms on a page.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Robert Schönthal <robert.schoenthal@gmail.com>
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class DataCollectorExtension extends AbstractExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var EventSubscriberInterface
|
||||||
|
*/
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
public function __construct(FormDataCollectorInterface $dataCollector)
|
||||||
|
{
|
||||||
|
$this->dataCollector = $dataCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function loadTypeExtensions()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
new Type\DataCollectorTypeExtension($this->dataCollector)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
<?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\Extension\DataCollector\EventListener;
|
||||||
|
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that invokes a data collector for the {@link FormEvents::POST_SET_DATA}
|
||||||
|
* and {@link FormEvents::POST_SUBMIT} events.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class DataCollectorListener implements EventSubscriberInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var FormDataCollectorInterface
|
||||||
|
*/
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
public function __construct(FormDataCollectorInterface $dataCollector)
|
||||||
|
{
|
||||||
|
$this->dataCollector = $dataCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public static function getSubscribedEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
// High priority in order to be called as soon as possible
|
||||||
|
FormEvents::POST_SET_DATA => array('postSetData', 255),
|
||||||
|
// Low priority in order to be called as late as possible
|
||||||
|
FormEvents::POST_SUBMIT => array('postSubmit', -255),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for the {@link FormEvents::POST_SET_DATA} event.
|
||||||
|
*
|
||||||
|
* @param FormEvent $event The event object
|
||||||
|
*/
|
||||||
|
public function postSetData(FormEvent $event)
|
||||||
|
{
|
||||||
|
if ($event->getForm()->isRoot()) {
|
||||||
|
// Collect basic information about each form
|
||||||
|
$this->dataCollector->collectConfiguration($event->getForm());
|
||||||
|
|
||||||
|
// Collect the default data
|
||||||
|
$this->dataCollector->collectDefaultData($event->getForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for the {@link FormEvents::POST_SUBMIT} event.
|
||||||
|
*
|
||||||
|
* @param FormEvent $event The event object
|
||||||
|
*/
|
||||||
|
public function postSubmit(FormEvent $event)
|
||||||
|
{
|
||||||
|
if ($event->getForm()->isRoot()) {
|
||||||
|
// Collect the submitted data of each form
|
||||||
|
$this->dataCollector->collectSubmittedData($event->getForm());
|
||||||
|
|
||||||
|
// Assemble a form tree
|
||||||
|
// This is done again in collectViewVariables(), but that method
|
||||||
|
// is not guaranteed to be called (i.e. when no view is created)
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($event->getForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,274 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data collector for {@link \Symfony\Component\Form\FormInterface} instances.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Robert Schönthal <robert.schoenthal@gmail.com>
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class FormDataCollector extends DataCollector implements FormDataCollectorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var FormDataExtractor
|
||||||
|
*/
|
||||||
|
private $dataExtractor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the collected data per {@link FormInterface} instance.
|
||||||
|
*
|
||||||
|
* Uses the hashes of the forms as keys. This is preferrable over using
|
||||||
|
* {@link \SplObjectStorage}, because in this way no references are kept
|
||||||
|
* to the {@link FormInterface} instances.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $dataByForm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the collected data per {@link FormView} instance.
|
||||||
|
*
|
||||||
|
* Uses the hashes of the views as keys. This is preferrable over using
|
||||||
|
* {@link \SplObjectStorage}, because in this way no references are kept
|
||||||
|
* to the {@link FormView} instances.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $dataByView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects {@link FormView} with {@link FormInterface} instances.
|
||||||
|
*
|
||||||
|
* Uses the hashes of the views as keys and the hashes of the forms as
|
||||||
|
* values. This is preferrable over storing the objects directly, because
|
||||||
|
* this way they can safely be discarded by the GC.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $formsByView;
|
||||||
|
|
||||||
|
public function __construct(FormDataExtractorInterface $dataExtractor)
|
||||||
|
{
|
||||||
|
$this->dataExtractor = $dataExtractor;
|
||||||
|
$this->data = array(
|
||||||
|
'forms' => array(),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing. The data is collected during the form event listeners.
|
||||||
|
*/
|
||||||
|
public function collect(Request $request, Response $response, \Exception $exception = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function associateFormWithView(FormInterface $form, FormView $view)
|
||||||
|
{
|
||||||
|
$this->formsByView[spl_object_hash($view)] = spl_object_hash($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function collectConfiguration(FormInterface $form)
|
||||||
|
{
|
||||||
|
$hash = spl_object_hash($form);
|
||||||
|
|
||||||
|
if (!isset($this->dataByForm[$hash])) {
|
||||||
|
$this->dataByForm[$hash] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dataByForm[$hash] = array_replace(
|
||||||
|
$this->dataByForm[$hash],
|
||||||
|
$this->dataExtractor->extractConfiguration($form)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($form as $child) {
|
||||||
|
$this->collectConfiguration($child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function collectDefaultData(FormInterface $form)
|
||||||
|
{
|
||||||
|
$hash = spl_object_hash($form);
|
||||||
|
|
||||||
|
if (!isset($this->dataByForm[$hash])) {
|
||||||
|
$this->dataByForm[$hash] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dataByForm[$hash] = array_replace(
|
||||||
|
$this->dataByForm[$hash],
|
||||||
|
$this->dataExtractor->extractDefaultData($form)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($form as $child) {
|
||||||
|
$this->collectDefaultData($child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function collectSubmittedData(FormInterface $form)
|
||||||
|
{
|
||||||
|
$hash = spl_object_hash($form);
|
||||||
|
|
||||||
|
if (!isset($this->dataByForm[$hash])) {
|
||||||
|
$this->dataByForm[$hash] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dataByForm[$hash] = array_replace(
|
||||||
|
$this->dataByForm[$hash],
|
||||||
|
$this->dataExtractor->extractSubmittedData($form)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Count errors
|
||||||
|
if (isset($this->dataByForm[$hash]['errors'])) {
|
||||||
|
$this->data['nb_errors'] += count($this->dataByForm[$hash]['errors']);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($form as $child) {
|
||||||
|
$this->collectSubmittedData($child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function collectViewVariables(FormView $view)
|
||||||
|
{
|
||||||
|
$hash = spl_object_hash($view);
|
||||||
|
|
||||||
|
if (!isset($this->dataByView[$hash])) {
|
||||||
|
$this->dataByView[$hash] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->dataByView[$hash] = array_replace(
|
||||||
|
$this->dataByView[$hash],
|
||||||
|
$this->dataExtractor->extractViewVariables($view)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($view->children as $child) {
|
||||||
|
$this->collectViewVariables($child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildPreliminaryFormTree(FormInterface $form)
|
||||||
|
{
|
||||||
|
$this->data['forms'][$form->getName()] = array();
|
||||||
|
|
||||||
|
$this->recursiveBuildPreliminaryFormTree($form, $this->data['forms'][$form->getName()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildFinalFormTree(FormInterface $form, FormView $view)
|
||||||
|
{
|
||||||
|
$this->data['forms'][$form->getName()] = array();
|
||||||
|
|
||||||
|
$this->recursiveBuildFinalFormTree($form, $view, $this->data['forms'][$form->getName()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'form';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function recursiveBuildPreliminaryFormTree(FormInterface $form, &$output = null)
|
||||||
|
{
|
||||||
|
$hash = spl_object_hash($form);
|
||||||
|
|
||||||
|
$output = isset($this->dataByForm[$hash])
|
||||||
|
? $this->dataByForm[$hash]
|
||||||
|
: array();
|
||||||
|
|
||||||
|
$output['children'] = array();
|
||||||
|
|
||||||
|
foreach ($form as $name => $child) {
|
||||||
|
$output['children'][$name] = array();
|
||||||
|
|
||||||
|
$this->recursiveBuildPreliminaryFormTree($child, $output['children'][$name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function recursiveBuildFinalFormTree(FormInterface $form = null, FormView $view, &$output = null)
|
||||||
|
{
|
||||||
|
$viewHash = spl_object_hash($view);
|
||||||
|
$formHash = null;
|
||||||
|
|
||||||
|
if (null !== $form) {
|
||||||
|
$formHash = spl_object_hash($form);
|
||||||
|
} elseif (isset($this->formsByView[$viewHash])) {
|
||||||
|
// The FormInterface instance of the CSRF token is never contained in
|
||||||
|
// the FormInterface tree of the form, so we need to get the
|
||||||
|
// corresponding FormInterface instance for its view in a different way
|
||||||
|
$formHash = $this->formsByView[$viewHash];
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = isset($this->dataByView[$viewHash])
|
||||||
|
? $this->dataByView[$viewHash]
|
||||||
|
: array();
|
||||||
|
|
||||||
|
if (null !== $formHash) {
|
||||||
|
$output = array_replace(
|
||||||
|
$output,
|
||||||
|
isset($this->dataByForm[$formHash])
|
||||||
|
? $this->dataByForm[$formHash]
|
||||||
|
: array()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$output['children'] = array();
|
||||||
|
|
||||||
|
foreach ($view->children as $name => $childView) {
|
||||||
|
// The CSRF token, for example, is never added to the form tree.
|
||||||
|
// It is only present in the view.
|
||||||
|
$childForm = null !== $form && $form->has($name)
|
||||||
|
? $form->get($name)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
$output['children'][$name] = array();
|
||||||
|
|
||||||
|
$this->recursiveBuildFinalFormTree($childForm, $childView, $output['children'][$name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects and structures information about forms.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
interface FormDataCollectorInterface extends DataCollectorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Stores configuration data of the given form and its children.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form A root form
|
||||||
|
*/
|
||||||
|
public function collectConfiguration(FormInterface $form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the default data of the given form and its children.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form A root form
|
||||||
|
*/
|
||||||
|
public function collectDefaultData(FormInterface $form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the submitted data of the given form and its children.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form A root form
|
||||||
|
*/
|
||||||
|
public function collectSubmittedData(FormInterface $form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the view variables of the given form view and its children.
|
||||||
|
*
|
||||||
|
* @param FormView $view A root form view
|
||||||
|
*/
|
||||||
|
public function collectViewVariables(FormView $view);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that the given objects represent the same conceptual form.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form A form object
|
||||||
|
* @param FormView $view A view object
|
||||||
|
*/
|
||||||
|
public function associateFormWithView(FormInterface $form, FormView $view);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assembles the data collected about the given form and its children as
|
||||||
|
* a tree-like data structure.
|
||||||
|
*
|
||||||
|
* The result can be queried using {@link getData()}.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form A root form
|
||||||
|
*/
|
||||||
|
public function buildPreliminaryFormTree(FormInterface $form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assembles the data collected about the given form and its children as
|
||||||
|
* a tree-like data structure.
|
||||||
|
*
|
||||||
|
* The result can be queried using {@link getData()}.
|
||||||
|
*
|
||||||
|
* Contrary to {@link buildPreliminaryFormTree()}, a {@link FormView}
|
||||||
|
* object has to be passed. The tree structure of this view object will be
|
||||||
|
* used for structuring the resulting data. That means, if a child is
|
||||||
|
* present in the view, but not in the form, it will be present in the final
|
||||||
|
* data array anyway.
|
||||||
|
*
|
||||||
|
* When {@link FormView} instances are present in the view tree, for which
|
||||||
|
* no corresponding {@link FormInterface} objects can be found in the form
|
||||||
|
* tree, only the view data will be included in the result. If a
|
||||||
|
* corresponding {@link FormInterface} exists otherwise, call
|
||||||
|
* {@link associateFormWithView()} before calling this method.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form A root form
|
||||||
|
* @param FormView $view A root view
|
||||||
|
*/
|
||||||
|
public function buildFinalFormTree(FormInterface $form, FormView $view);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all collected data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getData();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link FormDataExtractorInterface}.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class FormDataExtractor implements FormDataExtractorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ValueExporter
|
||||||
|
*/
|
||||||
|
private $valueExporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new data extractor.
|
||||||
|
*/
|
||||||
|
public function __construct(ValueExporter $valueExporter = null)
|
||||||
|
{
|
||||||
|
$this->valueExporter = $valueExporter ?: new ValueExporter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function extractConfiguration(FormInterface $form)
|
||||||
|
{
|
||||||
|
$data = array(
|
||||||
|
'type' => $form->getConfig()->getType()->getName(),
|
||||||
|
'type_class' => get_class($form->getConfig()->getType()->getInnerType()),
|
||||||
|
'synchronized' => $this->valueExporter->exportValue($form->isSynchronized()),
|
||||||
|
'passed_options' => array(),
|
||||||
|
'resolved_options' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($form->getConfig()->getAttribute('data_collector/passed_options', array()) as $option => $value) {
|
||||||
|
$data['passed_options'][$option] = $this->valueExporter->exportValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($form->getConfig()->getOptions() as $option => $value) {
|
||||||
|
$data['resolved_options'][$option] = $this->valueExporter->exportValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($data['passed_options']);
|
||||||
|
ksort($data['resolved_options']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function extractDefaultData(FormInterface $form)
|
||||||
|
{
|
||||||
|
$data = array(
|
||||||
|
'default_data' => array(
|
||||||
|
'norm' => $this->valueExporter->exportValue($form->getNormData()),
|
||||||
|
),
|
||||||
|
'submitted_data' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($form->getData() !== $form->getNormData()) {
|
||||||
|
$data['default_data']['model'] = $this->valueExporter->exportValue($form->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->getViewData() !== $form->getNormData()) {
|
||||||
|
$data['default_data']['view'] = $this->valueExporter->exportValue($form->getViewData());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function extractSubmittedData(FormInterface $form)
|
||||||
|
{
|
||||||
|
$data = array(
|
||||||
|
'submitted_data' => array(
|
||||||
|
'norm' => $this->valueExporter->exportValue($form->getNormData()),
|
||||||
|
),
|
||||||
|
'errors' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($form->getViewData() !== $form->getNormData()) {
|
||||||
|
$data['submitted_data']['view'] = $this->valueExporter->exportValue($form->getViewData());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->getData() !== $form->getNormData()) {
|
||||||
|
$data['submitted_data']['model'] = $this->valueExporter->exportValue($form->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($form->getErrors() as $error) {
|
||||||
|
$data['errors'][] = array(
|
||||||
|
'message' => $error->getMessage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['synchronized'] = $this->valueExporter->exportValue($form->isSynchronized());
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function extractViewVariables(FormView $view)
|
||||||
|
{
|
||||||
|
$data = array();
|
||||||
|
|
||||||
|
foreach ($view->vars as $varName => $value) {
|
||||||
|
$data['view_vars'][$varName] = $this->valueExporter->exportValue($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($data['view_vars']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts arrays of information out of forms.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
interface FormDataExtractorInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Extracts the configuration data of a form.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form The form
|
||||||
|
*
|
||||||
|
* @return array Information about the form's configuration
|
||||||
|
*/
|
||||||
|
public function extractConfiguration(FormInterface $form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the default data of a form.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form The form
|
||||||
|
*
|
||||||
|
* @return array Information about the form's default data
|
||||||
|
*/
|
||||||
|
public function extractDefaultData(FormInterface $form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the submitted data of a form.
|
||||||
|
*
|
||||||
|
* @param FormInterface $form The form
|
||||||
|
*
|
||||||
|
* @return array Information about the form's submitted data
|
||||||
|
*/
|
||||||
|
public function extractSubmittedData(FormInterface $form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the view variables of a form.
|
||||||
|
*
|
||||||
|
* @param FormView $view The form view
|
||||||
|
*
|
||||||
|
* @return array Information about the view's variables
|
||||||
|
*/
|
||||||
|
public function extractViewVariables(FormView $view);
|
||||||
|
}
|
@ -0,0 +1,148 @@
|
|||||||
|
<?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\Extension\DataCollector\Proxy;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormFactoryInterface;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\Form\ResolvedFormTypeInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy that invokes a data collector when creating a form and its view.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class ResolvedTypeDataCollectorProxy implements ResolvedFormTypeInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ResolvedFormTypeInterface
|
||||||
|
*/
|
||||||
|
private $proxiedType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FormDataCollectorInterface
|
||||||
|
*/
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
public function __construct(ResolvedFormTypeInterface $proxiedType, FormDataCollectorInterface $dataCollector)
|
||||||
|
{
|
||||||
|
$this->proxiedType = $proxiedType;
|
||||||
|
$this->dataCollector = $dataCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->proxiedType->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return $this->proxiedType->getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getInnerType()
|
||||||
|
{
|
||||||
|
return $this->proxiedType->getInnerType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getTypeExtensions()
|
||||||
|
{
|
||||||
|
return $this->proxiedType->getTypeExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createBuilder(FormFactoryInterface $factory, $name, array $options = array())
|
||||||
|
{
|
||||||
|
$builder = $this->proxiedType->createBuilder($factory, $name, $options);
|
||||||
|
|
||||||
|
$builder->setAttribute('data_collector/passed_options', $options);
|
||||||
|
$builder->setType($this);
|
||||||
|
|
||||||
|
return $builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createView(FormInterface $form, FormView $parent = null)
|
||||||
|
{
|
||||||
|
return $this->proxiedType->createView($form, $parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$this->proxiedType->buildForm($builder, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||||
|
{
|
||||||
|
$this->proxiedType->buildView($view, $form, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function finishView(FormView $view, FormInterface $form, array $options)
|
||||||
|
{
|
||||||
|
$this->proxiedType->finishView($view, $form, $options);
|
||||||
|
|
||||||
|
// Remember which view belongs to which form instance, so that we can
|
||||||
|
// get the collected data for a view when its form instance is not
|
||||||
|
// available (e.g. CSRF token)
|
||||||
|
$this->dataCollector->associateFormWithView($form, $view);
|
||||||
|
|
||||||
|
// Since the CSRF token is only present in the FormView tree, we also
|
||||||
|
// need to check the FormView tree instead of calling isRoot() on the
|
||||||
|
// FormInterface tree
|
||||||
|
if (null === $view->parent) {
|
||||||
|
$this->dataCollector->collectViewVariables($view);
|
||||||
|
|
||||||
|
// Re-assemble data, in case FormView instances were added, for
|
||||||
|
// which no FormInterface instances were present (e.g. CSRF token).
|
||||||
|
// Since finishView() is called after finishing the views of all
|
||||||
|
// children, we can safely assume that information has been
|
||||||
|
// collected about the complete form tree.
|
||||||
|
$this->dataCollector->buildFinalFormTree($form, $view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getOptionsResolver()
|
||||||
|
{
|
||||||
|
return $this->proxiedType->getOptionsResolver();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<?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\Extension\DataCollector\Proxy;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Exception;
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface;
|
||||||
|
use Symfony\Component\Form\FormTypeInterface;
|
||||||
|
use Symfony\Component\Form\ResolvedFormTypeFactoryInterface;
|
||||||
|
use Symfony\Component\Form\ResolvedFormTypeInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy that wraps resolved types into {@link ResolvedTypeDataCollectorProxy}
|
||||||
|
* instances.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class ResolvedTypeFactoryDataCollectorProxy implements ResolvedFormTypeFactoryInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ResolvedFormTypeFactoryInterface
|
||||||
|
*/
|
||||||
|
private $proxiedFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FormDataCollectorInterface
|
||||||
|
*/
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
public function __construct(ResolvedFormTypeFactoryInterface $proxiedFactory, FormDataCollectorInterface $dataCollector)
|
||||||
|
{
|
||||||
|
$this->proxiedFactory = $proxiedFactory;
|
||||||
|
$this->dataCollector = $dataCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null)
|
||||||
|
{
|
||||||
|
return new ResolvedTypeDataCollectorProxy(
|
||||||
|
$this->proxiedFactory->createResolvedType($type, $typeExtensions, $parent),
|
||||||
|
$this->dataCollector
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
<?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\Extension\DataCollector\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractTypeExtension;
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\EventListener\DataCollectorListener;
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type extension for collecting data of a form with this type.
|
||||||
|
*
|
||||||
|
* @since 2.4
|
||||||
|
* @author Robert Schönthal <robert.schoenthal@gmail.com>
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class DataCollectorTypeExtension extends AbstractTypeExtension
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \Symfony\Component\EventDispatcher\EventSubscriberInterface
|
||||||
|
*/
|
||||||
|
private $listener;
|
||||||
|
|
||||||
|
public function __construct(FormDataCollectorInterface $dataCollector)
|
||||||
|
{
|
||||||
|
$this->listener = new DataCollectorListener($dataCollector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->addEventSubscriber($this->listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getExtendedType()
|
||||||
|
{
|
||||||
|
return 'form';
|
||||||
|
}
|
||||||
|
}
|
@ -969,7 +969,23 @@ class Form implements \IteratorAggregate, FormInterface
|
|||||||
$parent = $this->parent->createView();
|
$parent = $this->parent->createView();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->config->getType()->createView($this, $parent);
|
$type = $this->config->getType();
|
||||||
|
$options = $this->config->getOptions();
|
||||||
|
|
||||||
|
// The methods createView(), buildView() and finishView() are called
|
||||||
|
// explicitly here in order to be able to override either of them
|
||||||
|
// in a custom resolved form type.
|
||||||
|
$view = $type->createView($this, $parent);
|
||||||
|
|
||||||
|
$type->buildView($view, $this, $options);
|
||||||
|
|
||||||
|
foreach ($this->children as $name => $child) {
|
||||||
|
$view->children[$name] = $child->createView($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
$type->finishView($view, $this, $options);
|
||||||
|
|
||||||
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,7 +84,13 @@ class FormFactory implements FormFactoryInterface
|
|||||||
throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface');
|
throw new UnexpectedTypeException($type, 'string, Symfony\Component\Form\ResolvedFormTypeInterface or Symfony\Component\Form\FormTypeInterface');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $type->createBuilder($this, $name, $options);
|
$builder = $type->createBuilder($this, $name, $options);
|
||||||
|
|
||||||
|
// Explicitly call buildForm() in order to be able to override either
|
||||||
|
// createBuilder() or buildForm() in the resolved form type
|
||||||
|
$type->buildForm($builder, $builder->getOptions());
|
||||||
|
|
||||||
|
return $builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,8 +114,6 @@ class ResolvedFormType implements ResolvedFormTypeInterface
|
|||||||
$builder = $this->newBuilder($name, $dataClass, $factory, $options);
|
$builder = $this->newBuilder($name, $dataClass, $factory, $options);
|
||||||
$builder->setType($this);
|
$builder->setType($this);
|
||||||
|
|
||||||
$this->buildForm($builder, $options);
|
|
||||||
|
|
||||||
return $builder;
|
return $builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,28 +122,12 @@ class ResolvedFormType implements ResolvedFormTypeInterface
|
|||||||
*/
|
*/
|
||||||
public function createView(FormInterface $form, FormView $parent = null)
|
public function createView(FormInterface $form, FormView $parent = null)
|
||||||
{
|
{
|
||||||
$options = $form->getConfig()->getOptions();
|
return $this->newView($parent);
|
||||||
|
|
||||||
$view = $this->newView($parent);
|
|
||||||
|
|
||||||
$this->buildView($view, $form, $options);
|
|
||||||
|
|
||||||
foreach ($form as $name => $child) {
|
|
||||||
/* @var FormInterface $child */
|
|
||||||
$view->children[$name] = $child->createView($view);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->finishView($view, $form, $options);
|
|
||||||
|
|
||||||
return $view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures a form builder for the type hierarchy.
|
* Configures a form builder for the type hierarchy.
|
||||||
*
|
*
|
||||||
* This method is protected in order to allow implementing classes
|
|
||||||
* to change or call it in re-implementations of {@link createBuilder()}.
|
|
||||||
*
|
|
||||||
* @param FormBuilderInterface $builder The builder to configure.
|
* @param FormBuilderInterface $builder The builder to configure.
|
||||||
* @param array $options The options used for the configuration.
|
* @param array $options The options used for the configuration.
|
||||||
*/
|
*/
|
||||||
@ -166,10 +148,7 @@ class ResolvedFormType implements ResolvedFormTypeInterface
|
|||||||
/**
|
/**
|
||||||
* Configures a form view for the type hierarchy.
|
* Configures a form view for the type hierarchy.
|
||||||
*
|
*
|
||||||
* This method is protected in order to allow implementing classes
|
* This method is called before the children of the view are built.
|
||||||
* to change or call it in re-implementations of {@link createView()}.
|
|
||||||
*
|
|
||||||
* It is called before the children of the view are built.
|
|
||||||
*
|
*
|
||||||
* @param FormView $view The form view to configure.
|
* @param FormView $view The form view to configure.
|
||||||
* @param FormInterface $form The form corresponding to the view.
|
* @param FormInterface $form The form corresponding to the view.
|
||||||
@ -192,10 +171,7 @@ class ResolvedFormType implements ResolvedFormTypeInterface
|
|||||||
/**
|
/**
|
||||||
* Finishes a form view for the type hierarchy.
|
* Finishes a form view for the type hierarchy.
|
||||||
*
|
*
|
||||||
* This method is protected in order to allow implementing classes
|
* This method is called after the children of the view have been built.
|
||||||
* to change or call it in re-implementations of {@link createView()}.
|
|
||||||
*
|
|
||||||
* It is called after the children of the view have been built.
|
|
||||||
*
|
*
|
||||||
* @param FormView $view The form view to configure.
|
* @param FormView $view The form view to configure.
|
||||||
* @param FormInterface $form The form corresponding to the view.
|
* @param FormInterface $form The form corresponding to the view.
|
||||||
@ -218,9 +194,6 @@ class ResolvedFormType implements ResolvedFormTypeInterface
|
|||||||
/**
|
/**
|
||||||
* Returns the configured options resolver used for this type.
|
* Returns the configured options resolver used for this type.
|
||||||
*
|
*
|
||||||
* This method is protected in order to allow implementing classes
|
|
||||||
* to change or call it in re-implementations of {@link createBuilder()}.
|
|
||||||
*
|
|
||||||
* @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
|
* @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
|
||||||
*/
|
*/
|
||||||
public function getOptionsResolver()
|
public function getOptionsResolver()
|
||||||
|
@ -60,9 +60,9 @@ abstract class AbstractFormTest extends \PHPUnit_Framework_TestCase
|
|||||||
*
|
*
|
||||||
* @return FormBuilder
|
* @return FormBuilder
|
||||||
*/
|
*/
|
||||||
protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null)
|
protected function getBuilder($name = 'name', EventDispatcherInterface $dispatcher = null, $dataClass = null, array $options = array())
|
||||||
{
|
{
|
||||||
return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory);
|
return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +15,7 @@ use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
|
|||||||
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
|
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
|
||||||
use Symfony\Component\Form\FormError;
|
use Symfony\Component\Form\FormError;
|
||||||
use Symfony\Component\Form\Forms;
|
use Symfony\Component\Form\Forms;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||||
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
|
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
|
||||||
@ -806,6 +807,65 @@ class CompoundFormTest extends AbstractFormTest
|
|||||||
$this->assertEquals("name:\n ERROR: Error!\nfoo:\n No errors\n", $parent->getErrorsAsString());
|
$this->assertEquals("name:\n ERROR: Error!\nfoo:\n No errors\n", $parent->getErrorsAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Basic cases are covered in SimpleFormTest
|
||||||
|
public function testCreateViewWithChildren()
|
||||||
|
{
|
||||||
|
$type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
|
||||||
|
$options = array('a' => 'Foo', 'b' => 'Bar');
|
||||||
|
$field1 = $this->getMockForm('foo');
|
||||||
|
$field2 = $this->getMockForm('bar');
|
||||||
|
$view = new FormView();
|
||||||
|
$field1View = new FormView();
|
||||||
|
$field2View = new FormView();
|
||||||
|
|
||||||
|
$this->form = $this->getBuilder('form', null, null, $options)
|
||||||
|
->setCompound(true)
|
||||||
|
->setDataMapper($this->getDataMapper())
|
||||||
|
->setType($type)
|
||||||
|
->getForm();
|
||||||
|
$this->form->add($field1);
|
||||||
|
$this->form->add($field2);
|
||||||
|
|
||||||
|
$test = $this;
|
||||||
|
|
||||||
|
$assertChildViewsEqual = function (array $childViews) use ($test) {
|
||||||
|
return function (FormView $view) use ($test, $childViews) {
|
||||||
|
/* @var \PHPUnit_Framework_TestCase $test */
|
||||||
|
$test->assertSame($childViews, $view->children);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// First create the view
|
||||||
|
$type->expects($this->once())
|
||||||
|
->method('createView')
|
||||||
|
->will($this->returnValue($view));
|
||||||
|
|
||||||
|
// Then build it for the form itself
|
||||||
|
$type->expects($this->once())
|
||||||
|
->method('buildView')
|
||||||
|
->with($view, $this->form, $options)
|
||||||
|
->will($this->returnCallback($assertChildViewsEqual(array())));
|
||||||
|
|
||||||
|
// Then add the first child form
|
||||||
|
$field1->expects($this->once())
|
||||||
|
->method('createView')
|
||||||
|
->will($this->returnValue($field1View));
|
||||||
|
|
||||||
|
// Then the second child form
|
||||||
|
$field2->expects($this->once())
|
||||||
|
->method('createView')
|
||||||
|
->will($this->returnValue($field2View));
|
||||||
|
|
||||||
|
// Again build the view for the form itself. This time the child views
|
||||||
|
// exist.
|
||||||
|
$type->expects($this->once())
|
||||||
|
->method('finishView')
|
||||||
|
->with($view, $this->form, $options)
|
||||||
|
->will($this->returnCallback($assertChildViewsEqual(array('foo' => $field1View, 'bar' => $field2View))));
|
||||||
|
|
||||||
|
$this->assertSame($view, $this->form->createView());
|
||||||
|
}
|
||||||
|
|
||||||
protected function createForm()
|
protected function createForm()
|
||||||
{
|
{
|
||||||
return $this->getBuilder()
|
return $this->getBuilder()
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\DataCollectorExtension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers Symfony\Component\Form\Extension\DataCollector\DataCollectorExtension
|
||||||
|
*/
|
||||||
|
class DataCollectorExtensionTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var DataCollectorExtension
|
||||||
|
*/
|
||||||
|
private $extension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->dataCollector = $this->getMock('Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface');
|
||||||
|
$this->extension = new DataCollectorExtension($this->dataCollector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLoadTypeExtensions()
|
||||||
|
{
|
||||||
|
$typeExtensions = $this->extension->getTypeExtensions('form');
|
||||||
|
|
||||||
|
$this->assertInternalType('array', $typeExtensions);
|
||||||
|
$this->assertCount(1, $typeExtensions);
|
||||||
|
$this->assertInstanceOf('Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension', array_shift($typeExtensions));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,465 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
|
||||||
|
use Symfony\Component\Form\Form;
|
||||||
|
use Symfony\Component\Form\FormBuilder;
|
||||||
|
use Symfony\Component\Form\FormEvent;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
|
||||||
|
class FormDataCollectorTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $dataExtractor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FormDataCollector
|
||||||
|
*/
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $dispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $dataMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Form
|
||||||
|
*/
|
||||||
|
private $form;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Form
|
||||||
|
*/
|
||||||
|
private $childForm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FormView
|
||||||
|
*/
|
||||||
|
private $view;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FormView
|
||||||
|
*/
|
||||||
|
private $childView;
|
||||||
|
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->dataExtractor = $this->getMock('Symfony\Component\Form\Extension\DataCollector\FormDataExtractorInterface');
|
||||||
|
$this->dataCollector = new FormDataCollector($this->dataExtractor);
|
||||||
|
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||||
|
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
|
||||||
|
$this->dataMapper = $this->getMock('Symfony\Component\Form\DataMapperInterface');
|
||||||
|
$this->form = $this->createForm('name');
|
||||||
|
$this->childForm = $this->createForm('child');
|
||||||
|
$this->view = new FormView();
|
||||||
|
$this->childView = new FormView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildPreliminaryFormTree()
|
||||||
|
{
|
||||||
|
$this->form->add($this->childForm);
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(0))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('config' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(1))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('config' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(2))
|
||||||
|
->method('extractDefaultData')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('default_data' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(3))
|
||||||
|
->method('extractDefaultData')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('default_data' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(4))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('submitted_data' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(5))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('submitted_data' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataCollector->collectConfiguration($this->form);
|
||||||
|
$this->dataCollector->collectDefaultData($this->form);
|
||||||
|
$this->dataCollector->collectSubmittedData($this->form);
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($this->form);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'config' => 'foo',
|
||||||
|
'default_data' => 'foo',
|
||||||
|
'submitted_data' => 'foo',
|
||||||
|
'children' => array(
|
||||||
|
'child' => array(
|
||||||
|
'config' => 'bar',
|
||||||
|
'default_data' => 'bar',
|
||||||
|
'submitted_data' => 'bar',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildMultiplePreliminaryFormTrees()
|
||||||
|
{
|
||||||
|
$form1 = $this->createForm('form1');
|
||||||
|
$form2 = $this->createForm('form2');
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(0))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($form1)
|
||||||
|
->will($this->returnValue(array('config' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(1))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($form2)
|
||||||
|
->will($this->returnValue(array('config' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataCollector->collectConfiguration($form1);
|
||||||
|
$this->dataCollector->collectConfiguration($form2);
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($form1);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'form1' => array(
|
||||||
|
'config' => 'foo',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($form2);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'form1' => array(
|
||||||
|
'config' => 'foo',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
'form2' => array(
|
||||||
|
'config' => 'bar',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildSamePreliminaryFormTreeMultipleTimes()
|
||||||
|
{
|
||||||
|
$this->dataExtractor->expects($this->at(0))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('config' => 'foo')));
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(1))
|
||||||
|
->method('extractDefaultData')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('default_data' => 'foo')));
|
||||||
|
|
||||||
|
$this->dataCollector->collectConfiguration($this->form);
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($this->form);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'config' => 'foo',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
|
||||||
|
$this->dataCollector->collectDefaultData($this->form);
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($this->form);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'config' => 'foo',
|
||||||
|
'default_data' => 'foo',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildPreliminaryFormTreeWithoutCollectingAnyData()
|
||||||
|
{
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($this->form);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildFinalFormTree()
|
||||||
|
{
|
||||||
|
$this->form->add($this->childForm);
|
||||||
|
$this->view->children['child'] = $this->childView;
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(0))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('config' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(1))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('config' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(2))
|
||||||
|
->method('extractDefaultData')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('default_data' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(3))
|
||||||
|
->method('extractDefaultData')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('default_data' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(4))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('submitted_data' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(5))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('submitted_data' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(6))
|
||||||
|
->method('extractViewVariables')
|
||||||
|
->with($this->view)
|
||||||
|
->will($this->returnValue(array('view_vars' => 'foo')));
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(7))
|
||||||
|
->method('extractViewVariables')
|
||||||
|
->with($this->childView)
|
||||||
|
->will($this->returnValue(array('view_vars' => 'bar')));
|
||||||
|
|
||||||
|
$this->dataCollector->collectConfiguration($this->form);
|
||||||
|
$this->dataCollector->collectDefaultData($this->form);
|
||||||
|
$this->dataCollector->collectSubmittedData($this->form);
|
||||||
|
$this->dataCollector->collectViewVariables($this->view);
|
||||||
|
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'view_vars' => 'foo',
|
||||||
|
'config' => 'foo',
|
||||||
|
'default_data' => 'foo',
|
||||||
|
'submitted_data' => 'foo',
|
||||||
|
'children' => array(
|
||||||
|
'child' => array(
|
||||||
|
'view_vars' => 'bar',
|
||||||
|
'config' => 'bar',
|
||||||
|
'default_data' => 'bar',
|
||||||
|
'submitted_data' => 'bar',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFinalFormReliesOnFormViewStructure()
|
||||||
|
{
|
||||||
|
$this->form->add($this->createForm('first'));
|
||||||
|
$this->form->add($this->createForm('second'));
|
||||||
|
|
||||||
|
$this->view->children['second'] = $this->childView;
|
||||||
|
|
||||||
|
$this->dataCollector->buildPreliminaryFormTree($this->form);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'children' => array(
|
||||||
|
'first' => array(
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
'second' => array(
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
|
||||||
|
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'children' => array(
|
||||||
|
// "first" not present in FormView
|
||||||
|
'second' => array(
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testChildViewsCanBeWithoutCorrespondingChildForms()
|
||||||
|
{
|
||||||
|
// don't add $this->childForm to $this->form!
|
||||||
|
|
||||||
|
$this->view->children['child'] = $this->childView;
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(0))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('config' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(1))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('config' => 'bar')));
|
||||||
|
|
||||||
|
// explicitly call collectConfiguration(), since $this->childForm is not
|
||||||
|
// contained in the form tree
|
||||||
|
$this->dataCollector->collectConfiguration($this->form);
|
||||||
|
$this->dataCollector->collectConfiguration($this->childForm);
|
||||||
|
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'config' => 'foo',
|
||||||
|
'children' => array(
|
||||||
|
'child' => array(
|
||||||
|
// no "config" key
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testChildViewsWithoutCorrespondingChildFormsMayBeExplicitlyAssociated()
|
||||||
|
{
|
||||||
|
// don't add $this->childForm to $this->form!
|
||||||
|
|
||||||
|
$this->view->children['child'] = $this->childView;
|
||||||
|
|
||||||
|
// but associate the two
|
||||||
|
$this->dataCollector->associateFormWithView($this->childForm, $this->childView);
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(0))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->form)
|
||||||
|
->will($this->returnValue(array('config' => 'foo')));
|
||||||
|
$this->dataExtractor->expects($this->at(1))
|
||||||
|
->method('extractConfiguration')
|
||||||
|
->with($this->childForm)
|
||||||
|
->will($this->returnValue(array('config' => 'bar')));
|
||||||
|
|
||||||
|
// explicitly call collectConfiguration(), since $this->childForm is not
|
||||||
|
// contained in the form tree
|
||||||
|
$this->dataCollector->collectConfiguration($this->form);
|
||||||
|
$this->dataCollector->collectConfiguration($this->childForm);
|
||||||
|
$this->dataCollector->buildFinalFormTree($this->form, $this->view);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'forms' => array(
|
||||||
|
'name' => array(
|
||||||
|
'config' => 'foo',
|
||||||
|
'children' => array(
|
||||||
|
'child' => array(
|
||||||
|
'config' => 'bar',
|
||||||
|
'children' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'nb_errors' => 0,
|
||||||
|
), $this->dataCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCollectSubmittedDataCountsErrors()
|
||||||
|
{
|
||||||
|
$form1 = $this->createForm('form1');
|
||||||
|
$childForm1 = $this->createForm('child1');
|
||||||
|
$form2 = $this->createForm('form2');
|
||||||
|
|
||||||
|
$form1->add($childForm1);
|
||||||
|
|
||||||
|
$this->dataExtractor->expects($this->at(0))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->with($form1)
|
||||||
|
->will($this->returnValue(array('errors' => array('foo'))));
|
||||||
|
$this->dataExtractor->expects($this->at(1))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->with($childForm1)
|
||||||
|
->will($this->returnValue(array('errors' => array('bar', 'bam'))));
|
||||||
|
$this->dataExtractor->expects($this->at(2))
|
||||||
|
->method('extractSubmittedData')
|
||||||
|
->with($form2)
|
||||||
|
->will($this->returnValue(array('errors' => array('baz'))));
|
||||||
|
|
||||||
|
$this->dataCollector->collectSubmittedData($form1);
|
||||||
|
|
||||||
|
$data = $this->dataCollector->getData();
|
||||||
|
$this->assertSame(3, $data['nb_errors']);
|
||||||
|
|
||||||
|
$this->dataCollector->collectSubmittedData($form2);
|
||||||
|
|
||||||
|
$data = $this->dataCollector->getData();
|
||||||
|
$this->assertSame(4, $data['nb_errors']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createForm($name)
|
||||||
|
{
|
||||||
|
$builder = new FormBuilder($name, null, $this->dispatcher, $this->factory);
|
||||||
|
$builder->setCompound(true);
|
||||||
|
$builder->setDataMapper($this->dataMapper);
|
||||||
|
|
||||||
|
return $builder->getForm();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,338 @@
|
|||||||
|
<?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\Extension\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\CallbackTransformer;
|
||||||
|
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor;
|
||||||
|
use Symfony\Component\Form\FormBuilder;
|
||||||
|
use Symfony\Component\Form\FormError;
|
||||||
|
use Symfony\Component\Form\FormView;
|
||||||
|
use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer;
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
|
||||||
|
|
||||||
|
class FormDataExtractorTest_SimpleValueExporter extends ValueExporter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function exportValue($value)
|
||||||
|
{
|
||||||
|
return var_export($value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class FormDataExtractorTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var FormDataExtractorTest_SimpleValueExporter
|
||||||
|
*/
|
||||||
|
private $valueExporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FormDataExtractor
|
||||||
|
*/
|
||||||
|
private $dataExtractor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $dispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $factory;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->valueExporter = new FormDataExtractorTest_SimpleValueExporter();
|
||||||
|
$this->dataExtractor = new FormDataExtractor($this->valueExporter);
|
||||||
|
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||||
|
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractConfiguration()
|
||||||
|
{
|
||||||
|
$type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
|
||||||
|
$type->expects($this->any())
|
||||||
|
->method('getName')
|
||||||
|
->will($this->returnValue('type_name'));
|
||||||
|
$type->expects($this->any())
|
||||||
|
->method('getInnerType')
|
||||||
|
->will($this->returnValue(new \stdClass()));
|
||||||
|
|
||||||
|
$form = $this->createBuilder('name')
|
||||||
|
->setType($type)
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'type' => 'type_name',
|
||||||
|
'type_class' => 'stdClass',
|
||||||
|
'synchronized' => 'true',
|
||||||
|
'passed_options' => array(),
|
||||||
|
'resolved_options' => array(),
|
||||||
|
), $this->dataExtractor->extractConfiguration($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractConfigurationSortsPassedOptions()
|
||||||
|
{
|
||||||
|
$type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
|
||||||
|
$type->expects($this->any())
|
||||||
|
->method('getName')
|
||||||
|
->will($this->returnValue('type_name'));
|
||||||
|
$type->expects($this->any())
|
||||||
|
->method('getInnerType')
|
||||||
|
->will($this->returnValue(new \stdClass()));
|
||||||
|
|
||||||
|
$options = array(
|
||||||
|
'b' => 'foo',
|
||||||
|
'a' => 'bar',
|
||||||
|
'c' => 'baz',
|
||||||
|
);
|
||||||
|
|
||||||
|
$form = $this->createBuilder('name')
|
||||||
|
->setType($type)
|
||||||
|
// passed options are stored in an attribute by
|
||||||
|
// ResolvedTypeDataCollectorProxy
|
||||||
|
->setAttribute('data_collector/passed_options', $options)
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'type' => 'type_name',
|
||||||
|
'type_class' => 'stdClass',
|
||||||
|
'synchronized' => 'true',
|
||||||
|
'passed_options' => array(
|
||||||
|
'a' => "'bar'",
|
||||||
|
'b' => "'foo'",
|
||||||
|
'c' => "'baz'",
|
||||||
|
),
|
||||||
|
'resolved_options' => array(),
|
||||||
|
), $this->dataExtractor->extractConfiguration($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractConfigurationSortsResolvedOptions()
|
||||||
|
{
|
||||||
|
$type = $this->getMock('Symfony\Component\Form\ResolvedFormTypeInterface');
|
||||||
|
$type->expects($this->any())
|
||||||
|
->method('getName')
|
||||||
|
->will($this->returnValue('type_name'));
|
||||||
|
$type->expects($this->any())
|
||||||
|
->method('getInnerType')
|
||||||
|
->will($this->returnValue(new \stdClass()));
|
||||||
|
|
||||||
|
$options = array(
|
||||||
|
'b' => 'foo',
|
||||||
|
'a' => 'bar',
|
||||||
|
'c' => 'baz',
|
||||||
|
);
|
||||||
|
|
||||||
|
$form = $this->createBuilder('name', $options)
|
||||||
|
->setType($type)
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'type' => 'type_name',
|
||||||
|
'type_class' => 'stdClass',
|
||||||
|
'synchronized' => 'true',
|
||||||
|
'passed_options' => array(),
|
||||||
|
'resolved_options' => array(
|
||||||
|
'a' => "'bar'",
|
||||||
|
'b' => "'foo'",
|
||||||
|
'c' => "'baz'",
|
||||||
|
),
|
||||||
|
), $this->dataExtractor->extractConfiguration($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractDefaultData()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')->getForm();
|
||||||
|
|
||||||
|
$form->setData('Foobar');
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'default_data' => array(
|
||||||
|
'norm' => "'Foobar'",
|
||||||
|
),
|
||||||
|
'submitted_data' => array(),
|
||||||
|
), $this->dataExtractor->extractDefaultData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractDefaultDataStoresModelDataIfDifferent()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')
|
||||||
|
->addModelTransformer(new FixedDataTransformer(array(
|
||||||
|
'Foo' => 'Bar'
|
||||||
|
)))
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$form->setData('Foo');
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'default_data' => array(
|
||||||
|
'norm' => "'Bar'",
|
||||||
|
'model' => "'Foo'",
|
||||||
|
),
|
||||||
|
'submitted_data' => array(),
|
||||||
|
), $this->dataExtractor->extractDefaultData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractDefaultDataStoresViewDataIfDifferent()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')
|
||||||
|
->addViewTransformer(new FixedDataTransformer(array(
|
||||||
|
'Foo' => 'Bar'
|
||||||
|
)))
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$form->setData('Foo');
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'default_data' => array(
|
||||||
|
'norm' => "'Foo'",
|
||||||
|
'view' => "'Bar'",
|
||||||
|
),
|
||||||
|
'submitted_data' => array(),
|
||||||
|
), $this->dataExtractor->extractDefaultData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractSubmittedData()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')->getForm();
|
||||||
|
|
||||||
|
$form->submit('Foobar');
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'submitted_data' => array(
|
||||||
|
'norm' => "'Foobar'",
|
||||||
|
),
|
||||||
|
'errors' => array(),
|
||||||
|
'synchronized' => 'true',
|
||||||
|
), $this->dataExtractor->extractSubmittedData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractSubmittedDataStoresModelDataIfDifferent()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')
|
||||||
|
->addModelTransformer(new FixedDataTransformer(array(
|
||||||
|
'Foo' => 'Bar',
|
||||||
|
'' => '',
|
||||||
|
)))
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$form->submit('Bar');
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'submitted_data' => array(
|
||||||
|
'norm' => "'Bar'",
|
||||||
|
'model' => "'Foo'",
|
||||||
|
),
|
||||||
|
'errors' => array(),
|
||||||
|
'synchronized' => 'true',
|
||||||
|
), $this->dataExtractor->extractSubmittedData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractSubmittedDataStoresViewDataIfDifferent()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')
|
||||||
|
->addViewTransformer(new FixedDataTransformer(array(
|
||||||
|
'Foo' => 'Bar',
|
||||||
|
'' => '',
|
||||||
|
)))
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$form->submit('Bar');
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'submitted_data' => array(
|
||||||
|
'norm' => "'Foo'",
|
||||||
|
'view' => "'Bar'",
|
||||||
|
),
|
||||||
|
'errors' => array(),
|
||||||
|
'synchronized' => 'true',
|
||||||
|
), $this->dataExtractor->extractSubmittedData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractSubmittedDataStoresErrors()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')->getForm();
|
||||||
|
|
||||||
|
$form->submit('Foobar');
|
||||||
|
$form->addError(new FormError('Invalid!'));
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'submitted_data' => array(
|
||||||
|
'norm' => "'Foobar'",
|
||||||
|
),
|
||||||
|
'errors' => array(
|
||||||
|
array('message' => 'Invalid!'),
|
||||||
|
),
|
||||||
|
'synchronized' => 'true',
|
||||||
|
), $this->dataExtractor->extractSubmittedData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractSubmittedDataRemembersIfNonSynchronized()
|
||||||
|
{
|
||||||
|
$form = $this->createBuilder('name')
|
||||||
|
->addModelTransformer(new CallbackTransformer(
|
||||||
|
function () {},
|
||||||
|
function () {
|
||||||
|
throw new TransformationFailedException('Fail!');
|
||||||
|
}
|
||||||
|
))
|
||||||
|
->getForm();
|
||||||
|
|
||||||
|
$form->submit('Foobar');
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'submitted_data' => array(
|
||||||
|
'norm' => "'Foobar'",
|
||||||
|
'model' => 'NULL',
|
||||||
|
),
|
||||||
|
'errors' => array(),
|
||||||
|
'synchronized' => 'false',
|
||||||
|
), $this->dataExtractor->extractSubmittedData($form));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExtractViewVariables()
|
||||||
|
{
|
||||||
|
$view = new FormView();
|
||||||
|
|
||||||
|
$view->vars = array(
|
||||||
|
'b' => 'foo',
|
||||||
|
'a' => 'bar',
|
||||||
|
'c' => 'baz',
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertSame(array(
|
||||||
|
'view_vars' => array(
|
||||||
|
'a' => "'bar'",
|
||||||
|
'b' => "'foo'",
|
||||||
|
'c' => "'baz'",
|
||||||
|
),
|
||||||
|
), $this->dataExtractor->extractViewVariables($view));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return FormBuilder
|
||||||
|
*/
|
||||||
|
private function createBuilder($name, array $options = array())
|
||||||
|
{
|
||||||
|
return new FormBuilder($name, null, $this->dispatcher, $this->factory, $options);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
<?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\Extension\DataCollector\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension;
|
||||||
|
|
||||||
|
class DataCollectorTypeExtensionTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var DataCollectorTypeExtension
|
||||||
|
*/
|
||||||
|
private $extension;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $dataCollector;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->dataCollector = $this->getMock('Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface');
|
||||||
|
$this->extension = new DataCollectorTypeExtension($this->dataCollector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetExtendedType()
|
||||||
|
{
|
||||||
|
$this->assertEquals('form', $this->extension->getExtendedType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildForm()
|
||||||
|
{
|
||||||
|
$builder = $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface');
|
||||||
|
$builder->expects($this->atLeastOnce())
|
||||||
|
->method('addEventSubscriber')
|
||||||
|
->with($this->isInstanceOf('Symfony\Component\Form\Extension\DataCollector\EventListener\DataCollectorListener'));
|
||||||
|
|
||||||
|
$this->extension->buildForm($builder, array());
|
||||||
|
}
|
||||||
|
}
|
@ -46,6 +46,11 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
private $resolvedTypeFactory;
|
private $resolvedTypeFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var FormFactory
|
* @var FormFactory
|
||||||
*/
|
*/
|
||||||
@ -57,6 +62,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
|
$this->guesser1 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
|
||||||
$this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
|
$this->guesser2 = $this->getMock('Symfony\Component\Form\FormTypeGuesserInterface');
|
||||||
$this->registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface');
|
$this->registry = $this->getMock('Symfony\Component\Form\FormRegistryInterface');
|
||||||
|
$this->builder = $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface');
|
||||||
$this->factory = new FormFactory($this->registry, $this->resolvedTypeFactory);
|
$this->factory = new FormFactory($this->registry, $this->resolvedTypeFactory);
|
||||||
|
|
||||||
$this->registry->expects($this->any())
|
$this->registry->expects($this->any())
|
||||||
@ -70,6 +76,7 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testCreateNamedBuilderWithTypeName()
|
public function testCreateNamedBuilderWithTypeName()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
$this->registry->expects($this->once())
|
$this->registry->expects($this->once())
|
||||||
@ -80,14 +87,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $options)
|
->with($this->factory, 'name', $options)
|
||||||
->will($this->returnValue('BUILDER'));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', null, $options));
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', null, $options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateNamedBuilderWithTypeInstance()
|
public function testCreateNamedBuilderWithTypeInstance()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$type = new FooType();
|
$type = new FooType();
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
@ -99,14 +115,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $options)
|
->with($this->factory, 'name', $options)
|
||||||
->will($this->returnValue('BUILDER'));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $type, null, $options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateNamedBuilderWithTypeInstanceWithParentType()
|
public function testCreateNamedBuilderWithTypeInstanceWithParentType()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$type = new FooSubType();
|
$type = new FooSubType();
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
$parentResolvedType = $this->getMockResolvedType();
|
$parentResolvedType = $this->getMockResolvedType();
|
||||||
@ -124,14 +149,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $options)
|
->with($this->factory, 'name', $options)
|
||||||
->will($this->returnValue('BUILDER'));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $type, null, $options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateNamedBuilderWithTypeInstanceWithParentTypeInstance()
|
public function testCreateNamedBuilderWithTypeInstanceWithParentTypeInstance()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$type = new FooSubTypeWithParentInstance();
|
$type = new FooSubTypeWithParentInstance();
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
$parentResolvedType = $this->getMockResolvedType();
|
$parentResolvedType = $this->getMockResolvedType();
|
||||||
@ -149,28 +183,46 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $options)
|
->with($this->factory, 'name', $options)
|
||||||
->will($this->returnValue('BUILDER'));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $type, null, $options));
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $type, null, $options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateNamedBuilderWithResolvedTypeInstance()
|
public function testCreateNamedBuilderWithResolvedTypeInstance()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $options)
|
->with($this->factory, 'name', $options)
|
||||||
->will($this->returnValue('BUILDER'));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', $resolvedType, null, $options));
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->builder, $this->factory->createNamedBuilder('name', $resolvedType, null, $options));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateNamedBuilderFillsDataOption()
|
public function testCreateNamedBuilderFillsDataOption()
|
||||||
{
|
{
|
||||||
$givenOptions = array('a' => '1', 'b' => '2');
|
$givenOptions = array('a' => '1', 'b' => '2');
|
||||||
$expectedOptions = array_merge($givenOptions, array('data' => 'DATA'));
|
$expectedOptions = array_merge($givenOptions, array('data' => 'DATA'));
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3', 'data' => 'DATA');
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
$this->registry->expects($this->once())
|
$this->registry->expects($this->once())
|
||||||
@ -181,14 +233,23 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $expectedOptions)
|
->with($this->factory, 'name', $expectedOptions)
|
||||||
->will($this->returnValue('BUILDER'));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $givenOptions));
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', 'DATA', $givenOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateNamedBuilderDoesNotOverrideExistingDataOption()
|
public function testCreateNamedBuilderDoesNotOverrideExistingDataOption()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2', 'data' => 'CUSTOM');
|
$options = array('a' => '1', 'b' => '2', 'data' => 'CUSTOM');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3', 'data' => 'CUSTOM');
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
|
|
||||||
$this->registry->expects($this->once())
|
$this->registry->expects($this->once())
|
||||||
@ -199,9 +260,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $options)
|
->with($this->factory, 'name', $options)
|
||||||
->will($this->returnValue('BUILDER'));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$this->assertSame('BUILDER', $this->factory->createNamedBuilder('name', 'type', 'DATA', $options));
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', 'DATA', $options));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,8 +285,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testCreateUsesTypeNameIfTypeGivenAsString()
|
public function testCreateUsesTypeNameIfTypeGivenAsString()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
$builder = $this->getMockFormBuilder();
|
|
||||||
|
|
||||||
$this->registry->expects($this->once())
|
$this->registry->expects($this->once())
|
||||||
->method('getType')
|
->method('getType')
|
||||||
@ -227,9 +296,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'TYPE', $options)
|
->with($this->factory, 'TYPE', $options)
|
||||||
->will($this->returnValue($builder));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$builder->expects($this->once())
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->builder->expects($this->once())
|
||||||
->method('getForm')
|
->method('getForm')
|
||||||
->will($this->returnValue('FORM'));
|
->will($this->returnValue('FORM'));
|
||||||
|
|
||||||
@ -239,8 +316,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testCreateUsesTypeNameIfTypeGivenAsObject()
|
public function testCreateUsesTypeNameIfTypeGivenAsObject()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
$builder = $this->getMockFormBuilder();
|
|
||||||
|
|
||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('getName')
|
->method('getName')
|
||||||
@ -249,9 +326,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'TYPE', $options)
|
->with($this->factory, 'TYPE', $options)
|
||||||
->will($this->returnValue($builder));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$builder->expects($this->once())
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->builder->expects($this->once())
|
||||||
->method('getForm')
|
->method('getForm')
|
||||||
->will($this->returnValue('FORM'));
|
->will($this->returnValue('FORM'));
|
||||||
|
|
||||||
@ -261,8 +346,8 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function testCreateNamed()
|
public function testCreateNamed()
|
||||||
{
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$resolvedOptions = array('a' => '2', 'b' => '3');
|
||||||
$resolvedType = $this->getMockResolvedType();
|
$resolvedType = $this->getMockResolvedType();
|
||||||
$builder = $this->getMockFormBuilder();
|
|
||||||
|
|
||||||
$this->registry->expects($this->once())
|
$this->registry->expects($this->once())
|
||||||
->method('getType')
|
->method('getType')
|
||||||
@ -272,9 +357,17 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
$resolvedType->expects($this->once())
|
$resolvedType->expects($this->once())
|
||||||
->method('createBuilder')
|
->method('createBuilder')
|
||||||
->with($this->factory, 'name', $options)
|
->with($this->factory, 'name', $options)
|
||||||
->will($this->returnValue($builder));
|
->will($this->returnValue($this->builder));
|
||||||
|
|
||||||
$builder->expects($this->once())
|
$this->builder->expects($this->any())
|
||||||
|
->method('getOptions')
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$resolvedType->expects($this->once())
|
||||||
|
->method('buildForm')
|
||||||
|
->with($this->builder, $resolvedOptions);
|
||||||
|
|
||||||
|
$this->builder->expects($this->once())
|
||||||
->method('getForm')
|
->method('getForm')
|
||||||
->will($this->returnValue('FORM'));
|
->will($this->returnValue('FORM'));
|
||||||
|
|
||||||
@ -294,9 +387,9 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->with('firstName', 'text', null, array())
|
->with('firstName', 'text', null, array())
|
||||||
->will($this->returnValue('builderInstance'));
|
->will($this->returnValue('builderInstance'));
|
||||||
|
|
||||||
$builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
|
$this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
|
||||||
|
|
||||||
$this->assertEquals('builderInstance', $builder);
|
$this->assertEquals('builderInstance', $this->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence()
|
public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence()
|
||||||
@ -326,9 +419,9 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->with('firstName', 'password', null, array('max_length' => 7))
|
->with('firstName', 'password', null, array('max_length' => 7))
|
||||||
->will($this->returnValue('builderInstance'));
|
->will($this->returnValue('builderInstance'));
|
||||||
|
|
||||||
$builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
|
$this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
|
||||||
|
|
||||||
$this->assertEquals('builderInstance', $builder);
|
$this->assertEquals('builderInstance', $this->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateBuilderCreatesTextFormIfNoGuess()
|
public function testCreateBuilderCreatesTextFormIfNoGuess()
|
||||||
@ -345,9 +438,9 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->with('firstName', 'text')
|
->with('firstName', 'text')
|
||||||
->will($this->returnValue('builderInstance'));
|
->will($this->returnValue('builderInstance'));
|
||||||
|
|
||||||
$builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
|
$this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName');
|
||||||
|
|
||||||
$this->assertEquals('builderInstance', $builder);
|
$this->assertEquals('builderInstance', $this->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testOptionsCanBeOverridden()
|
public function testOptionsCanBeOverridden()
|
||||||
@ -368,14 +461,14 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->with('firstName', 'text', null, array('max_length' => 11))
|
->with('firstName', 'text', null, array('max_length' => 11))
|
||||||
->will($this->returnValue('builderInstance'));
|
->will($this->returnValue('builderInstance'));
|
||||||
|
|
||||||
$builder = $factory->createBuilderForProperty(
|
$this->builder = $factory->createBuilderForProperty(
|
||||||
'Application\Author',
|
'Application\Author',
|
||||||
'firstName',
|
'firstName',
|
||||||
null,
|
null,
|
||||||
array('max_length' => 11)
|
array('max_length' => 11)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals('builderInstance', $builder);
|
$this->assertEquals('builderInstance', $this->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateBuilderUsesMaxLengthIfFound()
|
public function testCreateBuilderUsesMaxLengthIfFound()
|
||||||
@ -403,12 +496,12 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->with('firstName', 'text', null, array('max_length' => 20))
|
->with('firstName', 'text', null, array('max_length' => 20))
|
||||||
->will($this->returnValue('builderInstance'));
|
->will($this->returnValue('builderInstance'));
|
||||||
|
|
||||||
$builder = $factory->createBuilderForProperty(
|
$this->builder = $factory->createBuilderForProperty(
|
||||||
'Application\Author',
|
'Application\Author',
|
||||||
'firstName'
|
'firstName'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals('builderInstance', $builder);
|
$this->assertEquals('builderInstance', $this->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateBuilderUsesRequiredSettingWithHighestConfidence()
|
public function testCreateBuilderUsesRequiredSettingWithHighestConfidence()
|
||||||
@ -436,12 +529,12 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->with('firstName', 'text', null, array('required' => false))
|
->with('firstName', 'text', null, array('required' => false))
|
||||||
->will($this->returnValue('builderInstance'));
|
->will($this->returnValue('builderInstance'));
|
||||||
|
|
||||||
$builder = $factory->createBuilderForProperty(
|
$this->builder = $factory->createBuilderForProperty(
|
||||||
'Application\Author',
|
'Application\Author',
|
||||||
'firstName'
|
'firstName'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals('builderInstance', $builder);
|
$this->assertEquals('builderInstance', $this->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateBuilderUsesPatternIfFound()
|
public function testCreateBuilderUsesPatternIfFound()
|
||||||
@ -469,12 +562,12 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
->with('firstName', 'text', null, array('pattern' => '[a-zA-Z]'))
|
->with('firstName', 'text', null, array('pattern' => '[a-zA-Z]'))
|
||||||
->will($this->returnValue('builderInstance'));
|
->will($this->returnValue('builderInstance'));
|
||||||
|
|
||||||
$builder = $factory->createBuilderForProperty(
|
$this->builder = $factory->createBuilderForProperty(
|
||||||
'Application\Author',
|
'Application\Author',
|
||||||
'firstName'
|
'firstName'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals('builderInstance', $builder);
|
$this->assertEquals('builderInstance', $this->builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMockFactory(array $methods = array())
|
private function getMockFactory(array $methods = array())
|
||||||
@ -494,9 +587,4 @@ class FormFactoryTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
return $this->getMock('Symfony\Component\Form\FormTypeInterface');
|
return $this->getMock('Symfony\Component\Form\FormTypeInterface');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMockFormBuilder()
|
|
||||||
{
|
|
||||||
return $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,71 @@ class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||||
*/
|
*/
|
||||||
private $dataMapper;
|
private $dataMapper;
|
||||||
|
private $parentType;
|
||||||
|
private $type;
|
||||||
|
private $extension1;
|
||||||
|
private $extension2;
|
||||||
|
private $parentResolvedType;
|
||||||
|
private $resolvedType;
|
||||||
|
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
|
||||||
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
|
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
|
||||||
$this->dataMapper = $this->getMock('Symfony\Component\Form\DataMapperInterface');
|
$this->dataMapper = $this->getMock('Symfony\Component\Form\DataMapperInterface');
|
||||||
|
$this->parentType = $this->getMockFormType();
|
||||||
|
$this->type = $this->getMockFormType();
|
||||||
|
$this->extension1 = $this->getMockFormTypeExtension();
|
||||||
|
$this->extension2 = $this->getMockFormTypeExtension();
|
||||||
|
$this->parentResolvedType = new ResolvedFormType($this->parentType);
|
||||||
|
$this->resolvedType = new ResolvedFormType($this->type, array($this->extension1, $this->extension2), $this->parentResolvedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetOptionsResolver()
|
||||||
|
{
|
||||||
|
if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) {
|
||||||
|
$this->markTestSkipped('This test requires PHPUnit 3.7.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$test = $this;
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
$assertIndexAndAddOption = function ($index, $option, $default) use (&$i, $test) {
|
||||||
|
return function (OptionsResolverInterface $resolver) use (&$i, $test, $index, $option, $default) {
|
||||||
|
/* @var \PHPUnit_Framework_TestCase $test */
|
||||||
|
$test->assertEquals($index, $i, 'Executed at index '.$index);
|
||||||
|
|
||||||
|
++$i;
|
||||||
|
|
||||||
|
$resolver->setDefaults(array($option => $default));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// First the default options are generated for the super type
|
||||||
|
$this->parentType->expects($this->once())
|
||||||
|
->method('setDefaultOptions')
|
||||||
|
->will($this->returnCallback($assertIndexAndAddOption(0, 'a', 'a_default')));
|
||||||
|
|
||||||
|
// The form type itself
|
||||||
|
$this->type->expects($this->once())
|
||||||
|
->method('setDefaultOptions')
|
||||||
|
->will($this->returnCallback($assertIndexAndAddOption(1, 'b', 'b_default')));
|
||||||
|
|
||||||
|
// And its extensions
|
||||||
|
$this->extension1->expects($this->once())
|
||||||
|
->method('setDefaultOptions')
|
||||||
|
->will($this->returnCallback($assertIndexAndAddOption(2, 'c', 'c_default')));
|
||||||
|
|
||||||
|
$this->extension2->expects($this->once())
|
||||||
|
->method('setDefaultOptions')
|
||||||
|
->will($this->returnCallback($assertIndexAndAddOption(3, 'd', 'd_default')));
|
||||||
|
|
||||||
|
$givenOptions = array('a' => 'a_custom', 'c' => 'c_custom');
|
||||||
|
$resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default');
|
||||||
|
|
||||||
|
$resolver = $this->resolvedType->getOptionsResolver();
|
||||||
|
|
||||||
|
$this->assertEquals($resolvedOptions, $resolver->resolve($givenOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateBuilder()
|
public function testCreateBuilder()
|
||||||
@ -50,13 +109,70 @@ class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->markTestSkipped('This test requires PHPUnit 3.7.');
|
$this->markTestSkipped('This test requires PHPUnit 3.7.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$parentType = $this->getMockFormType();
|
$givenOptions = array('a' => 'a_custom', 'c' => 'c_custom');
|
||||||
$type = $this->getMockFormType();
|
$resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default');
|
||||||
$extension1 = $this->getMockFormTypeExtension();
|
$optionsResolver = $this->getMock('Symfony\Component\OptionsResolver\OptionsResolverInterface');
|
||||||
$extension2 = $this->getMockFormTypeExtension();
|
|
||||||
|
|
||||||
$parentResolvedType = new ResolvedFormType($parentType);
|
$this->resolvedType = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormType')
|
||||||
$resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType);
|
->setConstructorArgs(array($this->type, array($this->extension1, $this->extension2), $this->parentResolvedType))
|
||||||
|
->setMethods(array('getOptionsResolver'))
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->resolvedType->expects($this->once())
|
||||||
|
->method('getOptionsResolver')
|
||||||
|
->will($this->returnValue($optionsResolver));
|
||||||
|
|
||||||
|
$optionsResolver->expects($this->once())
|
||||||
|
->method('resolve')
|
||||||
|
->with($givenOptions)
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$factory = $this->getMockFormFactory();
|
||||||
|
$builder = $this->resolvedType->createBuilder($factory, 'name', $givenOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->resolvedType, $builder->getType());
|
||||||
|
$this->assertSame($resolvedOptions, $builder->getOptions());
|
||||||
|
$this->assertNull($builder->getDataClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateBuilderWithDataClassOption()
|
||||||
|
{
|
||||||
|
if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) {
|
||||||
|
$this->markTestSkipped('This test requires PHPUnit 3.7.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$givenOptions = array('data_class' => 'Foo');
|
||||||
|
$resolvedOptions = array('data_class' => '\stdClass');
|
||||||
|
$optionsResolver = $this->getMock('Symfony\Component\OptionsResolver\OptionsResolverInterface');
|
||||||
|
|
||||||
|
$this->resolvedType = $this->getMockBuilder('Symfony\Component\Form\ResolvedFormType')
|
||||||
|
->setConstructorArgs(array($this->type, array($this->extension1, $this->extension2), $this->parentResolvedType))
|
||||||
|
->setMethods(array('getOptionsResolver'))
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->resolvedType->expects($this->once())
|
||||||
|
->method('getOptionsResolver')
|
||||||
|
->will($this->returnValue($optionsResolver));
|
||||||
|
|
||||||
|
$optionsResolver->expects($this->once())
|
||||||
|
->method('resolve')
|
||||||
|
->with($givenOptions)
|
||||||
|
->will($this->returnValue($resolvedOptions));
|
||||||
|
|
||||||
|
$factory = $this->getMockFormFactory();
|
||||||
|
$builder = $this->resolvedType->createBuilder($factory, 'name', $givenOptions);
|
||||||
|
|
||||||
|
$this->assertSame($this->resolvedType, $builder->getType());
|
||||||
|
$this->assertSame($resolvedOptions, $builder->getOptions());
|
||||||
|
$this->assertSame('\stdClass', $builder->getDataClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testBuildForm()
|
||||||
|
{
|
||||||
|
if (version_compare(\PHPUnit_Runner_Version::id(), '3.7', '<')) {
|
||||||
|
$this->markTestSkipped('This test requires PHPUnit 3.7.');
|
||||||
|
}
|
||||||
|
|
||||||
$test = $this;
|
$test = $this;
|
||||||
$i = 0;
|
$i = 0;
|
||||||
@ -70,169 +186,142 @@ class ResolvedFormTypeTest extends \PHPUnit_Framework_TestCase
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
$assertIndexAndAddOption = function ($index, $option, $default) use ($assertIndex) {
|
$options = array('a' => 'Foo', 'b' => 'Bar');
|
||||||
$assertIndex = $assertIndex($index);
|
$builder = $this->getMock('Symfony\Component\Form\Test\FormBuilderInterface');
|
||||||
|
|
||||||
return function (OptionsResolverInterface $resolver) use ($assertIndex, $index, $option, $default) {
|
// First the form is built for the super type
|
||||||
$assertIndex();
|
$this->parentType->expects($this->once())
|
||||||
|
|
||||||
$resolver->setDefaults(array($option => $default));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// First the default options are generated for the super type
|
|
||||||
$parentType->expects($this->once())
|
|
||||||
->method('setDefaultOptions')
|
|
||||||
->will($this->returnCallback($assertIndexAndAddOption(0, 'a', 'a_default')));
|
|
||||||
|
|
||||||
// The form type itself
|
|
||||||
$type->expects($this->once())
|
|
||||||
->method('setDefaultOptions')
|
|
||||||
->will($this->returnCallback($assertIndexAndAddOption(1, 'b', 'b_default')));
|
|
||||||
|
|
||||||
// And its extensions
|
|
||||||
$extension1->expects($this->once())
|
|
||||||
->method('setDefaultOptions')
|
|
||||||
->will($this->returnCallback($assertIndexAndAddOption(2, 'c', 'c_default')));
|
|
||||||
|
|
||||||
$extension2->expects($this->once())
|
|
||||||
->method('setDefaultOptions')
|
|
||||||
->will($this->returnCallback($assertIndexAndAddOption(3, 'd', 'd_default')));
|
|
||||||
|
|
||||||
$givenOptions = array('a' => 'a_custom', 'c' => 'c_custom');
|
|
||||||
$resolvedOptions = array('a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default');
|
|
||||||
|
|
||||||
// Then the form is built for the super type
|
|
||||||
$parentType->expects($this->once())
|
|
||||||
->method('buildForm')
|
->method('buildForm')
|
||||||
->with($this->anything(), $resolvedOptions)
|
->with($builder, $options)
|
||||||
->will($this->returnCallback($assertIndex(4)));
|
->will($this->returnCallback($assertIndex(0)));
|
||||||
|
|
||||||
// Then the type itself
|
// Then the type itself
|
||||||
$type->expects($this->once())
|
$this->type->expects($this->once())
|
||||||
->method('buildForm')
|
->method('buildForm')
|
||||||
->with($this->anything(), $resolvedOptions)
|
->with($builder, $options)
|
||||||
->will($this->returnCallback($assertIndex(5)));
|
->will($this->returnCallback($assertIndex(1)));
|
||||||
|
|
||||||
// Then its extensions
|
// Then its extensions
|
||||||
$extension1->expects($this->once())
|
$this->extension1->expects($this->once())
|
||||||
->method('buildForm')
|
->method('buildForm')
|
||||||
->with($this->anything(), $resolvedOptions)
|
->with($builder, $options)
|
||||||
->will($this->returnCallback($assertIndex(6)));
|
->will($this->returnCallback($assertIndex(2)));
|
||||||
|
|
||||||
$extension2->expects($this->once())
|
$this->extension2->expects($this->once())
|
||||||
->method('buildForm')
|
->method('buildForm')
|
||||||
->with($this->anything(), $resolvedOptions)
|
->with($builder, $options)
|
||||||
->will($this->returnCallback($assertIndex(7)));
|
->will($this->returnCallback($assertIndex(3)));
|
||||||
|
|
||||||
$factory = $this->getMockFormFactory();
|
$this->resolvedType->buildForm($builder, $options);
|
||||||
$builder = $resolvedType->createBuilder($factory, 'name', $givenOptions);
|
|
||||||
|
|
||||||
$this->assertSame($resolvedType, $builder->getType());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCreateView()
|
public function testCreateView()
|
||||||
{
|
{
|
||||||
$parentType = $this->getMockFormType();
|
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||||
$type = $this->getMockFormType();
|
|
||||||
$field1Type = $this->getMockFormType();
|
|
||||||
$field2Type = $this->getMockFormType();
|
|
||||||
$extension1 = $this->getMockFormTypeExtension();
|
|
||||||
$extension2 = $this->getMockFormTypeExtension();
|
|
||||||
|
|
||||||
$parentResolvedType = new ResolvedFormType($parentType);
|
$view = $this->resolvedType->createView($form);
|
||||||
$resolvedType = new ResolvedFormType($type, array($extension1, $extension2), $parentResolvedType);
|
|
||||||
$field1ResolvedType = new ResolvedFormType($field1Type);
|
|
||||||
$field2ResolvedType = new ResolvedFormType($field2Type);
|
|
||||||
|
|
||||||
|
$this->assertInstanceOf('Symfony\Component\Form\FormView', $view);
|
||||||
|
$this->assertNull($view->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCreateViewWithParent()
|
||||||
|
{
|
||||||
|
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||||
|
$parentView = $this->getMock('Symfony\Component\Form\FormView');
|
||||||
|
|
||||||
|
$view = $this->resolvedType->createView($form, $parentView);
|
||||||
|
|
||||||
|
$this->assertInstanceOf('Symfony\Component\Form\FormView', $view);
|
||||||
|
$this->assertSame($parentView, $view->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBuildView()
|
||||||
|
{
|
||||||
$options = array('a' => '1', 'b' => '2');
|
$options = array('a' => '1', 'b' => '2');
|
||||||
$form = $this->getBuilder('name', $options)
|
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||||
->setCompound(true)
|
$view = $this->getMock('Symfony\Component\Form\FormView');
|
||||||
->setDataMapper($this->dataMapper)
|
|
||||||
->setType($resolvedType)
|
|
||||||
->add($this->getBuilder('foo')->setType($field1ResolvedType))
|
|
||||||
->add($this->getBuilder('bar')->setType($field2ResolvedType))
|
|
||||||
->getForm();
|
|
||||||
|
|
||||||
$test = $this;
|
$test = $this;
|
||||||
$i = 0;
|
$i = 0;
|
||||||
|
|
||||||
$assertIndexAndNbOfChildViews = function ($index, $nbOfChildViews) use (&$i, $test) {
|
$assertIndex = function ($index) use (&$i, $test) {
|
||||||
return function (FormView $view) use (&$i, $test, $index, $nbOfChildViews) {
|
return function () use (&$i, $test, $index) {
|
||||||
/* @var \PHPUnit_Framework_TestCase $test */
|
/* @var \PHPUnit_Framework_TestCase $test */
|
||||||
$test->assertEquals($index, $i, 'Executed at index '.$index);
|
$test->assertEquals($index, $i, 'Executed at index '.$index);
|
||||||
$test->assertCount($nbOfChildViews, $view);
|
|
||||||
|
|
||||||
++$i;
|
++$i;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// First the super type
|
// First the super type
|
||||||
$parentType->expects($this->once())
|
$this->parentType->expects($this->once())
|
||||||
->method('buildView')
|
->method('buildView')
|
||||||
->with($this->anything(), $form, $options)
|
->with($view, $form, $options)
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(0, 0)));
|
->will($this->returnCallback($assertIndex(0)));
|
||||||
|
|
||||||
// Then the type itself
|
// Then the type itself
|
||||||
$type->expects($this->once())
|
$this->type->expects($this->once())
|
||||||
->method('buildView')
|
->method('buildView')
|
||||||
->with($this->anything(), $form, $options)
|
->with($view, $form, $options)
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(1, 0)));
|
->will($this->returnCallback($assertIndex(1)));
|
||||||
|
|
||||||
// Then its extensions
|
// Then its extensions
|
||||||
$extension1->expects($this->once())
|
$this->extension1->expects($this->once())
|
||||||
->method('buildView')
|
->method('buildView')
|
||||||
->with($this->anything(), $form, $options)
|
->with($view, $form, $options)
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(2, 0)));
|
->will($this->returnCallback($assertIndex(2)));
|
||||||
|
|
||||||
$extension2->expects($this->once())
|
$this->extension2->expects($this->once())
|
||||||
->method('buildView')
|
->method('buildView')
|
||||||
->with($this->anything(), $form, $options)
|
->with($view, $form, $options)
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(3, 0)));
|
->will($this->returnCallback($assertIndex(3)));
|
||||||
|
|
||||||
// Now the first child form
|
$this->resolvedType->buildView($view, $form, $options);
|
||||||
$field1Type->expects($this->once())
|
}
|
||||||
->method('buildView')
|
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(4, 0)));
|
public function testFinishView()
|
||||||
$field1Type->expects($this->once())
|
{
|
||||||
|
$options = array('a' => '1', 'b' => '2');
|
||||||
|
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||||
|
$view = $this->getMock('Symfony\Component\Form\FormView');
|
||||||
|
|
||||||
|
$test = $this;
|
||||||
|
$i = 0;
|
||||||
|
|
||||||
|
$assertIndex = function ($index) use (&$i, $test) {
|
||||||
|
return function () use (&$i, $test, $index) {
|
||||||
|
/* @var \PHPUnit_Framework_TestCase $test */
|
||||||
|
$test->assertEquals($index, $i, 'Executed at index '.$index);
|
||||||
|
|
||||||
|
++$i;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// First the super type
|
||||||
|
$this->parentType->expects($this->once())
|
||||||
->method('finishView')
|
->method('finishView')
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(5, 0)));
|
->with($view, $form, $options)
|
||||||
|
->will($this->returnCallback($assertIndex(0)));
|
||||||
// And the second child form
|
|
||||||
$field2Type->expects($this->once())
|
|
||||||
->method('buildView')
|
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(6, 0)));
|
|
||||||
$field2Type->expects($this->once())
|
|
||||||
->method('finishView')
|
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(7, 0)));
|
|
||||||
|
|
||||||
// Again first the parent
|
|
||||||
$parentType->expects($this->once())
|
|
||||||
->method('finishView')
|
|
||||||
->with($this->anything(), $form, $options)
|
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(8, 2)));
|
|
||||||
|
|
||||||
// Then the type itself
|
// Then the type itself
|
||||||
$type->expects($this->once())
|
$this->type->expects($this->once())
|
||||||
->method('finishView')
|
->method('finishView')
|
||||||
->with($this->anything(), $form, $options)
|
->with($view, $form, $options)
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(9, 2)));
|
->will($this->returnCallback($assertIndex(1)));
|
||||||
|
|
||||||
// Then its extensions
|
// Then its extensions
|
||||||
$extension1->expects($this->once())
|
$this->extension1->expects($this->once())
|
||||||
->method('finishView')
|
->method('finishView')
|
||||||
->with($this->anything(), $form, $options)
|
->with($view, $form, $options)
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(10, 2)));
|
->will($this->returnCallback($assertIndex(2)));
|
||||||
|
|
||||||
$extension2->expects($this->once())
|
$this->extension2->expects($this->once())
|
||||||
->method('finishView')
|
->method('finishView')
|
||||||
->with($this->anything(), $form, $options)
|
->with($view, $form, $options)
|
||||||
->will($this->returnCallback($assertIndexAndNbOfChildViews(11, 2)));
|
->will($this->returnCallback($assertIndex(3)));
|
||||||
|
|
||||||
$parentView = new FormView();
|
$this->resolvedType->finishView($view, $form, $options);
|
||||||
$view = $resolvedType->createView($form, $parentView);
|
|
||||||
|
|
||||||
$this->assertSame($parentView, $view->parent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,17 +11,26 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\HttpKernel\DataCollector;
|
namespace Symfony\Component\HttpKernel\DataCollector;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter;
|
||||||
|
use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataCollector.
|
* DataCollector.
|
||||||
*
|
*
|
||||||
* Children of this class must store the collected data in the data property.
|
* Children of this class must store the collected data in the data property.
|
||||||
*
|
*
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Bernhard Schussek <bschussek@symfony.com>
|
||||||
*/
|
*/
|
||||||
abstract class DataCollector implements DataCollectorInterface, \Serializable
|
abstract class DataCollector implements DataCollectorInterface, \Serializable
|
||||||
{
|
{
|
||||||
protected $data;
|
protected $data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ValueExporter
|
||||||
|
*/
|
||||||
|
private $valueExporter;
|
||||||
|
|
||||||
public function serialize()
|
public function serialize()
|
||||||
{
|
{
|
||||||
return serialize($this->data);
|
return serialize($this->data);
|
||||||
@ -41,35 +50,10 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable
|
|||||||
*/
|
*/
|
||||||
protected function varToString($var)
|
protected function varToString($var)
|
||||||
{
|
{
|
||||||
if (is_object($var)) {
|
if (null === $this->valueExporter) {
|
||||||
return sprintf('Object(%s)', get_class($var));
|
$this->valueExporter = new ValueExporter();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($var)) {
|
$this->valueExporter->exportValue($var);
|
||||||
$a = array();
|
|
||||||
foreach ($var as $k => $v) {
|
|
||||||
$a[] = sprintf('%s => %s', $k, $this->varToString($v));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf("Array(%s)", implode(', ', $a));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_resource($var)) {
|
|
||||||
return sprintf('Resource(%s)', get_resource_type($var));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $var) {
|
|
||||||
return 'null';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === $var) {
|
|
||||||
return 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === $var) {
|
|
||||||
return 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string) $var;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
<?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\HttpKernel\DataCollector\Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
|
*/
|
||||||
|
class ValueExporter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Converts a PHP value to a string.
|
||||||
|
*
|
||||||
|
* @param mixed $value The PHP value
|
||||||
|
*
|
||||||
|
* @return string The string representation of the given value
|
||||||
|
*/
|
||||||
|
public function exportValue($value)
|
||||||
|
{
|
||||||
|
if (is_object($value)) {
|
||||||
|
return sprintf('Object(%s)', get_class($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
$a = array();
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
$a[] = sprintf('%s => %s', $k, $this->exportValue($v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf("Array(%s)", implode(', ', $a));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_resource($value)) {
|
||||||
|
return sprintf('Resource(%s)', get_resource_type($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $value) {
|
||||||
|
return 'false';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === $value) {
|
||||||
|
return 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $value;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user