diff --git a/.alexrc b/.alexrc new file mode 100644 index 00000000000..168d412c177 --- /dev/null +++ b/.alexrc @@ -0,0 +1,16 @@ +{ + "allow": [ + "attack", + "attacks", + "bigger", + "color", + "colors", + "failure", + "hook", + "hooks", + "host-hostess", + "invalid", + "remain", + "special" + ] +} diff --git a/.doctor-rst.yaml b/.doctor-rst.yaml new file mode 100644 index 00000000000..2ecd4fc7d2d --- /dev/null +++ b/.doctor-rst.yaml @@ -0,0 +1,122 @@ +rules: + american_english: ~ + avoid_repetetive_words: ~ + blank_line_after_anchor: ~ + blank_line_after_directive: ~ + blank_line_before_directive: ~ + composer_dev_option_not_at_the_end: ~ + correct_code_block_directive_based_on_the_content: ~ + deprecated_directive_should_have_version: ~ + ensure_bash_prompt_before_composer_command: ~ + ensure_correct_format_for_phpfunction: ~ + ensure_exactly_one_space_before_directive_type: ~ + ensure_exactly_one_space_between_link_definition_and_link: ~ + ensure_explicit_nullable_types: ~ + ensure_github_directive_start_with_prefix: + prefix: 'Symfony' + ensure_link_bottom: ~ + ensure_link_definition_contains_valid_url: ~ + ensure_order_of_code_blocks_in_configuration_block: ~ + ensure_php_reference_syntax: ~ + extend_abstract_controller: ~ + # extension_xlf_instead_of_xliff: ~ + forbidden_directives: + directives: + - '.. index::' + - directive: '.. caution::' + replacements: ['.. warning::', '.. danger::'] + indention: ~ + lowercase_as_in_use_statements: ~ + max_blank_lines: + max: 2 + max_colons: ~ + no_app_console: ~ + no_attribute_redundant_parenthesis: ~ + no_blank_line_after_filepath_in_php_code_block: ~ + no_blank_line_after_filepath_in_twig_code_block: ~ + no_blank_line_after_filepath_in_xml_code_block: ~ + no_blank_line_after_filepath_in_yaml_code_block: ~ + no_brackets_in_method_directive: ~ + no_broken_ref_directive: ~ + no_composer_req: ~ + no_directive_after_shorthand: ~ + no_duplicate_use_statements: ~ + no_empty_literals: ~ + no_explicit_use_of_code_block_php: ~ + no_footnotes: ~ + no_inheritdoc: ~ + no_merge_conflict: ~ + no_namespace_after_use_statements: ~ + no_php_open_tag_in_code_block_php_directive: ~ + no_space_before_self_xml_closing_tag: ~ + non_static_phpunit_assertions: ~ + only_backslashes_in_namespace_in_php_code_block: ~ + only_backslashes_in_use_statements_in_php_code_block: ~ + ordered_use_statements: ~ + php_prefix_before_bin_console: ~ + remove_trailing_whitespace: ~ + replace_code_block_types: ~ + replacement: ~ + short_array_syntax: ~ + space_between_label_and_link_in_doc: ~ + space_between_label_and_link_in_ref: ~ + string_replacement: ~ + title_underline_length_must_match_title_length: ~ + typo: ~ + unused_links: ~ + use_deprecated_directive_instead_of_versionadded: ~ + use_named_constructor_without_new_keyword_rule: ~ + use_https_xsd_urls: ~ + valid_inline_highlighted_namespaces: ~ + valid_use_statements: ~ + versionadded_directive_should_have_version: ~ + yaml_instead_of_yml_suffix: ~ + + # master + versionadded_directive_major_version: + major_version: 7 + + versionadded_directive_min_version: + min_version: '7.0' + + deprecated_directive_major_version: + major_version: 7 + + deprecated_directive_min_version: + min_version: '7.0' + +exclude_rule_for_file: + - path: configuration/multiple_kernels.rst + rule_name: replacement + - path: page_creation.rst + rule_name: no_php_open_tag_in_code_block_php_directive + - path: frontend/create_ux_bundle.rst + rule_name: argument_variable_must_match_type + +# do not report as violation +whitelist: + regex: + - '/``.yml``/' + - '/(.*)\.orm\.yml/' # currently DoctrineBundle only supports .yml + lines: + - 'in config files, so the old ``app/config/config_dev.yml`` goes to' + - '#. The most important config file is ``app/config/services.yml``, which now is' + - 'The bin/console Command' + - '.. _`LDAP injection`: http://projects.webappsec.org/w/page/13246947/LDAP%20Injection' + - '.. versionadded:: 2.8.0' # Doctrine + - '.. versionadded:: 1.9.0' # Encore + - '.. versionadded:: 1.18' # Flex in setup/upgrade_minor.rst + - '.. versionadded:: 1.0.0' # Encore + - '.. versionadded:: 2.7.1' # Doctrine + - '123,' # assertion for var_dumper - components/var_dumper.rst + - '"foo",' # assertion for var_dumper - components/var_dumper.rst + - '$var .= "Because of this `\xE9` octet (\\xE9),\n";' + - '.. versionadded:: 0.2' # MercureBundle + - '.. versionadded:: 3.6' # MonologBundle + - '.. versionadded:: 3.8' # MonologBundle + - '.. versionadded:: 3.5' # Monolog + - '.. versionadded:: 3.0' # Doctrine ORM + - '.. _`a feature to test applications using Mercure`: https://github.com/symfony/panther#creating-isolated-browsers-to-test-apps-using-mercure-or-websocket' + - 'End to End Tests (E2E)' + - '.. versionadded:: 2.2.0' # Panther + - '* Inline code blocks use double-ticks (````like this````).' diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..f9366facfb0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..9eb5d91783b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,30 @@ +# GithubActions workflows +/.github/workflows* @OskarStark + +# Console +/console* @chalasr +/components/console* @chalasr + +# Form +/forms.rst @xabbuh @HeahDude +/components/form* @xabbuh @HeahDude +/reference/forms* @xabbuh @HeahDude + +# PropertyInfo +/components/property_info* @dunglas + +# Security +/security* @chalasr +/components/security* @chalasr + +# Validator +/validation/* @xabbuh @HeahDude +/components/validator* @xabbuh @HeahDude +/reference/constraints* @xabbuh @HeahDude + +# Workflow +/workflow* @lyrixx +/components/workflow* @lyrixx + +# Yaml +/components/yaml* @xabbuh diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000000..acb0770920e --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,5 @@ +Contributing +------------ + +We love contributors! For more information on how you can contribute to the +Symfony documentation, please read [Contributing to the Documentation](https://symfony.com/doc/current/contributing/documentation/overview.html). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..f32043e4523 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ + diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000000..497dfd9b430 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,145 @@ +name: CI + +on: + push: + branches-ignore: + - 'github-comments' + pull_request: + branches-ignore: + - 'github-comments' + +permissions: + contents: read + +jobs: + symfony-docs-builder-build: + name: Build (symfony-tools/docs-builder) + + runs-on: ubuntu-latest + + continue-on-error: true + + steps: + - name: "Checkout" + uses: actions/checkout@v4 + + - name: "Set-up PHP" + uses: shivammathur/setup-php@v2 + with: + php-version: 8.4 + coverage: none + + - name: Get composer cache directory + id: composercache + working-directory: _build + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: "Install dependencies" + working-directory: _build + run: composer install --prefer-dist --no-progress + + - name: "Build the docs" + working-directory: _build + run: php build.php --disable-cache + + doctor-rst: + name: Lint (DOCtor-RST) + + runs-on: ubuntu-latest + + steps: + - name: "Checkout" + uses: actions/checkout@v4 + + - name: "Create cache dir" + run: mkdir .cache + + - name: "Extract base branch name" + run: echo "branch=$(echo ${GITHUB_BASE_REF:=${GITHUB_REF##*/}})" >> $GITHUB_OUTPUT + id: extract_base_branch + + - name: "Cache DOCtor-RST" + uses: actions/cache@v3 + with: + path: .cache + key: ${{ runner.os }}-doctor-rst-${{ steps.extract_base_branch.outputs.branch }} + + - name: "Run DOCtor-RST" + uses: docker://oskarstark/doctor-rst:1.67.0 + with: + args: --short --error-format=github --cache-file=/github/workspace/.cache/doctor-rst.cache + + symfony-code-block-checker: + name: Code Blocks + + runs-on: ubuntu-latest + + continue-on-error: true + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + path: 'docs' + + - name: Set-up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.4 + coverage: none + + - name: Fetch branch from where the PR started + working-directory: docs + run: git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* + + - name: Find modified files + id: find-files + working-directory: docs + run: echo "files=$(git diff --name-only origin/${{ github.base_ref }} HEAD | grep ".rst" | tr '\n' ' ')" >> $GITHUB_OUTPUT + + - name: Get composer cache directory + id: composercache + working-directory: docs/_build + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + if: ${{ steps.find-files.outputs.files }} + uses: actions/cache@v3 + with: + path: ${{ steps.composercache.outputs.dir }} + key: ${{ runner.os }}-composer-codeBlocks-${{ hashFiles('_checker/composer.lock', '_sf_app/composer.lock') }} + restore-keys: ${{ runner.os }}-composer-codeBlocks- + + - name: Install dependencies + if: ${{ steps.find-files.outputs.files }} + run: composer create-project symfony-tools/code-block-checker:@dev _checker + + - name: Install test application + if: ${{ steps.find-files.outputs.files }} + run: | + git clone -b ${{ github.base_ref }} --depth 5 --single-branch https://github.com/symfony-tools/symfony-application.git _sf_app + cd _sf_app + composer update + + - name: Generate baseline + if: ${{ steps.find-files.outputs.files }} + working-directory: docs + run: | + CURRENT=$(git rev-parse HEAD) + git checkout -m ${{ github.base_ref }} + ../_checker/code-block-checker.php verify:docs `pwd` ${{ steps.find-files.outputs.files }} --generate-baseline=baseline.json --symfony-application=`realpath ../_sf_app` + git checkout -m $CURRENT + cat baseline.json + + - name: Verify examples + if: ${{ steps.find-files.outputs.files }} + working-directory: docs + run: | + ../_checker/code-block-checker.php verify:docs `pwd` ${{ steps.find-files.outputs.files }} --baseline=baseline.json --output-format=github --symfony-application=`realpath ../_sf_app` diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..b69047f69a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/_build/vendor +/_build/output diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000000..547ac103984 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,340 @@ +LICENSE +======= + +**Creative Commons Attribution-ShareAlike 3.0 Unported** +https://creativecommons.org/licenses/by-sa/3.0/ + +----- + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS +PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR +OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS +LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE +BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED +TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN +CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. + +1. Definitions +-------------- + +a. **"Adaptation"** means a work based upon the Work, or upon the Work and other +pre-existing works, such as a translation, adaptation, derivative work, +arrangement of music or other alterations of a literary or artistic work, or +phonogram or performance and includes cinematographic adaptations or any other +form in which the Work may be recast, transformed, or adapted including in any +form recognizably derived from the original, except that a work that constitutes +a Collection will not be considered an Adaptation for the purpose of this +License. For the avoidance of doubt, where the Work is a musical work, +performance or phonogram, the synchronization of the Work in timed-relation with +a moving image ("synching") will be considered an Adaptation for the purpose of +this License. + +b. **"Collection"** means a collection of literary or artistic works, such as +encyclopedias and anthologies, or performances, phonograms or broadcasts, or +other works or subject matter other than works listed in Section 1(f) below, +which, by reason of the selection and arrangement of their contents, constitute +intellectual creations, in which the Work is included in its entirety in +unmodified form along with one or more other contributions, each constituting +separate and independent works in themselves, which together are assembled into +a collective whole. A work that constitutes a Collection will not be considered +an Adaptation (as defined below) for the purposes of this License. + +c. **"Creative Commons Compatible License"** means a license that is listed at +https://creativecommons.org/compatiblelicenses that has been approved by +Creative Commons as being essentially equivalent to this License, including, at +a minimum, because that license: (i) contains terms that have the same purpose, +meaning and effect as the License Elements of this License; and, (ii) explicitly +permits the relicensing of adaptations of works made available under that +license under this License or a Creative Commons jurisdiction license with the +same License Elements as this License. + +d. **"Distribute"** means to make available to the public the original and +copies of the Work or Adaptation, as appropriate, through sale or other transfer +of ownership. + +e. **"License Elements"** means the following high-level license attributes as +selected by Licensor and indicated in the title of this License: Attribution, +ShareAlike. + +f. **"Licensor"** means the individual, individuals, entity or entities that +offer(s) the Work under the terms of this License. + +g. **"Original Author""** means, in the case of a literary or artistic work, the +individual, individuals, entity or entities who created the Work or if no +individual or entity can be identified, the publisher; and in addition (i) in +the case of a performance the actors, singers, musicians, dancers, and other +persons who act, sing, deliver, declaim, play in, interpret or otherwise perform +literary or artistic works or expressions of folklore; (ii) in the case of a +phonogram the producer being the person or legal entity who first fixes the +sounds of a performance or other sounds; and, (iii) in the case of broadcasts, +the organization that transmits the broadcast. + +h. **"Work"** means the literary and/or artistic work offered under the terms of +this License including without limitation any production in the literary, +scientific and artistic domain, whatever may be the mode or form of its +expression including digital form, such as a book, pamphlet and other writing; a +lecture, address, sermon or other work of the same nature; a dramatic or +dramatico-musical work; a choreographic work or entertainment in dumb show; a +musical composition with or without words; a cinematographic work to which are +assimilated works expressed by a process analogous to cinematography; a work of +drawing, painting, architecture, sculpture, engraving or lithography; a +photographic work to which are assimilated works expressed by a process +analogous to photography; a work of applied art; an illustration, map, plan, +sketch or three-dimensional work relative to geography, topography, architecture +or science; a performance; a broadcast; a phonogram; a compilation of data to +the extent it is protected as a copyrightable work; or a work performed by a +variety or circus performer to the extent it is not otherwise considered a +literary or artistic work. + +i. **"You"** means an individual or entity exercising rights under this License +who has not previously violated the terms of this License with respect to the +Work, or who has received express permission from the Licensor to exercise +rights under this License despite a previous violation. + +j. **"Publicly Perform"** means to perform public recitations of the Work and to +communicate to the public those public recitations, by any means or process, +including by wire or wireless means or public digital performances; to make +available to the public Works in such a way that members of the public may +access these Works from a place and at a place individually chosen by them; to +perform the Work to the public by any means or process and the communication to +the public of the performances of the Work, including by public digital +performance; to broadcast and rebroadcast the Work by any means including signs, +sounds or images. + +k. **"Reproduce"** means to make copies of the Work by any means including +without limitation by sound or visual recordings and the right of fixation and +reproducing fixations of the Work, including storage of a protected performance +or phonogram in digital form or other electronic medium. + +2. Fair Dealing Rights +---------------------- + +Nothing in this License is intended to reduce, limit, or restrict any uses free +from copyright or rights arising from limitations or exceptions that are +provided for in connection with the copyright protection under copyright law or +other applicable laws. + +3. License Grant +---------------- + +Subject to the terms and conditions of this License, Licensor hereby grants You +a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the +applicable copyright) license to exercise the rights in the Work as stated +below: + +a. to Reproduce the Work, to incorporate the Work into one or more Collections, +and to Reproduce the Work as incorporated in the Collections; + +b. to create and Reproduce Adaptations provided that any such Adaptation, +including any translation in any medium, takes reasonable steps to clearly +label, demarcate or otherwise identify that changes were made to the original +Work. For example, a translation could be marked "The original work was +translated from English to Spanish," or a modification could indicate "The +original work has been modified."; + +c. to Distribute and Publicly Perform the Work including as incorporated in +Collections; and, + +d. to Distribute and Publicly Perform Adaptations. + +e. For the avoidance of doubt: + + 1. **Non-waivable Compulsory License Schemes.** In those jurisdictions in + which the right to collect royalties through any statutory or compulsory + licensing scheme cannot be waived, the Licensor reserves the exclusive + right to collect such royalties for any exercise by You of the rights + granted under this License; + + 2. **Waivable Compulsory License Schemes.** In those jurisdictions in which + the right to collect royalties through any statutory or compulsory + licensing scheme can be waived, the Licensor waives the exclusive right to + collect such royalties for any exercise by You of the rights granted under + this License; and, + + 3. **Voluntary License Schemes.** The Licensor waives the right to collect + royalties, whether individually or, in the event that the Licensor is a + member of a collecting society that administers voluntary licensing + schemes, via that society, from any exercise by You of the rights granted + under this License. + +The above rights may be exercised in all media and formats whether now known or +hereafter devised. The above rights include the right to make such modifications +as are technically necessary to exercise the rights in other media and formats. +Subject to Section 8(f), all rights not expressly granted by Licensor are hereby +reserved. + +4. Restrictions +--------------- + +The license granted in Section 3 above is expressly made subject to and limited +by the following restrictions: + +a. You may Distribute or Publicly Perform the Work only under the terms of this +License. You must include a copy of, or the Uniform Resource Identifier (URI) +for, this License with every copy of the Work You Distribute or Publicly +Perform. You may not offer or impose any terms on the Work that restrict the +terms of this License or the ability of the recipient of the Work to exercise +the rights granted to that recipient under the terms of the License. You may not +sublicense the Work. You must keep intact all notices that refer to this License +and to the disclaimer of warranties with every copy of the Work You Distribute +or Publicly Perform. When You Distribute or Publicly Perform the Work, You may +not impose any effective technological measures on the Work that restrict the +ability of a recipient of the Work from You to exercise the rights granted to +that recipient under the terms of the License. This Section 4(a) applies to the +Work as incorporated in a Collection, but this does not require the Collection +apart from the Work itself to be made subject to the terms of this License. If +You create a Collection, upon notice from any Licensor You must, to the extent +practicable, remove from the Collection any credit as required by Section 4(c), +as requested. If You create an Adaptation, upon notice from any Licensor You +must, to the extent practicable, remove from the Adaptation any credit as +required by Section 4(c), as requested. + +b. You may Distribute or Publicly Perform an Adaptation only under the terms of: +(i) this License; (ii) a later version of this License with the same License +Elements as this License; (iii) a Creative Commons jurisdiction license (either +this or a later license version) that contains the same License Elements as this +License (e.g. Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons +Compatible License. If you license the Adaptation under one of the licenses +mentioned in (iv), you must comply with the terms of that license. If you +license the Adaptation under the terms of any of the licenses mentioned in (i), +(ii) or (iii) (the "Applicable License"), you must comply with the terms of the +Applicable License generally and the following provisions: (I) You must include +a copy of, or the URI for, the Applicable License with every copy of each +Adaptation You Distribute or Publicly Perform; (II) You may not offer or impose +any terms on the Adaptation that restrict the terms of the Applicable License or +the ability of the recipient of the Adaptation to exercise the rights granted to +that recipient under the terms of the Applicable License; (III) You must keep +intact all notices that refer to the Applicable License and to the disclaimer of +warranties with every copy of the Work as included in the Adaptation You +Distribute or Publicly Perform; (IV) when You Distribute or Publicly Perform the +Adaptation, You may not impose any effective technological measures on the +Adaptation that restrict the ability of a recipient of the Adaptation from You +to exercise the rights granted to that recipient under the terms of the +Applicable License. This Section 4(b) applies to the Adaptation as incorporated +in a Collection, but this does not require the Collection apart from the +Adaptation itself to be made subject to the terms of the Applicable License. + +c. If You Distribute, or Publicly Perform the Work or any Adaptations or +Collections, You must, unless a request has been made pursuant to Section 4(a), +keep intact all copyright notices for the Work and provide, reasonable to the +medium or means You are utilizing: (i) the name of the Original Author (or +pseudonym, if applicable) if supplied, and/or if the Original Author and/or +Licensor designate another party or parties (e.g. a sponsor institute, +publishing entity, journal) for attribution ("Attribution Parties") in +Licensor's copyright notice, terms of service or by other reasonable means, the +name of such party or parties; (ii) the title of the Work if supplied; (iii) to +the extent reasonably practicable, the URI, if any, that Licensor specifies to +be associated with the Work, unless such URI does not refer to the copyright +notice or licensing information for the Work; and (iv) , consistent with Section +3(b), in the case of an Adaptation, a credit identifying the use of the Work in +the Adaptation (e.g. "French translation of the Work by Original Author," or +"Screenplay based on original Work by Original Author"). The credit required by +this Section 4(c) may be implemented in any reasonable manner; provided, +however, that in the case of a Adaptation or Collection, at a minimum such +credit will appear, if a credit for all contributing authors of the Adaptation +or Collection appears, then as part of these credits and in a manner at least as +prominent as the credits for the other contributing authors. For the avoidance +of doubt, You may only use the credit required by this Section for the purpose +of attribution in the manner set out above and, by exercising Your rights under +this License, You may not implicitly or explicitly assert or imply any +connection with, sponsorship or endorsement by the Original Author, Licensor +and/or Attribution Parties, as appropriate, of You or Your use of the Work, +without the separate, express prior written permission of the Original Author, +Licensor and/or Attribution Parties. + +d. Except as otherwise agreed in writing by the Licensor or as may be otherwise +permitted by applicable law, if You Reproduce, Distribute or Publicly Perform +the Work either by itself or as part of any Adaptations or Collections, You must +not distort, mutilate, modify or take other derogatory action in relation to the +Work which would be prejudicial to the Original Author's honor or reputation. +Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise +of the right granted in Section 3(b) of this License (the right to make +Adaptations) would be deemed to be a distortion, mutilation, modification or +other derogatory action prejudicial to the Original Author's honor and +reputation, the Licensor will waive or not assert, as appropriate, this Section, +to the fullest extent permitted by the applicable national law, to enable You to +reasonably exercise Your right under Section 3(b) of this License (right to make +Adaptations) but not otherwise. + +5. Representations, Warranties and Disclaimer +--------------------------------------------- + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS +THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING +THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT +LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR +PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, +OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME +JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH +EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability +-------------------------- + +EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE +LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, +PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE +WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination +-------------- + +a. This License and the rights granted hereunder will terminate automatically +upon any breach by You of the terms of this License. Individuals or entities who +have received Adaptations or Collections from You under this License, however, +will not have their licenses terminated provided such individuals or entities +remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 +will survive any termination of this License. + +b. Subject to the above terms and conditions, the license granted here is +perpetual (for the duration of the applicable copyright in the Work). +Notwithstanding the above, Licensor reserves the right to release the Work under +different license terms or to stop distributing the Work at any time; provided, +however that any such election will not serve to withdraw this License (or any +other license that has been, or is required to be, granted under the terms of +this License), and this License will continue in full force and effect unless +terminated as stated above. + +8. Miscellaneous +---------------- + +a. Each time You Distribute or Publicly Perform the Work or a Collection, the +Licensor offers to the recipient a license to the Work on the same terms and +conditions as the license granted to You under this License. + +b. Each time You Distribute or Publicly Perform an Adaptation, Licensor offers +to the recipient a license to the original Work on the same terms and conditions +as the license granted to You under this License. + +c. If any provision of this License is invalid or unenforceable under applicable +law, it shall not affect the validity or enforceability of the remainder of the +terms of this License, and without further action by the parties to this +agreement, such provision shall be reformed to the minimum extent necessary to +make such provision valid and enforceable. + +d. No term or provision of this License shall be deemed waived and no breach +consented to unless such waiver or consent shall be in writing and signed by the +party to be charged with such waiver or consent. + +e. This License constitutes the entire agreement between the parties with +respect to the Work licensed here. There are no understandings, agreements or +representations with respect to the Work not specified here. Licensor shall not +be bound by any additional provisions that may appear in any communication from +You. This License may not be modified without the mutual written agreement of +the Licensor and You. + +f. The rights granted under, and the subject matter referenced, in this License +were drafted utilizing the terminology of the Berne Convention for the +Protection of Literary and Artistic Works (as amended on September 28, 1979), +the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO +Performances and Phonograms Treaty of 1996 and the Universal Copyright +Convention (as revised on July 24, 1971). These rights and subject matter take +effect in the relevant jurisdiction in which the License terms are sought to be +enforced according to the corresponding provisions of the implementation of +those treaty provisions in the applicable national law. If the standard suite of +rights granted under applicable copyright law includes additional rights not +granted under this License, such additional rights are deemed to be included in +the License; this License is not intended to restrict the license of any rights +under applicable law. diff --git a/README.md b/README.md new file mode 100644 index 00000000000..5c063058c02 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +

+ +

+ +

+ The official Symfony Documentation +

+ +

+ + Online version + + | + + Components + + | + + Screencasts + +

+ +Contributing +------------ + +We love contributors! For more information on how you can contribute, please read +the [Symfony Docs Contributing Guide](https://symfony.com/doc/current/contributing/documentation/overview.html). + +> [!IMPORTANT] +> Use `6.4` branch as the base of your pull requests, unless you are documenting a +> feature that was introduced *after* Symfony 6.4 (e.g. in Symfony 7.2). + +Build Documentation Locally +--------------------------- + +This is not needed for contributing, but it's useful if you would like to debug some +issue in the docs or if you want to read Symfony Documentation offline. + +```bash +$ git clone git@github.com:symfony/symfony-docs.git + +$ cd symfony-docs/ +$ cd _build/ + +$ composer install + +$ php build.php +``` + +After generating docs, serve them with the internal PHP server: + +```bash +$ php -S localhost:8000 -t output/ +``` + +Browse `http://localhost:8000` to read the docs. diff --git a/_build/build.php b/_build/build.php new file mode 100755 index 00000000000..b684700a848 --- /dev/null +++ b/_build/build.php @@ -0,0 +1,91 @@ +#!/usr/bin/env php +register('build-docs') + ->addOption('generate-fjson-files', null, InputOption::VALUE_NONE, 'Use this option to generate docs both in HTML and JSON formats') + ->addOption('disable-cache', null, InputOption::VALUE_NONE, 'Use this option to force a full regeneration of all doc contents') + ->setCode(function(InputInterface $input, OutputInterface $output) { + // the doc building app doesn't work on Windows + if ('\\' === DIRECTORY_SEPARATOR) { + $output->writeln('ERROR: The application that builds Symfony Docs does not support Windows. You can try using a Linux distribution via WSL (Windows Subsystem for Linux).'); + + return 1; + } + + $io = new SymfonyStyle($input, $output); + $io->text('Building all Symfony Docs...'); + + $outputDir = __DIR__.'/output'; + $buildConfig = (new BuildConfig()) + ->setSymfonyVersion('7.1') + ->setContentDir(__DIR__.'/..') + ->setOutputDir($outputDir) + ->setImagesDir(__DIR__.'/output/_images') + ->setImagesPublicPrefix('_images') + ->setTheme('rtd') + ; + + $buildConfig->setExcludedPaths(['.github/', '_build/']); + + if (!$generateJsonFiles = $input->getOption('generate-fjson-files')) { + $buildConfig->disableJsonFileGeneration(); + } + + if ($isCacheDisabled = $input->getOption('disable-cache')) { + $buildConfig->disableBuildCache(); + } + + $io->comment(sprintf('cache: %s / output file type(s): %s', $isCacheDisabled ? 'disabled' : 'enabled', $generateJsonFiles ? 'HTML and JSON' : 'HTML')); + if (!$isCacheDisabled) { + $io->comment('Tip: add the --disable-cache option to this command to force the re-build of all docs.'); + } + + $result = (new DocBuilder())->build($buildConfig); + + if ($result->isSuccessful()) { + // fix assets URLs to make them absolute (otherwise, they don't work in subdirectories) + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($outputDir)); + + foreach (new RegexIterator($iterator, '/^.+\.html$/i', RegexIterator::GET_MATCH) as $match) { + $htmlFilePath = array_shift($match); + $htmlContents = file_get_contents($htmlFilePath); + + $htmlRelativeFilePath = str_replace($outputDir.'/', '', $htmlFilePath); + $subdirLevel = substr_count($htmlRelativeFilePath, '/'); + $baseHref = str_repeat('../', $subdirLevel); + + $htmlContents = str_replace('', '', $htmlContents); + $htmlContents = str_replace('success(sprintf("The Symfony Docs were successfully built at %s", realpath($outputDir))); + } else { + $io->error(sprintf("There were some errors while building the docs:\n\n%s\n", $result->getErrorTrace())); + $io->newLine(); + $io->comment('Tip: you can add the -v, -vv or -vvv flags to this command to get debug information.'); + + return 1; + } + + return 0; + }) + ->getApplication() + ->setDefaultCommand('build-docs', true) + ->run(); diff --git a/_build/composer.json b/_build/composer.json new file mode 100644 index 00000000000..f77976b10f4 --- /dev/null +++ b/_build/composer.json @@ -0,0 +1,22 @@ +{ + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "platform": { + "php": "8.3" + }, + "preferred-install": { + "*": "dist" + }, + "sort-packages": true, + "allow-plugins": { + "symfony/flex": true + } + }, + "require": { + "php": ">=8.3", + "symfony/console": "^6.2", + "symfony/process": "^6.2", + "symfony-tools/docs-builder": "^0.27" + } +} diff --git a/_build/composer.lock b/_build/composer.lock new file mode 100644 index 00000000000..b9a4646f8ae --- /dev/null +++ b/_build/composer.lock @@ -0,0 +1,1792 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "e38eca557458275428db96db370d2c74", + "packages": [ + { + "name": "doctrine/event-manager", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "conflict": { + "doctrine/common": "<2.9" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.8.8", + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^5.24" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "keywords": [ + "event", + "event dispatcher", + "event manager", + "event system", + "events" + ], + "support": { + "issues": "https://github.com/doctrine/event-manager/issues", + "source": "https://github.com/doctrine/event-manager/tree/2.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager", + "type": "tidelift" + } + ], + "time": "2024-05-22T20:47:39+00:00" + }, + { + "name": "doctrine/rst-parser", + "version": "0.5.6", + "source": { + "type": "git", + "url": "https://github.com/doctrine/rst-parser.git", + "reference": "ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/rst-parser/zipball/ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104", + "reference": "ca7f5f31f9ea58fde5aeffe0f7b8eb569e71a104", + "shasum": "" + }, + "require": { + "doctrine/event-manager": "^1.0 || ^2.0", + "php": "^7.2 || ^8.0", + "symfony/filesystem": "^4.1 || ^5.0 || ^6.0 || ^7.0", + "symfony/finder": "^4.1 || ^5.0 || ^6.0 || ^7.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/string": "^5.3 || ^6.0 || ^7.0", + "symfony/translation-contracts": "^1.1 || ^2.0 || ^3.0", + "twig/twig": "^2.9 || ^3.3" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "gajus/dindent": "^2.0.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.2", + "phpstan/phpstan-strict-rules": "^1.4", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.0", + "symfony/css-selector": "4.4 || ^5.2 || ^6.0 || ^7.0", + "symfony/dom-crawler": "4.4 || ^5.2 || ^6.0 || ^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\RST\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Passault", + "email": "g.passault@gmail.com", + "homepage": "http://www.gregwar.com/" + }, + { + "name": "Jonathan H. Wage", + "email": "jonwage@gmail.com", + "homepage": "https://jwage.com" + } + ], + "description": "PHP library to parse reStructuredText documents and generate HTML or LaTeX documents.", + "homepage": "https://github.com/doctrine/rst-parser", + "keywords": [ + "html", + "latex", + "markup", + "parser", + "reStructuredText", + "rst" + ], + "support": { + "issues": "https://github.com/doctrine/rst-parser/issues", + "source": "https://github.com/doctrine/rst-parser/tree/0.5.6" + }, + "time": "2024-01-14T11:02:23+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + }, + "time": "2024-03-31T07:05:07+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "scrivo/highlight.php", + "version": "v9.18.1.10", + "source": { + "type": "git", + "url": "https://github.com/scrivo/highlight.php.git", + "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/850f4b44697a2552e892ffe71490ba2733c2fc6e", + "reference": "850f4b44697a2552e892ffe71490ba2733c2fc6e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7", + "sabberworm/php-css-parser": "^8.3", + "symfony/finder": "^2.8|^3.4|^5.4", + "symfony/var-dumper": "^2.8|^3.4|^5.4" + }, + "suggest": { + "ext-mbstring": "Allows highlighting code with unicode characters and supports language with unicode keywords" + }, + "type": "library", + "autoload": { + "files": [ + "HighlightUtilities/functions.php" + ], + "psr-0": { + "Highlight\\": "", + "HighlightUtilities\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Geert Bergman", + "homepage": "http://www.scrivo.org/", + "role": "Project Author" + }, + { + "name": "Vladimir Jimenez", + "homepage": "https://allejo.io", + "role": "Maintainer" + }, + { + "name": "Martin Folkers", + "homepage": "https://twobrain.io", + "role": "Contributor" + } + ], + "description": "Server side syntax highlighter that supports 185 languages. It's a PHP port of highlight.js", + "keywords": [ + "code", + "highlight", + "highlight.js", + "highlight.php", + "syntax" + ], + "support": { + "issues": "https://github.com/scrivo/highlight.php/issues", + "source": "https://github.com/scrivo/highlight.php" + }, + "funding": [ + { + "url": "https://github.com/allejo", + "type": "github" + } + ], + "time": "2022-12-17T21:53:22+00:00" + }, + { + "name": "symfony-tools/docs-builder", + "version": "0.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony-tools/docs-builder.git", + "reference": "720b52b2805122a4c08376496bd9661944c2624a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony-tools/docs-builder/zipball/720b52b2805122a4c08376496bd9661944c2624a", + "reference": "720b52b2805122a4c08376496bd9661944c2624a", + "shasum": "" + }, + "require": { + "doctrine/rst-parser": "^0.5", + "ext-curl": "*", + "ext-json": "*", + "php": ">=8.3", + "scrivo/highlight.php": "^9.18.1", + "symfony/console": "^5.2 || ^6.0 || ^7.0", + "symfony/css-selector": "^5.2 || ^6.0 || ^7.0", + "symfony/dom-crawler": "^5.2 || ^6.0 || ^7.0", + "symfony/filesystem": "^5.2 || ^6.0 || ^7.0", + "symfony/finder": "^5.2 || ^6.0 || ^7.0", + "symfony/http-client": "^5.2 || ^6.0 || ^7.0", + "twig/twig": "^2.14 || ^3.3" + }, + "require-dev": { + "gajus/dindent": "^2.0", + "masterminds/html5": "^2.7", + "symfony/phpunit-bridge": "^5.2 || ^6.0 || ^7.0", + "symfony/process": "^5.2 || ^6.0 || ^7.0" + }, + "bin": [ + "bin/docs-builder" + ], + "type": "project", + "autoload": { + "psr-4": { + "SymfonyDocsBuilder\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The build system for Symfony's documentation", + "support": { + "issues": "https://github.com/symfony-tools/docs-builder/issues", + "source": "https://github.com/symfony-tools/docs-builder/tree/0.27.0" + }, + "time": "2025-03-21T09:48:45+00:00" + }, + { + "name": "symfony/console", + "version": "v6.4.17", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", + "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.4.17" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-07T12:07:30+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/dom-crawler", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "19cc7b08efe9ad1ab1b56e0948e8d02e15ed3ef7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/19cc7b08efe9ad1ab1b56e0948e8d02e15ed3ef7", + "reference": "19cc7b08efe9ad1ab1b56e0948e8d02e15ed3ef7", + "shasum": "" + }, + "require": { + "masterminds/html5": "^2.6", + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony/css-selector": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dom-crawler/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-17T15:53:07+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-25T15:15:23+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:17+00:00" + }, + { + "name": "symfony/http-client", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", + "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "amphp/amp": "<2.5", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-13T10:27:23+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-07T08:49:48+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v6.4.19", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3", + "reference": "7a1c12e87b08ec9c97abdd188c9b3f5a40e37fc3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v6.4.19" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-04T13:35:48+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-13T13:31:26+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "twig/twig", + "version": "v3.20.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "3468920399451a384bef53cf7996965f7cd40183" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183", + "reference": "3468920399451a384bef53cf7996965f7cd40183", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.20.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-02-13T08:34:43+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=8.3" + }, + "platform-dev": {}, + "platform-overrides": { + "php": "8.3" + }, + "plugin-api-version": "2.6.0" +} diff --git a/_build/maintainer_guide.rst b/_build/maintainer_guide.rst new file mode 100644 index 00000000000..9758b4e7397 --- /dev/null +++ b/_build/maintainer_guide.rst @@ -0,0 +1,378 @@ +Symfony Docs Maintainer Guide +============================= + +The `symfony/symfony-docs`_ repository stores the Symfony project documentation +and is managed by the `Symfony Docs team`_. This article explains in detail some +of those management tasks, so it's only useful for maintainers and not regular +readers or Symfony developers. + +Reviewing Pull Requests +----------------------- + +All the recommendations of the `Symfony's respectful review comments`_ apply, +but there are extra things to keep in mind for maintainers: + +* Always be nice in all interactions with all contributors. +* Be extra-patient with new contributors (GitHub shows a special badge for them). +* Don't assume that contributors know what you think is obvious (e.g. lots of + them don't know what to "squash commits" means). +* Don't use acronyms like IMO, IIRC, etc. or complex English words (most + contributors are not native in English and it's intimidating for them). +* Never engage in a heated discussion. Lock it right away using GitHub. +* Never discuss non-tech issues. Some PRs are related to our Diversity initiative + and some people always try to drag you into politics. Never engage in that and + lock the issue/PR as off-topic on GitHub. + +Fixing Minor Issues Yourself +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It's common for new contributors to make lots of minor mistakes in the syntax +of the RST format used in the docs. It's also common for non English speakers to +make minor typos. + +Even if your intention is good, if you add lots of comments when reviewing a +first contribution, that person will probably not contribute again. It's better +to fix the minor errors and typos yourself while merging. If that person +contributes again, it's OK to mention some of the minor issues to educate them. + +.. code-block:: terminal + + $ gh merge 11059 + + Working on symfony/symfony-docs (branch 6.2) + Merging Pull Request 11059: dmaicher/patch-3 + + ... + + # This is important!! Say NO to push the changes now + Push the changes now? (Y/n) n + Now, push with: git push gh "6.2" refs/notes/github-comments + + # Now, open your editor and make the needed changes ... + + $ git commit -a + # Use "Minor reword", "Minor tweak", etc. as the commit message + + # now run the 'push' command shown above by 'gh' (it's different each time) + $ git push gh "6.2" refs/notes/github-comments + +Merging Pull Requests +--------------------- + +Technical Requirements +~~~~~~~~~~~~~~~~~~~~~~ + +* `Git`_ installed and properly configured. +* ``gh`` tool fully installed according to its installation instructions + (GitHub token configured, Git remote configured, etc.) + This is a proprietary CLI tool which only Symfony team members have access to. +* Some previous Git experience, specially merging pull requests. + +First Setup +~~~~~~~~~~~ + +First, fork the using the GitHub web +interface. Then: + +.. code-block:: terminal + + # Clone your fork + $ git clone https://github.com//symfony-docs.git + + $ cd symfony-docs/ + + # Add the original repo as 'upstream' remote + $ git remote add upstream https://github.com/symfony/symfony-docs + + # Add the original repo as 'gh' remote (needed for the 'gh' tool) + $ git remote add gh https://github.com/symfony/symfony-docs + + # Configure 'gh' in Git as the remote used by the 'gh' tool + $ git config gh.remote gh + +Merging Process +~~~~~~~~~~~~~~~ + +At first, it's common to make mistakes and merge things badly. Don't worry. This +has happened to all of us and we've always been able to recover from any mistake. + +Step 1: Select the right branch to merge +........................................ + +PRs must be merged in the oldest maintained branch where they are applicable: + +* Here you can find the currently maintained branches: https://symfony.com/roadmap. +* Typos and old undocumented features are merged into the oldest maintained branch. +* New features are merged into the branch where they were introduced. This + usually means ``master``. And don't forget to check that new feature includes + the ``versionadded`` directive. + +It's very common for contributors (specially newcomers) to select the wrong +branch for their PRs, so we must always check if the change should go to the +proposed branch or not. + +If the branch is wrong, there's no need to ask the contributor to rebase. The +``gh`` tool can do that for us. + +Step 2: Merge the pull request +.............................. + +Never use GitHub's web interface (or desktop clients) to merge PRs or to solve +merge conflicts. Always use the ``gh`` tool for anything related to merges. + +We require two approval votes from team members before merging a PR, except if +it's a typo, a small change or clearly an error. + +If a PR contains lots of commits, there's no need to ask the contributor to +squash them. The ``gh`` tool does that automatically. The only exceptions are +when commits are made by more than one person and when there's a merge commit. +``gh`` can't squash commits in those cases, so it's better to ask to the +original contributor. + +.. code-block:: terminal + + $ cd symfony-docs/ + + # make sure that your local branch is updated + $ git checkout 4.4 + $ git fetch upstream + $ git merge upstream/4.4 + + # merge any PR passing its GitHub number as argument + $ gh merge 11159 + + # the gh tool will ask you some questions... + + # push your changes (you can merge several PRs and push once at the end) + $ git push origin + $ git push upstream + +It's common to have to change the branch where a PR is merged. Instead of asking +the contributors to rebase their PRs, the "gh" tool can change the branch with +the ``-s`` option: + +.. code-block:: terminal + + # e.g. this PR was sent against 'master', but it's merged in '4.4' + $ gh merge 11160 -s 4.4 + +Sometimes, when changing the branch, you may face rebase issues, but they are +usually simple to fix: + +.. code-block:: terminal + + $ gh merge 11160 -s 4.4 + + ... + + Unable to rebase the patch for pull/11183 + The command "'git' 'rebase' '--onto' '4.4' '5.0' 'pull/11160'" failed. + Exit Code: 128(Invalid exit argument) + + [...] + Auto-merging reference/forms/types/entity.rst + CONFLICT (content): Merge conflict in reference/forms/types/entity.rst + Patch failed at 0001 Update entity.rst + The copy of the patch that failed is found in: .git/rebase-apply/patch + + # Now, fix all the conflicts using your editor + + # Add the modified files and continue the rebase + $ git add reference/forms/types/entity.rst ... + $ git rebase --continue + + # Lastly, re-run the exact same original command that resulted in a conflict + # There's no need to change the branch or do anything else. + $ gh merge 11160 -s 4.4 + + The previous run had some conflicts. Do you want to resume the merge? (Y/n) + +Later in this article you can find a troubleshooting section for the errors that +you will usually face while merging. + +Step 3: Merge it into the other branches +........................................ + +If a PR has not been merged in ``master``, you must merge it up into all the +maintained branches until ``master``. Imagine that you are merging a PR against +``4.4`` and the maintained branches are ``4.4``, ``5.0`` and ``master``: + +.. code-block:: terminal + + $ git fetch upstream + + $ git checkout 4.4 + $ git merge upstream/4.4 + + $ gh merge 11159 + $ git push origin + $ git push upstream + + $ git checkout 5.0 + $ git merge upstream/5.0 + $ git merge --log 4.4 + # here you can face several errors explained later + $ git push origin + $ git push upstream + + $ git checkout master + $ git merge upstream/master + $ git merge --log 5.0 + $ git push origin + $ git push upstream + +.. tip:: + + If you followed the full ``gh`` installation instructions you can remove the + ``--log`` option in the above commands. + +.. tip:: + + When the support of a Symfony branch ends, it's recommended to delete your + local branch to avoid merging in it unawarely: + + .. code-block:: terminal + + # if Symfony 3.3 goes out of maintenance today, delete your local branch + $ git branch -D 3.3 + +Troubleshooting +~~~~~~~~~~~~~~~ + +Wrong merge of your local branch +................................ + +When updating your local branches before merging: + +.. code-block:: terminal + + $ git fetch upstream + $ git checkout 4.4 + $ git merge upstream/4.4 + +It's possible that you merge a wrong upstream branch unawarely. It's usually +easy to spot because you'll see lots of conflicts: + +.. code-block:: terminal + + # DON'T DO THIS! It's a wrong branch merge + $ git checkout 4.4 + $ git merge upstream/5.0 + +As long as you don't push this wrong merge, there's no problem. Delete your +local branch and check it out again: + +.. code-block:: terminal + + $ git checkout master + $ git branch -D 4.4 + $ git checkout 4.4 upstream/4.4 + +If you did push the wrong branch merge, ask for help in the documentation +mergers chat and we'll help solve the problem. + +Solving merge conflicts +....................... + +When merging things to upper branches, most of the times you'll see conflicts: + +.. code-block:: terminal + + $ git checkout 5.0 + $ git merge upstream/5.0 + $ git merge --log 4.4 + + Auto-merging security/entity_provider.rst + Auto-merging logging/monolog_console.rst + Auto-merging form/dynamic_form_modification.rst + Auto-merging components/phpunit_bridge.rst + CONFLICT (content): Merge conflict in components/phpunit_bridge.rst + Automatic merge failed; fix conflicts and then commit the result. + +Solve the conflicts with your editor (look for occurrences of ``<<<<``, which is +the marker used by Git for conflicts) and then do this: + +.. code-block:: terminal + + # add all the conflicting files that you fixed + $ git add components/phpunit_bridge.rst + $ git commit -a + $ git push origin + $ git push upstream + +.. tip:: + + When there are lots of conflicts, look for ``<<<<<`` with your editor in all + docs before committing the changes. It's common to forget about some of them. + If you prefer, you can run this too: ``git grep --cached "<<<<<"``. + +Merging deleted files +..................... + +A common cause of conflict when merging PRs into upper branches are files which +were modified by the PR but no longer exist in newer branches: + +.. code-block:: terminal + + $ git checkout 5.0 + $ git merge upstream/5.0 + $ git merge --log 4.4 + + Auto-merging translation/debug.rst + CONFLICT (modify/delete): service_container/scopes.rst deleted in HEAD and + modified in 4.4. Version 4.4 of service_container/scopes.rst left in tree. + Auto-merging service_container.rst + +If the contents of the deleted file were moved to a different file in newer +branches, redo the changes in the new file. Then, delete the file that Git left +in the tree as follows: + +.. code-block:: terminal + + # delete all the conflicting files that no longer exist in this branch + $ git rm service_container/scopes.rst + $ git commit -a + $ git push origin + $ git push upstream + +Merging in the wrong branch +........................... + +A Pull Request was made against ``5.x`` but it should be merged in ``5.1`` and you +forgot to merge as ``gh merge NNNNN -s 5.1`` to change the merge branch. Solution: + +.. code-block:: terminal + + $ git checkout 5.1 + $ git cherry-pick -m 1 + $ git checkout 5.x + $ git revert -m 1 + # now continue with the normal "upmerging" + $ git checkout 5.2 + $ git merge 5.1 + $ ... + +Merging while the target branch changed +....................................... + +Sometimes, someone else merges a PR in ``5.x`` at the same time as you are +doing it. In these cases, ``gh merge ...`` fails to push. Solve this by +resetting your local branch and restarting the merge: + +.. code-block:: terminal + + $ gh merge ... + # this failed + + # fetch the updated 5.x branch from GitHub + $ git fetch upstream + $ git checkout 5.x + $ git reset --hard upstream/5.x + + # restart the merge + $ gh merge ... + +.. _`symfony/symfony-docs`: https://github.com/symfony/symfony-docs +.. _`Symfony Docs team`: https://github.com/orgs/symfony/teams/team-symfony-docs +.. _`Symfony's respectful review comments`: https://symfony.com/doc/current/contributing/community/review-comments.html +.. _`Git`: https://git-scm.com/ diff --git a/_build/redirection_map b/_build/redirection_map new file mode 100644 index 00000000000..ee14c191025 --- /dev/null +++ b/_build/redirection_map @@ -0,0 +1,576 @@ +/book/index /index +/cookbook/index /index +/book/stable_api /contributing/code/bc +/book/internals /reference/events +/configuration/apache_router /routing +/cookbook/console/sending_emails /cookbook/console/request_context +/cookbook/deployment-tools /cookbook/deployment/tools +/cookbook/doctrine/migrations /bundles/DoctrineFixturesBundle/index +/cookbook/doctrine/doctrine_fixtures /bundles/DoctrineFixturesBundle/index +/cookbook/doctrine/mongodb /bundles/DoctrineMongoDBBundle/index +/cookbook/form/dynamic_form_generation /cookbook/form/dynamic_form_modification +/cookbook/form/simple_signup_form_with_mongodb /bundles/DoctrineMongoDBBundle/form +/cookbook/email /email +/cookbook/gmail /cookbook/email/gmail +/cookbook/console /components/console +/cookbook/tools/autoloader https://github.com/symfony/class-loader +/cookbook/tools/finder /components/finder +/cookbook/service_container/parentservices /service_container/parent_services +/cookbook/service_container/factories /service_container/factories +/cookbook/service_container/tags /service_container/tags +/reference/configuration/mongodb /bundles/DoctrineMongoDBBundle/config +/reference/YAML /components/yaml +/cookbook/console/generating_urls /cookbook/console/sending_emails +/cmf/reference/configuration/block /cmf/bundles/block/configuration +/cmf/reference/configuration/content /cmf/bundles/content/configuration +/cmf/reference/configuration/core /cmf/bundles/core/configuration +/cmf/reference/configuration/create /cmf/bundles/create/configuration +/cmf/reference/configuration/media /cmf/bundles/media/configuration +/cmf/reference/configuration/menu /cmf/bundles/menu/configuration +/cmf/reference/configuration/phpcr_odm /cmf/bundles/phpcr_odm/configuration +/cmf/reference/configuration/routing /cmf/bundles/routing/configuration +/cmf/reference/configuration/search /cmf/bundles/search/configuration +/cmf/reference/configuration/seo /cmf/bundles/seo/configuration +/cmf/reference/configuration/simple_cms /cmf/bundles/simple_cms/configuration +/cmf/reference/configuration/tree_browser /cmf/bundles/tree_browser/configuration +/cmf/cookbook/exposing_content_via_rest /cmf/bundles/content/exposing_content_via_rest +/cmf/cookbook/creating_a_cms/auto-routing /cmf/tutorial/auto-routing +/cmf/cookbook/creating_a_cms/conclusion /cmf/tutorial/conclusion +/cmf/cookbook/creating_a_cms/content-to-controllers /cmf/tutorial/content-to-controllers +/cmf/cookbook/creating_a_cms/getting-started /cmf/tutorial/getting-started +/cmf/cookbook/creating_a_cms/index /cmf/tutorial/index +/cmf/cookbook/creating_a_cms/introduction /cmf/tutorial/introduction +/cmf/cookbook/creating_a_cms/make-homepage /cmf/tutorial/make-homepage +/cmf/cookbook/creating_a_cms/sonata-admin /cmf/tutorial/sonata-admin +/cmf/cookbook/creating_a_cms/the-frontend /cmf/tutorial/the-frontend +/cookbook/upgrading /cookbook/upgrade/index +/cookbook/security/voters_data_permission /cookbook/security/voters +/cookbook/configuration/pdo_session_storage /cookbook/doctrine/pdo_session_storage +/cookbook/configuration/mongodb_session_storage /cookbook/doctrine/mongodb_session_storage +/cookbook/service_container/event_listener /event_dispatcher +/create_framework/http-foundation /create_framework/http_foundation +/create_framework/front-controller /create_framework/front_controller +/create_framework/http-kernel-controller-resolver /create_framework/http_kernel_controller_resolver +/create_framework/separation-of-concerns /create_framework/separation_of_concerns +/create_framework/unit-testing /create_framework/unit_testing +/create_framework/event-dispatcher /create_framework/event_dispatcher +/create_framework/http-kernel-httpkernelinterface /create_framework/http_kernel_httpkernelinterface +/create_framework/http-kernel-httpkernel-class /create_framework/http_kernel_httpkernel_class +/create_framework/dependency-injection /create_framework/dependency_injection +/cookbook/doctrine/file_uploads /cookbook/controller/upload_file +/book/installation /setup +/book/page_creation /page_creation +/book/controller /controller +/book/routing /routing +/book/templating /templating +/book/bundles /bundles +/book/doctrine /doctrine +/book/testing /testing +/book/validation /validation +/book/forms /forms +/book/security /security +/book/http_cache /http_cache +/book/translation /translation +/book/service_container /service_container +/book/http_fundamentals /introduction/http_fundamentals +/book/from_flat_php_to_symfony2 /introduction/from_flat_php_to_symfony2 +/book/configuration /configuration +/book/propel /propel/propel +/book/performance /performance +/bundles/installation /bundles +/cookbook/assetic/apply_to_option /frontend/assetic/apply_to_option +/cookbook/assetic/asset_management /frontend/assetic/asset_management +/cookbook/assetic/index /frontend/assetic/index +/cookbook/assetic/jpeg_optimize /frontend/assetic/jpeg_optimize +/cookbook/assetic/php /frontend/assetic/php +/cookbook/assetic/uglifyjs /frontend/assetic/uglifyjs +/cookbook/assetic/yuicompressor /frontend/assetic/yuicompressor +/assetic /frontend/assetic/index +/assetic/apply_to_option /frontend/assetic/apply_to_option +/assetic/asset_management /frontend/assetic/asset_management +/assetic/jpeg_optimize /frontend/assetic/jpeg_optimize +/assetic/php /frontend/assetic/php +/assetic/uglifyjs /frontend/assetic/uglifyjs +/assetic/yuicompressor /frontend/assetic/yuicompressor +/cookbook/bundles/best_practices /bundles/best_practices +/cookbook/bundles/configuration /bundles/configuration +/cookbook/bundles/extension /bundles/extension +/cookbook/bundles/index /bundles +/cookbook/bundles/inheritance /bundles/inheritance +/cookbook/bundles/installation /bundles +/cookbook/bundles/override /bundles/override +/cookbook/bundles/prepend_extension /bundles/prepend_extension +/cookbook/bundles/remove /bundles +/bundles/remove /bundles +/cookbook/cache/form_csrf_caching /http_cache/form_csrf_caching +/cookbook/cache/varnish /http_cache/varnish +/cookbook/composer /setup/composer +/cookbook/configuration/apache_router /routing +/cookbook/configuration/configuration_organization /configuration/configuration_organization +/cookbook/configuration/environments /configuration/environments +/cookbook/configuration/external_parameters /configuration/external_parameters +/cookbook/configuration/front_controllers_and_kernel /configuration/front_controllers_and_kernel +/cookbook/configuration/micro-kernel-trait /configuration/micro_kernel_trait +/cookbook/configuration/index /configuration +/cookbook/configuration/override_dir_structure /configuration/override_dir_structure +/cookbook/configuration/using_parameters_in_dic /configuration/using_parameters_in_dic +/cookbook/configuration/web_server_configuration /setup/web_server_configuration +/cookbook/console/command_in_controller /console/command_in_controller +/cookbook/console/commands_as_services /console/commands_as_services +/cookbook/console/console_command /console +/cookbook/console/index /console +/cookbook/console/logging /console +/cookbook/console/request_context /console/request_context +/cookbook/console/style /console/style +/cookbook/console/usage /console +/console/usage /console +/cookbook/controller/csrf_token_validation /security/csrf +/cookbook/controller/error_pages /controller/error_pages +/cookbook/controller/forwarding /controller/forwarding +/cookbook/controller/index /controller +/cookbook/controller/service /controller/service +/cookbook/controller/upload_file /controller/upload_file +/cookbook/debugging / +/debug/debugging / +/cookbook/deployment/tools /deployment/tools +/cookbook/doctrine/common_extensions /doctrine/common_extensions +/cookbook/doctrine/console /doctrine +/cookbook/doctrine/custom_dql_functions /doctrine/custom_dql_functions +/cookbook/doctrine/dbal /doctrine/dbal +/cookbook/doctrine/event_listeners_subscribers /doctrine/event_listeners_subscribers +/cookbook/doctrine/index /doctrine +/cookbook/doctrine/mapping_model_classes /doctrine +/doctrine/mapping_model_classes /doctrine +/cookbook/doctrine/mongodb_session_storage /doctrine/mongodb_session_storage +/cookbook/doctrine/multiple_entity_managers /doctrine/multiple_entity_managers +/cookbook/doctrine/pdo_session_storage /doctrine/pdo_session_storage +/cookbook/doctrine/registration_form /doctrine/registration_form +/cookbook/doctrine/resolve_target_entity /doctrine/resolve_target_entity +/cookbook/doctrine/reverse_engineering /doctrine/reverse_engineering +/doctrine/repository /doctrine +/doctrine/console /doctrine +/cookbook/email/cloud /email +/cookbook/email/dev_environment /email/dev_environment +/cookbook/email/email /email +/cookbook/email/gmail /email +/cookbook/email/index /email +/cookbook/email/spool /email/spool +/cookbook/email/testing /email/testing +/cookbook/event_dispatcher/before_after_filters /event_dispatcher#event-dispatcher-before-after-filters +/event_dispatcher/before_after_filters /event_dispatcher#event-dispatcher-before-after-filters +/cookbook/event_dispatcher/class_extension /event_dispatcher/class_extension +/cookbook/event_dispatcher/event_listener /event_dispatcher +/cookbook/event_dispatcher/index /event_dispatcher +/cookbook/event_dispatcher/method_behavior /event_dispatcher/method_behavior +/event_dispatcher/method_behavior /event_dispatcher#event-dispatcher-method-behavior +/cookbook/expressions /security/expressions +/expressions /security/expressions +/cookbook/form/create_custom_field_type /form/create_custom_field_type +/cookbook/form/create_form_type_extension /form/create_form_type_extension +/cookbook/form/data_transformers /form/data_transformers +/cookbook/form/direct_submit /form/direct_submit +/cookbook/form/dynamic_form_modification /form/dynamic_form_modification +/cookbook/form/form_collections /form/form_collections +/cookbook/form/form_customization /form/form_customization +/cookbook/form/index /forms +/cookbook/form/inherit_data_option /form/inherit_data_option +/cookbook/form/unit_testing /form/unit_testing +/cookbook/form/use_empty_data /form/use_empty_data +/cookbook/frontend/bower /frontend +/cookbook/frontend/index /frontend +/cookbook/install/unstable_versions /setup/unstable_versions +/cookbook/install/bundles /setup/bundles +/cookbook/install/index /setup +/cookbook/install/upgrade_major /setup/upgrade_major +/cookbook/install/upgrade_minor /setup/upgrade_minor +/cookbook/install/upgrade_patch /setup/upgrade_patch +/cookbook/logging/channels_handlers /logging/channels_handlers +/cookbook/logging/index /logging +/cookbook/logging/monolog /logging +/cookbook/logging/monolog_console /logging/monolog_console +/cookbook/logging/monolog_email /logging/monolog_email +/cookbook/logging/monolog_regex_based_excludes /logging/monolog_regex_based_excludes +/cookbook/profiler/data_collector /profiler#profiler-data-collector +/profiler/data_collector /profiler#profiler-data-collector +/cookbook/profiler/index /profiler +/cookbook/profiler/matchers /profiler/matchers +/cookbook/profiler/profiling_data /profiler/profiling_data +/cookbook/profiler/storage /profiler/storage +/cookbook/psr7 /components/psr7 +/cookbook/request/index /request +/cookbook/request/load_balancer_reverse_proxy /deployment/proxies +/cookbook/request/mime_type /reference/configuration/framework +/cookbook/routing/conditions /routing/conditions +/cookbook/routing/custom_route_loader /routing/custom_route_loader +/cookbook/routing/debug /routing/debug +/cookbook/routing/external_resources /routing/external_resources +/cookbook/routing/extra_information /routing/extra_information +/cookbook/routing/index /routing +/cookbook/routing/method_parameters /routing/requirements +/cookbook/routing/optional_placeholders /routing/optional_placeholders +/cookbook/routing/redirect_in_config /routing/redirect_in_config +/cookbook/routing/redirect_trailing_slash /routing/redirect_trailing_slash +/cookbook/routing/requirements /routing/requirements +/cookbook/routing/routing_from_database /routing/routing_from_database +/cookbook/routing/scheme /routing/scheme +/cookbook/routing/service_container_parameters /routing/service_container_parameters +/cookbook/routing/slash_in_parameter /routing/slash_in_parameter +/cookbook/security/access_control /security/access_control +/cookbook/security/acl /security/acl +/cookbook/security/acl_advanced /security/acl_advanced +/cookbook/security/api_key_authentication /security/api_key_authentication +/cookbook/security/csrf_in_login_form /security/csrf +/cookbook/security/custom_authentication_provider /security/custom_authentication_provider +/cookbook/security/custom_password_authenticator /security/custom_password_authenticator +/cookbook/security/custom_provider /security/custom_provider +/cookbook/security/entity_provider /security/entity_provider +/cookbook/security/firewall_restriction /security/firewall_restriction +/cookbook/security/force_https /security/force_https +/cookbook/security/form_login /security/form_login +/cookbook/security/form_login_setup /security/form_login_setup +/cookbook/security/guard-authentication /security/guard_authentication +/cookbook/security/host_restriction /security/host_restriction +/cookbook/security/impersonating_user /security/impersonating_user +/cookbook/security/ldap /security/ldap +/cookbook/security/multiple_guard_authenticators /security/multiple_guard_authenticators +/cookbook/security/index /security +/cookbook/security/multiple_user_providers /security/multiple_user_providers +/cookbook/security/named_encoders /security/named_encoders +/cookbook/security/pre_authenticated /security/pre_authenticated +/cookbook/security/remember_me /security/remember_me +/cookbook/security/securing_services /security/securing_services +/cookbook/security/target_path /security/target_path +/cookbook/security/user_checkers /security/user_checkers +/cookbook/security/voters /security/voters +/cookbook/serializer /serializer +/cookbook/service_container/compiler_passes /service_container/compiler_passes +/cookbook/service_container/index /service_container +/cookbook/service_container/scopes /service_container/scopes +/cookbook/service_container/shared /service_container/shared +/cookbook/session/avoid_session_start /session/avoid_session_start +/cookbook/session/index /session +/cookbook/session/limit_metadata_writes /reference/configuration/framework +/session/limit_metadata_writes /reference/configuration/framework +/cookbook/session/locale_sticky_session /session#locale-sticky-session +/cookbook/locale_sticky_session /session#locale-sticky-session +/cookbook/session/php_bridge /session/php_bridge +/cookbook/session/proxy_examples /session/proxy_examples +/cookbook/session/sessions_directory /session/sessions_directory +/cookbook/symfony1 /introduction/symfony1 +/cookbook/templating/global_variables /templating#templating-global-variables +/templating/global_variables /templating#templating-global-variables +/cookbook/templating/index /templating +/cookbook/templating/namespaced_paths /templating/namespaced_paths +/cookbook/templating/PHP /templating/PHP +/cookbook/templating/render_without_controller /templating/render_without_controller +/cookbook/templating/twig_extension /templating/twig_extension +/cookbook/testing/bootstrap /testing/bootstrap +/cookbook/testing/database /testing/database +/cookbook/testing/doctrine /testing/doctrine +/cookbook/testing/http_authentication /testing/http_authentication +/cookbook/testing/index /testing +/cookbook/testing/insulating_clients /testing/insulating_clients +/cookbook/testing/profiling /testing/profiling +/cookbook/testing/simulating_authentication /testing/simulating_authentication +/cookbook/upgrade/bundles /upgrade/patch_version +/cookbook/upgrade/index /setup/upgrade_major +/cookbook/upgrade/major_version /setup/upgrade_minor +/cookbook/upgrade/minor_version /setup/upgrade_major +/cookbook/upgrade/patch_version /upgrade/bundles +/cookbook/validation/custom_constraint /validation/custom_constraint +/cookbook/validation/group_service_resolver /form/validation_group_service_resolver +/cookbook/validation/index /validation +/cookbook/validation/severity /validation/severity +/cookbook/web_server/built_in /setup/built_in_web_server +/cookbook/web_server/index /setup/built_in_web_server +/cookbook/web_services/index /controller/soap_web_service +/cookbook/web_services/php_soap_extension /controller/soap_web_service +/cookbook/workflow/homestead /setup/homestead +/cookbook/workflow/index /setup +/cookbook/workflow/new_project_git /setup +/cookbook/workflow/new_project_svn /setup +/setup/new_project_git /setup +/setup/new_project_svn /setup +/components/asset/index /components/asset +/components/asset/introduction /components/asset +/components/browser_kit/index /components/browser_kit +/components/browser_kit/introduction /components/browser_kit +/components/class_loader/introduction https://github.com/symfony/class-loader +/components/class_loader/index https://github.com/symfony/class-loader +/components/class_loader/cache_class_loader https://github.com/symfony/class-loader +/components/class_loader/class_loader https://github.com/symfony/class-loader +/components/class_loader/class_map_generator https://github.com/symfony/class-loader +/components/class_loader/debug_class_loader https://github.com/symfony/class-loader +/components/class_loader/map_class_loader https://github.com/symfony/class-loader +/components/class_loader/map_class_loader https://github.com/symfony/class-loader +/components/class_loader/psr4_class_loader https://github.com/symfony/class-loader +/components/config/introduction /components/config +/components/config/index /components/config +/components/console/helpers/tablehelper /components/console/helpers/table +/components/console/helpers/progresshelper /components/console/helpers/progressbar +/components/console/helpers/dialoghelper /components/console/helpers/questionhelper +/components/console/introduction /components/console +/components/console/index /components/console +/components/debug/class_loader /components/debug +/components/debug/introduction /components/debug +/components/debug/index /components/debug +/components/dependency_injection/advanced /service_container/alias_private +/components/dependency_injection/autowiring /service_container/autowiring +/components/dependency_injection/definitions /service_container/definitions +/components/dependency_injection/introduction /components/dependency_injection +/components/dependency_injection/index /components/dependency_injection +/components/dependency_injection/factories /service_container/factories +/components/dependency_injection/lazy_services /service_container/lazy_services +/components/dependency_injection/parameters /service_container/parameters +/components/dependency_injection/parentservices /service_container/parent_services +/components/dependency_injection/parent_services /service_container/parent_services +/components/dependency_injection/synthetic_services /service_container/synthetic_services +/components/dependency_injection/tags /service_container/tags +/components/dependency_injection/types /service_container/injection_types +/components/event_dispatcher/index /components/event_dispatcher +/components/event_dispatcher/introduction /components/event_dispatcher +/components/expression_language/introduction /components/expression_language +/components/expression_language/index /components/expression_language +/components/filesystem/introduction /components/filesystem +/components/filesystem/index /components/filesystem +/components/form/form_events /form/events +/components/form/introduction /components/form +/components/form/index /components/form +/components/form/type_guesser /form/type_guesser +/components/http_foundation/index /components/http_foundation +/components/http_foundation/introduction /components/http_foundation +/request/load_balancer_reverse_proxy /deployment/proxies +/components/http_foundation/trusting_proxies /deployment/proxies +/components/http_kernel/introduction /components/http_kernel +/components/http_kernel/index /components/http_kernel +/components/property_access/introduction /components/property_access +/components/property_access/index /components/property_access +/components/routing/index https://github.com/symfony/routing +/components/routing/introduction https://github.com/symfony/routing +/components/routing/hostname_pattern /routing/hostname_pattern +/components/security/introduction /components/security +/components/security/index /components/security +/components/templating/introduction https://github.com/symfony/templating +/components/templating/index https://github.com/symfony/templating +/components/templating/helpers/assetshelper https://github.com/symfony/templating +/components/templating/helpers/slotshelper https://github.com/symfony/templating +/components/translation/introduction /components/translation +/components/translation/index /components/translation +/components/var_dumper/introduction /components/var_dumper +/components/var_dumper/index /components/var_dumper +/components/yaml/introduction /components/yaml +/components/yaml/index /components/yaml +/console/logging /console +/controller/csrf_token_validation /security/csrf +/deployment/tools /deployment +/form/csrf_protection /security/csrf +/install/bundles /setup/bundles +/email/gmail /email +/email/cloud /email +/event_dispatcher/class_extension /event_dispatcher +/form /forms +/form/use_virtual_forms /form/inherit_data_option +/frontend/assetic /frontend/assetic/index +/frontend/assetic/apply_to_option /frontend/assetic/index +/frontend/assetic/asset_management /frontend/assetic/index +/frontend/assetic/jpeg_optimize /frontend/assetic/index +/frontend/assetic/php /frontend/assetic/index +/frontend/assetic/uglifyjs /frontend/assetic/index +/frontend/assetic/yuicompressor /frontend/assetic/index +/reference/configuration/assetic /frontend/assetic/index +/security/target_path /security +/security/csrf_in_login_form /security/csrf +/service_container/service_locators /service_container/service_subscribers_locators +/service_container/third_party /service_container +/templating/templating_service /templates +/testing/simulating_authentication /testing/http_authentication +/validation/group_service_resolver /form/validation_group_service_resolver +/request/load_balancer_reverse_proxy /deployment/proxies +/quick_tour/the_controller /quick_tour/the_big_picture +/quick_tour/the_view /quick_tour/flex_recipes +/service_container/service_locators /service_container/service_subscribers_locators +/templating/overriding /bundles/override +/templating/twig_extension /templates#templates-twig-extension +/templating/hinclude /templates#templates-hinclude +/templating/PHP /templates +/security/custom_provider /security/user_provider +/security/multiple_user_providers /security/user_provider +/security/custom_password_authenticator /security/guard_authentication +/security/api_key_authentication /security/guard_authentication +/security/pre_authenticated /security/auth_providers +/security/host_restriction /security/firewall_restriction +/security/acl_advanced /security/acl +/security/password_encoding /security +/weblink /web_link +/components/weblink https://github.com/symfony/web-link +/frontend/encore/installation-no-flex /frontend/encore/installation +/http_cache/form_csrf_caching /security/csrf +/console/logging /console +/reference/forms/twig_reference /form/form_customization +/form/rendering /form/form_customization +/profiler/matchers /profiler +/profiler/profiling_data /profiler +/profiler/wdt_follow_ajax /profiler +/security/entity_provider /security/user_provider +/session/avoid_session_start /session +/session/sessions_directory /session +/session/configuring_ttl /session#session-configure-ttl +/frontend/encore/legacy-apps /frontend/encore/legacy-applications +/configuration/external_parameters /configuration/environment_variables +/contributing/code/patches /contributing/code/pull_requests +/workflow/state-machines /workflow/workflow-and-state-machine +/workflow/introduction /workflow/workflow-and-state-machine +/workflow/usage /workflow +/introduction/from_flat_php_to_symfony2 /introduction/from_flat_php_to_symfony +/configuration/environment_variables /configuration/env_var_processors +/configuration/configuration_organization /configuration +/configuration/environments /configuration +/configuration/configuration_organization /configuration +/email/dev_environment /mailer +/email/spool /mailer +/email/testing /mailer +/contributing/community/other /contributing/community +/contributing/code/core_team /contributing/core_team +/profiler/storage /profiler +/setup/composer /setup +/security/security_checker /setup +/setup/built_in_web_server /setup/symfony_server +/service_container/parameters /configuration +/routing/generate_url_javascript /routing +/routing/slash_in_parameter /routing +/routing/scheme /routing +/routing/optional_placeholders /routing +/routing/conditions /routing +/routing/requirements /routing +/routing/redirect_trailing_slash /routing +/routing/debug /routing +/routing/service_container_parameters /routing +/routing/redirect_in_config /routing +/routing/external_resources /routing +/routing/hostname_pattern /routing +/routing/extra_information /routing +/console/request_context /routing +/form/action_method /forms +/reference/requirements /setup +/bundles/inheritance /bundles/override +/templating /templates +/templating/escaping /templates#output-escaping +/templating/syntax /templates#linting-twig-templates +/templating/debug /templates#the-dump-twig-utilities +/templating/render_without_controller /templates#rendering-a-template-directly-from-a-route +/templating/app_variable /templates#the-app-global-variable +/templating/formats /templates +/templating/namespaced_paths /templates#template-namespaces +/templating/embedding_controllers /templates#embedding-controllers +/templating/inheritance /templates#template-inheritance-and-layouts +/testing/doctrine /testing/database +/translation/templates /translation#translation-in-templates +/translation/debug /translation#translation-debug +/translation/lint /translation#translation-lint +/translation/locale /translation#translation-locale +/doctrine/lifecycle_callbacks /doctrine/events +/doctrine/event_listeners_subscribers /doctrine/events +/doctrine/common_extensions /doctrine +/best_practices/index /best_practices +/best_practices/introduction /best_practices +/best_practices/creating-the-project /best_practices +/best_practices/configuration /best_practices +/best_practices/business-logic /best_practices +/best_practices/controllers /best_practices +/best_practices/templates /best_practices +/best_practices/forms /best_practices +/best_practices/i18n /best_practices +/best_practices/security /best_practices +/best_practices/web-assets /best_practices +/best_practices/tests /best_practices +/components/debug https://github.com/symfony/debug +/components/translation https://github.com/symfony/translation +/components/translation/usage /translation +/components/translation/custom_formats https://github.com/symfony/translation +/components/translation/custom_message_formatter https://github.com/symfony/translation +/components/notifier https://github.com/symfony/notifier +/components/routing https://github.com/symfony/routing +/session/database /session#session-database +/doctrine/pdo_session_storage /session#session-database-pdo +/doctrine/mongodb_session_storage /session#session-database-mongodb +/components/dotenv https://github.com/symfony/dotenv +/components/mercure /mercure +/components/polyfill_apcu https://github.com/symfony/polyfill-apcu +/components/polyfill_ctype https://github.com/symfony/polyfill-ctype +/components/polyfill_iconv https://github.com/symfony/polyfill-iconv +/components/polyfill_intl_grapheme https://github.com/symfony/polyfill_intl-grapheme +/components/polyfill_intl_icu https://github.com/symfony/polyfill_intl-icu +/components/polyfill_intl_idn https://github.com/symfony/polyfill_intl-idn +/components/polyfill_intl_normalizer https://github.com/symfony/polyfill_intl-normalizer +/components/polyfill_mbstring https://github.com/symfony/polyfill-mbstring +/components/polyfill_php54 https://github.com/symfony/polyfill-php54 +/components/polyfill_php55 https://github.com/symfony/polyfill-php55 +/components/polyfill_php56 https://github.com/symfony/polyfill-php56 +/components/polyfill_php70 https://github.com/symfony/polyfill-php70 +/components/polyfill_php71 https://github.com/symfony/polyfill-php71 +/components/polyfill_php72 https://github.com/symfony/polyfill-php72 +/components/polyfill_php73 https://github.com/symfony/polyfill-php73 +/components/polyfill_uuid https://github.com/symfony/polyfill-uuid +/components/web_link https://github.com/symfony/web-link +/components/templating https://github.com/symfony/templating +/components/error_handler https://github.com/symfony/error-handler +/components/class_loader https://github.com/symfony/class-loader +/frontend/encore/versus-assetic /frontend +/components/http_client /http_client +/components/mailer /mailer +/messenger/message-recorder /messenger/dispatch_after_current_bus +/components/stopwatch https://github.com/symfony/stopwatch +/service_container/3.3-di-changes https://symfony.com/doc/3.4/service_container/3.3-di-changes.html +/frontend/encore/shared-entry /frontend/encore/split-chunks +/frontend/encore/page-specific-assets /frontend/encore/simple-example#page-specific-javascript-or-css +/testing/functional_tests_assertions /testing#testing-application-assertions +/components https://symfony.com/components +/components/index https://symfony.com/components +/serializer/normalizers /serializer#serializer-built-in-normalizers +/logging/monolog_regex_based_excludes /logging/monolog_exclude_http_codes +/security/named_encoders /security/named_hashers +/components/inflector /string#inflector +/security/experimental_authenticators /security +/security/user_provider /security/user_providers +/security/reset_password /security/passwords#reset-password +/security/auth_providers /security#security-authenticators +/security/form_login /security#form-login +/security/form_login_setup /security#form-login +/security/json_login_setup /security#json-login +/security/named_hashers /security/passwords#named-password-hashers +/security/password_migration /security/passwords#security-password-migration +/security/acl https://github.com/symfony/acl-bundle/blob/main/src/Resources/doc/index.rst +/security/securing_services /security#securing-other-services +/security/authenticator_manager /security +/security/multiple_guard_authenticators /security/entry_point +/security/guard_authentication /security/custom_authenticator +/components/security/authentication /security#authenticating-users +/components/security/authorization /security#access-control-authorization +/components/security/firewall /security#the-firewall +/components/security/secure_tools /security/passwords +/components/security /security +/components/var_dumper/advanced /components/var_dumper#advanced-usage +/components/yaml/yaml_format /reference/formats/yaml +/components/expression_language/syntax /reference/formats/expression_language +/components/expression_language/ast /components/expression_language#expression-language-ast +/components/expression_language/caching /components/expression_language#expression-language-caching +/components/expression_language/extending /components/expression_language#expression-language-extending +/notifier/chatters /notifier#sending-chat-messages +/notifier/texters /notifier#sending-sms +/notifier/events /notifier#notifier-events +/email /mailer +/frontend/assetic /frontend +/frontend/assetic/index /frontend +/controller/argument_value_resolver /controller/value_resolver +/frontend/ux https://symfony.com/bundles/StimulusBundle/current/index.html +/messenger/handler_results /messenger#messenger-getting-handler-results +/messenger/dispatch_after_current_bus /messenger#messenger-transactional-messages +/messenger/multiple_buses /messenger#messenger-multiple-buses +/frontend/encore/server-data /frontend/server-data +/components/string /string +/testing/http_authentication /testing#testing_logging_in_users +/doctrine/registration_form /security#security-make-registration-form +/form/form_dependencies /form/create_custom_field_type +/doctrine/reverse_engineering /doctrine#doctrine-adding-mapping +/components/serializer /serializer +/serializer/custom_encoder /serializer/encoders#serializer-custom-encoder diff --git a/_images/components/console/completion.gif b/_images/components/console/completion.gif new file mode 100644 index 00000000000..18b3f5475c8 Binary files /dev/null and b/_images/components/console/completion.gif differ diff --git a/_images/components/console/cursor.gif b/_images/components/console/cursor.gif new file mode 100644 index 00000000000..71a74dd8637 Binary files /dev/null and b/_images/components/console/cursor.gif differ diff --git a/_images/components/console/debug_formatter.png b/_images/components/console/debug_formatter.png new file mode 100644 index 00000000000..4ba2c0c2b57 Binary files /dev/null and b/_images/components/console/debug_formatter.png differ diff --git a/_images/components/console/process-helper-debug.png b/_images/components/console/process-helper-debug.png new file mode 100644 index 00000000000..96c5c316739 Binary files /dev/null and b/_images/components/console/process-helper-debug.png differ diff --git a/_images/components/console/process-helper-error-debug.png b/_images/components/console/process-helper-error-debug.png new file mode 100644 index 00000000000..48f6c7258d4 Binary files /dev/null and b/_images/components/console/process-helper-error-debug.png differ diff --git a/_images/components/console/process-helper-verbose.png b/_images/components/console/process-helper-verbose.png new file mode 100644 index 00000000000..abdff9812b0 Binary files /dev/null and b/_images/components/console/process-helper-verbose.png differ diff --git a/_images/components/console/progressbar.gif b/_images/components/console/progressbar.gif new file mode 100644 index 00000000000..0746e399354 Binary files /dev/null and b/_images/components/console/progressbar.gif differ diff --git a/_images/components/http_kernel/http-workflow-exception.svg b/_images/components/http_kernel/http-workflow-exception.svg new file mode 100644 index 00000000000..3330010367a --- /dev/null +++ b/_images/components/http_kernel/http-workflow-exception.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_images/components/http_kernel/http-workflow-subrequest.svg b/_images/components/http_kernel/http-workflow-subrequest.svg new file mode 100644 index 00000000000..4f4912dc5a1 --- /dev/null +++ b/_images/components/http_kernel/http-workflow-subrequest.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_images/components/http_kernel/http-workflow.svg b/_images/components/http_kernel/http-workflow.svg new file mode 100644 index 00000000000..f3bc7a9ee8b --- /dev/null +++ b/_images/components/http_kernel/http-workflow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/_images/components/messenger/basic_cycle.png b/_images/components/messenger/basic_cycle.png new file mode 100644 index 00000000000..a0558968cbb Binary files /dev/null and b/_images/components/messenger/basic_cycle.png differ diff --git a/_images/components/messenger/overview.svg b/_images/components/messenger/overview.svg new file mode 100644 index 00000000000..4b82c203756 --- /dev/null +++ b/_images/components/messenger/overview.svg @@ -0,0 +1 @@ + diff --git a/_images/components/scheduler/generate_consume.png b/_images/components/scheduler/generate_consume.png new file mode 100644 index 00000000000..269281266a5 Binary files /dev/null and b/_images/components/scheduler/generate_consume.png differ diff --git a/_images/components/scheduler/scheduler_cycle.png b/_images/components/scheduler/scheduler_cycle.png new file mode 100644 index 00000000000..18addb37d91 Binary files /dev/null and b/_images/components/scheduler/scheduler_cycle.png differ diff --git a/_images/components/string/bytes-points-graphemes.png b/_images/components/string/bytes-points-graphemes.png new file mode 100644 index 00000000000..18d971cecf7 Binary files /dev/null and b/_images/components/string/bytes-points-graphemes.png differ diff --git a/_images/components/var_dumper/01-simple.png b/_images/components/var_dumper/01-simple.png new file mode 100644 index 00000000000..a4d03147667 Binary files /dev/null and b/_images/components/var_dumper/01-simple.png differ diff --git a/_images/components/var_dumper/02-multi-line-str.png b/_images/components/var_dumper/02-multi-line-str.png new file mode 100644 index 00000000000..b40949bd981 Binary files /dev/null and b/_images/components/var_dumper/02-multi-line-str.png differ diff --git a/_images/components/var_dumper/03-object.png b/_images/components/var_dumper/03-object.png new file mode 100644 index 00000000000..47fc5e5e245 Binary files /dev/null and b/_images/components/var_dumper/03-object.png differ diff --git a/_images/components/var_dumper/04-dynamic-property.png b/_images/components/var_dumper/04-dynamic-property.png new file mode 100644 index 00000000000..de7938c20cf Binary files /dev/null and b/_images/components/var_dumper/04-dynamic-property.png differ diff --git a/_images/components/var_dumper/05-soft-ref.png b/_images/components/var_dumper/05-soft-ref.png new file mode 100644 index 00000000000..964af97ffd3 Binary files /dev/null and b/_images/components/var_dumper/05-soft-ref.png differ diff --git a/_images/components/var_dumper/06-constants.png b/_images/components/var_dumper/06-constants.png new file mode 100644 index 00000000000..26c735bd613 Binary files /dev/null and b/_images/components/var_dumper/06-constants.png differ diff --git a/_images/components/var_dumper/07-hard-ref.png b/_images/components/var_dumper/07-hard-ref.png new file mode 100644 index 00000000000..02dc17c9c40 Binary files /dev/null and b/_images/components/var_dumper/07-hard-ref.png differ diff --git a/_images/components/var_dumper/08-virtual-property.png b/_images/components/var_dumper/08-virtual-property.png new file mode 100644 index 00000000000..564a2731ec1 Binary files /dev/null and b/_images/components/var_dumper/08-virtual-property.png differ diff --git a/_images/components/var_dumper/09-cut.png b/_images/components/var_dumper/09-cut.png new file mode 100644 index 00000000000..5229f48820c Binary files /dev/null and b/_images/components/var_dumper/09-cut.png differ diff --git a/_images/components/var_dumper/10-uninitialized.png b/_images/components/var_dumper/10-uninitialized.png new file mode 100644 index 00000000000..735731b83b5 Binary files /dev/null and b/_images/components/var_dumper/10-uninitialized.png differ diff --git a/_images/components/workflow/blogpost.png b/_images/components/workflow/blogpost.png new file mode 100644 index 00000000000..b7f51eabb43 Binary files /dev/null and b/_images/components/workflow/blogpost.png differ diff --git a/_images/components/workflow/blogpost_mermaid.png b/_images/components/workflow/blogpost_mermaid.png new file mode 100644 index 00000000000..7a4d3a57cfe Binary files /dev/null and b/_images/components/workflow/blogpost_mermaid.png differ diff --git a/_images/components/workflow/blogpost_metadata.png b/_images/components/workflow/blogpost_metadata.png new file mode 100644 index 00000000000..783f51c6ccf Binary files /dev/null and b/_images/components/workflow/blogpost_metadata.png differ diff --git a/_images/components/workflow/blogpost_puml.png b/_images/components/workflow/blogpost_puml.png new file mode 100644 index 00000000000..efe543a6f8e Binary files /dev/null and b/_images/components/workflow/blogpost_puml.png differ diff --git a/_images/components/workflow/job_application.png b/_images/components/workflow/job_application.png new file mode 100644 index 00000000000..9c5e6792ae9 Binary files /dev/null and b/_images/components/workflow/job_application.png differ diff --git a/_images/components/workflow/pull_request.png b/_images/components/workflow/pull_request.png new file mode 100644 index 00000000000..692a95345ae Binary files /dev/null and b/_images/components/workflow/pull_request.png differ diff --git a/_images/components/workflow/pull_request_puml_styled.png b/_images/components/workflow/pull_request_puml_styled.png new file mode 100644 index 00000000000..cda9233d731 Binary files /dev/null and b/_images/components/workflow/pull_request_puml_styled.png differ diff --git a/_images/components/workflow/simple.png b/_images/components/workflow/simple.png new file mode 100644 index 00000000000..ed158d5cc7a Binary files /dev/null and b/_images/components/workflow/simple.png differ diff --git a/_images/components/workflow/states_transitions.png b/_images/components/workflow/states_transitions.png new file mode 100644 index 00000000000..d1f54391afd Binary files /dev/null and b/_images/components/workflow/states_transitions.png differ diff --git a/_images/contributing/code/stack-trace.gif b/_images/contributing/code/stack-trace.gif new file mode 100644 index 00000000000..97a2043448d Binary files /dev/null and b/_images/contributing/code/stack-trace.gif differ diff --git a/_images/contributing/docs-github-create-pr.png b/_images/contributing/docs-github-create-pr.png new file mode 100644 index 00000000000..43b6842ffc2 Binary files /dev/null and b/_images/contributing/docs-github-create-pr.png differ diff --git a/_images/contributing/docs-github-edit-page.png b/_images/contributing/docs-github-edit-page.png new file mode 100644 index 00000000000..b739497f70f Binary files /dev/null and b/_images/contributing/docs-github-edit-page.png differ diff --git a/_images/contributing/docs-pull-request-change-base.png b/_images/contributing/docs-pull-request-change-base.png new file mode 100644 index 00000000000..791901b8ec6 Binary files /dev/null and b/_images/contributing/docs-pull-request-change-base.png differ diff --git a/_images/controller/error_pages/errors-in-prod-environment.png b/_images/controller/error_pages/errors-in-prod-environment.png new file mode 100644 index 00000000000..808d0d70028 Binary files /dev/null and b/_images/controller/error_pages/errors-in-prod-environment.png differ diff --git a/_images/controller/error_pages/exceptions-in-dev-environment.png b/_images/controller/error_pages/exceptions-in-dev-environment.png new file mode 100644 index 00000000000..e1fba2bebf9 Binary files /dev/null and b/_images/controller/error_pages/exceptions-in-dev-environment.png differ diff --git a/_images/deployment/azure-website/step-01.png b/_images/deployment/azure-website/step-01.png new file mode 100644 index 00000000000..ef60db66ab2 Binary files /dev/null and b/_images/deployment/azure-website/step-01.png differ diff --git a/_images/deployment/azure-website/step-02.png b/_images/deployment/azure-website/step-02.png new file mode 100644 index 00000000000..fe38cf45be3 Binary files /dev/null and b/_images/deployment/azure-website/step-02.png differ diff --git a/_images/deployment/azure-website/step-03.png b/_images/deployment/azure-website/step-03.png new file mode 100644 index 00000000000..6fc0789cac9 Binary files /dev/null and b/_images/deployment/azure-website/step-03.png differ diff --git a/_images/deployment/azure-website/step-04.png b/_images/deployment/azure-website/step-04.png new file mode 100644 index 00000000000..a16d8f07a86 Binary files /dev/null and b/_images/deployment/azure-website/step-04.png differ diff --git a/_images/deployment/azure-website/step-05.png b/_images/deployment/azure-website/step-05.png new file mode 100644 index 00000000000..8da32f7ab67 Binary files /dev/null and b/_images/deployment/azure-website/step-05.png differ diff --git a/_images/deployment/azure-website/step-06.png b/_images/deployment/azure-website/step-06.png new file mode 100644 index 00000000000..067ff4e767a Binary files /dev/null and b/_images/deployment/azure-website/step-06.png differ diff --git a/_images/deployment/azure-website/step-07.png b/_images/deployment/azure-website/step-07.png new file mode 100644 index 00000000000..7acffd2c782 Binary files /dev/null and b/_images/deployment/azure-website/step-07.png differ diff --git a/_images/deployment/azure-website/step-08.png b/_images/deployment/azure-website/step-08.png new file mode 100644 index 00000000000..cb106db5c02 Binary files /dev/null and b/_images/deployment/azure-website/step-08.png differ diff --git a/_images/deployment/azure-website/step-09.png b/_images/deployment/azure-website/step-09.png new file mode 100644 index 00000000000..5005531fb09 Binary files /dev/null and b/_images/deployment/azure-website/step-09.png differ diff --git a/_images/deployment/azure-website/step-10.png b/_images/deployment/azure-website/step-10.png new file mode 100644 index 00000000000..e9a7d8fdff8 Binary files /dev/null and b/_images/deployment/azure-website/step-10.png differ diff --git a/_images/deployment/azure-website/step-11.png b/_images/deployment/azure-website/step-11.png new file mode 100644 index 00000000000..48b1c2992e1 Binary files /dev/null and b/_images/deployment/azure-website/step-11.png differ diff --git a/_images/deployment/azure-website/step-12.png b/_images/deployment/azure-website/step-12.png new file mode 100644 index 00000000000..85f8f54d142 Binary files /dev/null and b/_images/deployment/azure-website/step-12.png differ diff --git a/_images/deployment/azure-website/step-13.png b/_images/deployment/azure-website/step-13.png new file mode 100644 index 00000000000..49aac465fd7 Binary files /dev/null and b/_images/deployment/azure-website/step-13.png differ diff --git a/_images/deployment/azure-website/step-14.png b/_images/deployment/azure-website/step-14.png new file mode 100644 index 00000000000..8e6c3ed3a5e Binary files /dev/null and b/_images/deployment/azure-website/step-14.png differ diff --git a/_images/deployment/azure-website/step-15.png b/_images/deployment/azure-website/step-15.png new file mode 100644 index 00000000000..c8d5bce96d3 Binary files /dev/null and b/_images/deployment/azure-website/step-15.png differ diff --git a/_images/deployment/azure-website/step-16.png b/_images/deployment/azure-website/step-16.png new file mode 100644 index 00000000000..da7d4bebde7 Binary files /dev/null and b/_images/deployment/azure-website/step-16.png differ diff --git a/_images/doctrine/doctrine_web_debug_toolbar.png b/_images/doctrine/doctrine_web_debug_toolbar.png new file mode 100644 index 00000000000..8103162e591 Binary files /dev/null and b/_images/doctrine/doctrine_web_debug_toolbar.png differ diff --git a/_images/doctrine/mapping_relations.svg b/_images/doctrine/mapping_relations.svg new file mode 100644 index 00000000000..7dc8979cb1a --- /dev/null +++ b/_images/doctrine/mapping_relations.svg @@ -0,0 +1,602 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/doctrine/mapping_relations_proxy.svg b/_images/doctrine/mapping_relations_proxy.svg new file mode 100644 index 00000000000..634d1b0add2 --- /dev/null +++ b/_images/doctrine/mapping_relations_proxy.svg @@ -0,0 +1,926 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/doctrine/mapping_single_entity.svg b/_images/doctrine/mapping_single_entity.svg new file mode 100644 index 00000000000..5d517c85fb1 --- /dev/null +++ b/_images/doctrine/mapping_single_entity.svg @@ -0,0 +1,469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/form/data-transformer-types.svg b/_images/form/data-transformer-types.svg new file mode 100644 index 00000000000..9393b224f89 --- /dev/null +++ b/_images/form/data-transformer-types.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/form/form-custom-type-postal-address-fragment-names.svg b/_images/form/form-custom-type-postal-address-fragment-names.svg new file mode 100644 index 00000000000..db9463b8327 --- /dev/null +++ b/_images/form/form-custom-type-postal-address-fragment-names.svg @@ -0,0 +1 @@ + diff --git a/_images/form/form-custom-type-postal-address.svg b/_images/form/form-custom-type-postal-address.svg new file mode 100644 index 00000000000..42ffce4067f --- /dev/null +++ b/_images/form/form-custom-type-postal-address.svg @@ -0,0 +1 @@ + diff --git a/_images/form/form-field-parts.svg b/_images/form/form-field-parts.svg new file mode 100644 index 00000000000..c9856c89a99 --- /dev/null +++ b/_images/form/form-field-parts.svg @@ -0,0 +1 @@ + diff --git a/_images/form/form_prepopulation_workflow.svg b/_images/form/form_prepopulation_workflow.svg new file mode 100644 index 00000000000..c908f5c5a76 --- /dev/null +++ b/_images/form/form_prepopulation_workflow.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/form/form_submission_workflow.svg b/_images/form/form_submission_workflow.svg new file mode 100644 index 00000000000..d6d138ee61a --- /dev/null +++ b/_images/form/form_submission_workflow.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/form/form_workflow.svg b/_images/form/form_workflow.svg new file mode 100644 index 00000000000..2dbacbbf096 --- /dev/null +++ b/_images/form/form_workflow.svg @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/form/simple-form-2.png b/_images/form/simple-form-2.png new file mode 100644 index 00000000000..d50028fc1f7 Binary files /dev/null and b/_images/form/simple-form-2.png differ diff --git a/_images/form/simple-form.png b/_images/form/simple-form.png new file mode 100644 index 00000000000..1dced444561 Binary files /dev/null and b/_images/form/simple-form.png differ diff --git a/_images/form/tailwindcss-form.png b/_images/form/tailwindcss-form.png new file mode 100644 index 00000000000..8a290749149 Binary files /dev/null and b/_images/form/tailwindcss-form.png differ diff --git a/_images/http/request-flow.svg b/_images/http/request-flow.svg new file mode 100644 index 00000000000..97061ada0d5 --- /dev/null +++ b/_images/http/request-flow.svg @@ -0,0 +1 @@ + diff --git a/_images/http/xkcd-full.svg b/_images/http/xkcd-full.svg new file mode 100644 index 00000000000..da590c2b97e --- /dev/null +++ b/_images/http/xkcd-full.svg @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/http/xkcd-request.svg b/_images/http/xkcd-request.svg new file mode 100644 index 00000000000..6a21280ca34 --- /dev/null +++ b/_images/http/xkcd-request.svg @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/install/deprecations-in-profiler.png b/_images/install/deprecations-in-profiler.png new file mode 100644 index 00000000000..3d3f9a98a4a Binary files /dev/null and b/_images/install/deprecations-in-profiler.png differ diff --git a/_images/mercure/chrome.png b/_images/mercure/chrome.png new file mode 100644 index 00000000000..8ccc55a0a88 Binary files /dev/null and b/_images/mercure/chrome.png differ diff --git a/_images/mercure/discovery.svg b/_images/mercure/discovery.svg new file mode 100644 index 00000000000..ed18381068a --- /dev/null +++ b/_images/mercure/discovery.svg @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/mercure/hub.svg b/_images/mercure/hub.svg new file mode 100644 index 00000000000..6b5e496e3c6 --- /dev/null +++ b/_images/mercure/hub.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/mercure/panel.png b/_images/mercure/panel.png new file mode 100644 index 00000000000..22b214f5ff2 Binary files /dev/null and b/_images/mercure/panel.png differ diff --git a/_images/notifier/microsoft_teams/message-card.png b/_images/notifier/microsoft_teams/message-card.png new file mode 100644 index 00000000000..05f505fb3e0 Binary files /dev/null and b/_images/notifier/microsoft_teams/message-card.png differ diff --git a/_images/notifier/microsoft_teams/message.png b/_images/notifier/microsoft_teams/message.png new file mode 100644 index 00000000000..5c4c7f11ed1 Binary files /dev/null and b/_images/notifier/microsoft_teams/message.png differ diff --git a/_images/notifier/slack/field-method.png b/_images/notifier/slack/field-method.png new file mode 100644 index 00000000000..d77a60e6a2e Binary files /dev/null and b/_images/notifier/slack/field-method.png differ diff --git a/_images/notifier/slack/message-reply.png b/_images/notifier/slack/message-reply.png new file mode 100644 index 00000000000..9a60e4573ab Binary files /dev/null and b/_images/notifier/slack/message-reply.png differ diff --git a/_images/notifier/slack/slack-footer.png b/_images/notifier/slack/slack-footer.png new file mode 100644 index 00000000000..a53952c78f6 Binary files /dev/null and b/_images/notifier/slack/slack-footer.png differ diff --git a/_images/notifier/slack/slack-header.png b/_images/notifier/slack/slack-header.png new file mode 100644 index 00000000000..a7caf915d8f Binary files /dev/null and b/_images/notifier/slack/slack-header.png differ diff --git a/_images/profiler/web-interface.png b/_images/profiler/web-interface.png new file mode 100644 index 00000000000..b107f6427d7 Binary files /dev/null and b/_images/profiler/web-interface.png differ diff --git a/_images/quick_tour/no_routes_page.png b/_images/quick_tour/no_routes_page.png new file mode 100644 index 00000000000..030953a17b1 Binary files /dev/null and b/_images/quick_tour/no_routes_page.png differ diff --git a/_images/rate_limiter/fixed_window.svg b/_images/rate_limiter/fixed_window.svg new file mode 100644 index 00000000000..83d5f6e79ac --- /dev/null +++ b/_images/rate_limiter/fixed_window.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + 10:00 + + + 10:30 + + + 11:00 + + + 11:30 + + + 12:00 + + + + + + + + 12:30 + + + 13:00 + + + + + + + + + + + + + + + + + + + + + + 1 hour window + + + 1 hour window + + + + + + 1 hour window + + + + + 13:15 + + + diff --git a/_images/rate_limiter/sliding_window.svg b/_images/rate_limiter/sliding_window.svg new file mode 100644 index 00000000000..2c565615441 --- /dev/null +++ b/_images/rate_limiter/sliding_window.svg @@ -0,0 +1,65 @@ + + + + + + + + + + 10:00 + + + 10:30 + + + 11:00 + + + 11:30 + + + 12:00 + + + + + + 12:30 + + + 13:00 + + + + + + + + + + + + + + + + + + + + + + 1 hour window + + + + + + 13:15 + + + + + + diff --git a/_images/rate_limiter/token_bucket.svg b/_images/rate_limiter/token_bucket.svg new file mode 100644 index 00000000000..29d6fc8f103 --- /dev/null +++ b/_images/rate_limiter/token_bucket.svg @@ -0,0 +1,83 @@ + + + + 10:00 + + + 10:30 + + + 11:00 + + + 11:30 + + + 12:00 + + + + + + + + 12:30 + + + 13:00 + + + + + + + + + + + + + + + + + + + + + + + + + + + 13:15 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/reference/form/choice-example1.png b/_images/reference/form/choice-example1.png new file mode 100644 index 00000000000..00e47d0bb27 Binary files /dev/null and b/_images/reference/form/choice-example1.png differ diff --git a/_images/reference/form/choice-example2.png b/_images/reference/form/choice-example2.png new file mode 100644 index 00000000000..147d82bcfca Binary files /dev/null and b/_images/reference/form/choice-example2.png differ diff --git a/_images/reference/form/choice-example3.png b/_images/reference/form/choice-example3.png new file mode 100644 index 00000000000..232f8519fee Binary files /dev/null and b/_images/reference/form/choice-example3.png differ diff --git a/_images/reference/form/choice-example4.png b/_images/reference/form/choice-example4.png new file mode 100644 index 00000000000..7f6071d3532 Binary files /dev/null and b/_images/reference/form/choice-example4.png differ diff --git a/_images/reference/form/choice-example5.png b/_images/reference/form/choice-example5.png new file mode 100644 index 00000000000..188eeeec234 Binary files /dev/null and b/_images/reference/form/choice-example5.png differ diff --git a/_images/security/anonymous_wdt.png b/_images/security/anonymous_wdt.png new file mode 100644 index 00000000000..80736afce39 Binary files /dev/null and b/_images/security/anonymous_wdt.png differ diff --git a/_images/security/authentication-guard-methods.svg b/_images/security/authentication-guard-methods.svg new file mode 100644 index 00000000000..cc042656212 --- /dev/null +++ b/_images/security/authentication-guard-methods.svg @@ -0,0 +1 @@ + diff --git a/_images/security/login_link_email.png b/_images/security/login_link_email.png new file mode 100644 index 00000000000..8331b878f68 Binary files /dev/null and b/_images/security/login_link_email.png differ diff --git a/_images/security/profiler-badges.png b/_images/security/profiler-badges.png new file mode 100644 index 00000000000..a19f8539581 Binary files /dev/null and b/_images/security/profiler-badges.png differ diff --git a/_images/security/security_events.svg b/_images/security/security_events.svg new file mode 100644 index 00000000000..f1b93923da6 --- /dev/null +++ b/_images/security/security_events.svg @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/security/symfony_loggedin_wdt.png b/_images/security/symfony_loggedin_wdt.png new file mode 100644 index 00000000000..b51e1cafba1 Binary files /dev/null and b/_images/security/symfony_loggedin_wdt.png differ diff --git a/_images/serializer/serializer_workflow.svg b/_images/serializer/serializer_workflow.svg new file mode 100644 index 00000000000..b6e9c254778 --- /dev/null +++ b/_images/serializer/serializer_workflow.svg @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_images/sources/README.md b/_images/sources/README.md new file mode 100644 index 00000000000..84810a9783d --- /dev/null +++ b/_images/sources/README.md @@ -0,0 +1,102 @@ +How to Create Symfony Images +============================ + +Creating Diagrams +----------------- + +* Use [Dia][1] as the diagramming application; +* Use [PT Sans Narrow][2] as the only font in all diagrams (if possible, use + only the "normal" weight for all contents); +* Use 36pt as the base font size; +* Use 0.10 cm width for lines and shape borders; +* Use the following color palette: + * Text, lines and shape borders: black (#000000) + * Shape backgrounds: + * Grays: dark (#4d4d4d), medium (#b3b3b3), light (#f2f2f2) + * Blue: #b2d4eb + * Red: #ecbec0 + * Green: #b2dec7 + * Orange: #fddfbb + +In case of doubt, check the existing diagrams or ask to the +[Symfony Documentation Team][3]. + +### Saving and Exporting the Diagram + +* Save the original diagram in `*.dia` format in `_images/sources/`; +* Export the diagram to SVG format and save it in `_images/`. + +Important: choose "Cairo Scalable Vector Graphics (.svg)" format instead of +plain " Scalable Vector Graphics (.svg)" because the former is the only format +that transforms text into vector shapes (resulting file is larger in size, but +it's truly portable because text is displayed the same even if you don't have +some fonts installed). + +### Including the Diagram in the Symfony Docs + +Use the following snippet to embed the diagram in the docs: + +``` +.. raw:: html + + +``` + +### Reasoning + +* Dia was chosen because it's one of the few applications which are free, open + source and compatible with Linux, macOS and Windows. +* Font, colors and line widths were chosen to be similar to the diagrams used + in the best tech books. + +### Troubleshooting + +* On some macOS systems, Dia cannot be executed as a regular application and + you must run the following console command instead: + `export DISPLAY=:0 && /Applications/Dia.app/Contents/Resources/bin/dia` + +Creating Console Screenshots +---------------------------- + +* Use [Asciinema][4] to record the console session locally: + + ``` + $ asciinema rec -c bash recording.cast + ``` +* Use `$ ` as the prompt in recordings. E.g. if you're using Bash, add the + following lines to your ``.bashrc``: + + ``` + if [ "$ASCIINEMA_REC" = "1" ]; then + PS1="\e[37m$ \e[0m" + fi + ``` +* Save the generated asciicast in `_images/sources/`. + +### Rendering the Recording + +Rendering the recording can be a difficult task. The [documentation team][3] +is always ready to help you with this task (e.g. you can open a PR with +only the asciicast file). + +* Use [agg][5] to generated a GIF file from the recording; +* Install the [JetBrains Mono][6] font; +* Use the ``_images/sources/ascii-render.sh`` file to call agg: + + ``` + AGG_PATH=/path/to/agg ./_images/sources/ascii-render.sh recording.cast --cols 45 --rows 20 + ``` + + This utility configures a predefined theme; +* Always configure `--cols`` (width) and ``--rows`` (height), try to use as + low as possible numbers. Do not exceed 70 columns; +* Save the generated GIF file in `_images/`. + +[1]: http://dia-installer.de/ +[2]: https://fonts.google.com/specimen/PT+Sans+Narrow +[3]: https://symfony.com/doc/current/contributing/core_team.html +[4]: https://github.com/asciinema/asciinema +[5]: https://github.com/asciinema/agg +[6]: https://www.jetbrains.com/lp/mono/ diff --git a/_images/sources/ascii-render.sh b/_images/sources/ascii-render.sh new file mode 100755 index 00000000000..e72be572390 --- /dev/null +++ b/_images/sources/ascii-render.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +case "$1" in + ''|help|-h) + echo "ansi-render.sh RECORDING [options]" + echo "" + echo " RECORDING: path to the .cast file generated by asciinema" + echo " [options]: optional options to be passed to agg" + ;; + *) + recording=$1 + extra_options= + if [ $# -gt 1 ]; then + shift + extra_options=$@ + fi + + # optionally, use this green color: 1f4631 + ${AGG_PATH:-agg} \ + --theme 18202a,f9fafb,f9fafb,ff7b72,7ee787,ffa657,79c0ff,d2a8ff,a5d6ff,f9fafb,8b949e,ff7b72,00c300,ffa657,79c0ff,d2a8ff,a5d6ff,f9fafb --line-height 1.6 \ + --font-family 'JetBrains Mono' \ + $extra_options \ + $recording $(echo $recording | sed "s/cast/gif/") + ;; +esac diff --git a/_images/sources/components/console/completion.cast b/_images/sources/components/console/completion.cast new file mode 100644 index 00000000000..c268863e9b0 --- /dev/null +++ b/_images/sources/components/console/completion.cast @@ -0,0 +1,37 @@ +{"version": 2, "width": 76, "height": 30, "timestamp": 1663253713, "env": {"SHELL": "/usr/bin/fish", "TERM": "st-256color"}} +[0.00798, "o", "\u001b[?2004h\u001b[90m$ \u001b[0m"] +[0.614685, "o", "b"] +[0.776549, "o", "i"] +[0.86682, "o", "n"] +[1.092426, "o", "/"] +[1.332671, "o", "c"] +[1.55068, "o", "o"] +[1.630651, "o", "n"] +[1.784584, "o", "s"] +[1.873108, "o", "o"] +[2.074652, "o", "l"] +[2.180433, "o", "e"] +[2.260475, "o", " "] +[2.696628, "o", "\u0007"] +[2.947263, "o", "\r\nabout debug:event-dispatcher\r\nassets:install debug:router\r\ncache:clear help\r\ncache:pool:clear lint:container\r\ncache:pool:delete lint:yaml\r\ncache:pool:list list\r\ncache:pool:prune router:match\r\ncache:warmup secrets:decrypt-to-local\r\ncompletion secrets:encrypt-from-local\r\nconfig:dump-reference secrets:generate-keys\r\ndebug:autowiring secrets:list\r\ndebug:config secrets:remove\r\ndebug:container secrets:set\r\ndebug:dotenv \r\n\u001b[37m$ \u001b[0mbin/console "] +[3.614479, "o", "s"] +[3.802449, "o", "e"] +[4.205631, "o", "\u0007crets:"] +[4.520435, "o", "r"] +[4.598031, "o", "e"] +[5.026287, "o", "move "] +[5.47041, "o", "\u0007SOME_"] +[5.673941, "o", "\u0007"] +[6.024086, "o", "\r\nSOME_OTHER_SECRET SOME_SECRET \r\n\u001b[37m$ \u001b[0mbin/console secrets:remove SOME_"] +[6.770627, "o", "O"] +[7.14335, "o", "THER_SECRET "] +[7.724482, "o", "\r\n\u001b[?2004l\r"] +[7.776657, "o", "\r\n"] +[7.779108, "o", "\u001b[30;42m \u001b[39;49m\r\n\u001b[30;42m [OK] Secret \"SOME_OTHER_SECRET\" removed from \"config/secrets/dev/\". \u001b[39;49m\r\n\u001b[30;42m \u001b[39;49m\r\n\r\n"] +[7.782993, "o", "\u001b[?2004h\u001b[37m$ \u001b[0m"] +[9.214537, "o", "e"] +[9.522429, "o", "x"] +[9.690371, "o", "i"] +[9.85446, "o", "t"] +[10.292412, "o", "\r\n\u001b[?2004l\r"] +[10.292526, "o", "exit\r\n"] diff --git a/_images/sources/components/console/cursor.cast b/_images/sources/components/console/cursor.cast new file mode 100644 index 00000000000..be2f2f6c351 --- /dev/null +++ b/_images/sources/components/console/cursor.cast @@ -0,0 +1,49 @@ +{"version": 2, "width": 191, "height": 30, "timestamp": 1663251833, "env": {"SHELL": "/usr/bin/fish", "TERM": "st-256color"}} +[0.007941, "o", "\u001b[?2004h\u001b[90m$ \u001b[0m"] +[0.566363, "o", "c"] +[0.643353, "o", "l"] +[0.762325, "o", "e"] +[0.952363, "o", "a"] +[0.995878, "o", "r"] +[1.107784, "o", "\r\n\u001b[?2004l\r"] +[1.109766, "o", "\u001b[H\u001b[2J"] +[1.109946, "o", "\u001b[?2004h\u001b[30m$ \u001b[0m"] +[1.653461, "o", "p"] +[1.772323, "o", "h"] +[1.856444, "o", "p"] +[1.980339, "o", " "] +[2.15827, "o", "c"] +[2.273242, "o", "u"] +[2.402231, "o", "r"] +[2.563066, "o", "s"] +[2.760266, "o", "o"] +[2.900252, "o", "r"] +[3.020537, "o", "."] +[3.316404, "o", "p"] +[3.403213, "o", "h"] +[3.483391, "o", "p"] +[3.820273, "o", "\r\n\u001b[?2004l\r"] +[3.845697, "o", "\u001b[6;9H#"] +[4.045942, "o", "\u001b[8;9H#"] +[4.246327, "o", "\u001b[8;2H#####"] +[4.446737, "o", "\u001b[2;9H#######"] +[4.647128, "o", "\u001b[7;7H#"] +[4.84749, "o", "\u001b[3;9H#"] +[5.047857, "o", "\u001b[7;9H#"] +[5.248246, "o", "\u001b[4;9H#"] +[5.448622, "o", "\u001b[2;2H#####"] +[5.648999, "o", "\u001b[3;7H#"] +[5.849378, "o", "\u001b[5;9H#####"] +[6.049711, "o", "\u001b[3;1H#"] +[6.250118, "o", "\u001b[7;1H#"] +[6.45056, "o", "\u001b[5;2H#####"] +[6.650897, "o", "\u001b[4;1H#"] +[6.851281, "o", "\u001b[6;7H#"] +[7.051644, "o", "\u001b[9;1H"] +[7.058802, "o", "\u001b[?2004h\u001b[30m$ \u001b[0m"] +[7.657612, "o", "e"] +[7.846956, "o", "x"] +[7.949451, "o", "i"] +[8.0893, "o", "t"] +[8.201144, "o", "\r\n\u001b[?2004l\r"] +[8.201227, "o", "exit\r\n"] diff --git a/_images/sources/components/console/progress.cast b/_images/sources/components/console/progress.cast new file mode 100644 index 00000000000..9c5244b37e2 --- /dev/null +++ b/_images/sources/components/console/progress.cast @@ -0,0 +1,57 @@ +{"version": 2, "width": 191, "height": 17, "timestamp": 1663423221, "env": {"SHELL": "/usr/bin/fish", "TERM": "st-256color"}} +[0.008171, "o", "\u001b[?2004h\u001b[90m$ \u001b[0m"] +[0.385858, "o", "p"] +[0.577979, "o", "h"] +[0.768282, "o", "p"] +[0.96433, "o", " "] +[1.133645, "o", "p"] +[1.262693, "o", "r"] +[1.385832, "o", "o"] +[1.476876, "o", "g"] +[1.652322, "o", "r"] +[1.722357, "o", "e"] +[1.935395, "o", "s"] +[2.083915, "o", "s"] +[2.200109, "o", "."] +[2.403686, "o", "p"] +[2.510201, "o", "h"] +[2.602756, "o", "p"] +[2.909974, "o", "\r\n\u001b[?2004l\r"] +[2.935647, "o", "\u001b[34m Starting the demo... fingers crossed \u001b[39m\r\n 0/15 \u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 0%\r\n  < 1 sec 4.0 MiB"] +[3.418022, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K"] +[3.419196, "o", "\u001b[34m Starting the demo... fingers crossed \u001b[39m\r\n 2/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 13%\r\n  < 1 sec 6.0 MiB"] +[3.66102, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G"] +[3.661071, "o", "\u001b[2K"] +[3.661731, "o", "\u001b[34m Starting the demo... fingers crossed \u001b[39m\r\n 3/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 20%\r\n  5 secs 6.0 MiB"] +[4.143554, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K"] +[4.14385, "o", "\u001b[34m Starting the demo... fingers crossed \u001b[39m\r\n 5/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 33%\r\n  3 secs 6.5 MiB"] +[4.385367, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K"] +[4.38612, "o", "\u001b[34m Looks good to me... \u001b[39m\r\n 6/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 40%\r\n  3 secs 7.1 MiB"] +[4.868053, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K"] +[4.86852, "o", "\u001b[34m Looks good to me... \u001b[39m\r\n 8/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 53%\r\n  4 secs 8.1 MiB"] +[5.110341, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K"] +[5.11133, "o", "\u001b[34m Looks good to me... \u001b[39m\r\n 9/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 60%\r\n  3 secs 8.6 MiB"] +[5.593851, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G"] +[5.593924, "o", "\u001b[2K"] +[5.594818, "o", "\u001b[34m Looks good to me... \u001b[39m\r\n11/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 73%\r\n  4 secs 9.6 MiB"] +[5.836301, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K"] +[5.836831, "o", "\u001b[34m Looks good to me... \u001b[39m\r\n12/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m\u001b[41m \u001b[49m 80%\r\n  4 secs 10.1 MiB"] +[6.31877, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K\u001b[1A"] +[6.318814, "o", "\u001b[1G\u001b[2K"] +[6.319403, "o", "\u001b[34m Looks good to me... \u001b[39m\r\n14/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[32;41m\u001b[39;49m\u001b[41m \u001b[49m 93%\r\n  3 secs 11.1 MiB"] +[6.561359, "o", "\u001b[1G\u001b[2K\u001b[1A"] +[6.561561, "o", "\u001b[1G\u001b[2K\u001b[1A\u001b[1G\u001b[2K"] +[6.562504, "o", "\u001b[34m Looks good to me... \u001b[39m\r\n15/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m 100%\r\n  4 secs 11.6 MiB"] +[6.563772, "o", "\u001b[1G"] +[6.563824, "o", "\u001b[2K\u001b[1A"] +[6.563875, "o", "\u001b[1G\u001b[2K"] +[6.563926, "o", "\u001b[1A\u001b[1G\u001b[2K"] +[6.564766, "o", "\u001b[34m Thanks bye! \u001b[39m\r\n15/15 \u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m\u001b[42m \u001b[49m 100%\r\n  4 secs 11.6 MiB"] +[6.564805, "o", "\r\n\r\n"] +[6.570516, "o", "\u001b[?2004h"] +[6.570537, "o", "\u001b[90m$ \u001b[0m"] +[8.441927, "o", "e"] +[8.646449, "o", "x"] +[8.76668, "o", "i"] +[8.897799, "o", "t"] +[9.091614, "o", "\r\n\u001b[?2004l\rexit\r\n"] diff --git a/_images/sources/components/messenger/overview.dia b/_images/sources/components/messenger/overview.dia new file mode 100644 index 00000000000..b0e2edaeab2 Binary files /dev/null and b/_images/sources/components/messenger/overview.dia differ diff --git a/_images/sources/doctrine/mapping_relations.dia b/_images/sources/doctrine/mapping_relations.dia new file mode 100644 index 00000000000..5703e1b781c Binary files /dev/null and b/_images/sources/doctrine/mapping_relations.dia differ diff --git a/_images/sources/doctrine/mapping_relations_proxy.dia b/_images/sources/doctrine/mapping_relations_proxy.dia new file mode 100644 index 00000000000..1f491e9e2ef Binary files /dev/null and b/_images/sources/doctrine/mapping_relations_proxy.dia differ diff --git a/_images/sources/doctrine/mapping_single_entity.dia b/_images/sources/doctrine/mapping_single_entity.dia new file mode 100644 index 00000000000..5a9dc21889c Binary files /dev/null and b/_images/sources/doctrine/mapping_single_entity.dia differ diff --git a/_images/sources/form/data-transformer-types.dia b/_images/sources/form/data-transformer-types.dia new file mode 100644 index 00000000000..972b973a36d Binary files /dev/null and b/_images/sources/form/data-transformer-types.dia differ diff --git a/_images/sources/form/form-custom-type-postal-address-fragment-names.dia b/_images/sources/form/form-custom-type-postal-address-fragment-names.dia new file mode 100644 index 00000000000..ca12fcdeadc Binary files /dev/null and b/_images/sources/form/form-custom-type-postal-address-fragment-names.dia differ diff --git a/_images/sources/form/form-custom-type-postal-address.dia b/_images/sources/form/form-custom-type-postal-address.dia new file mode 100644 index 00000000000..1b7c6226315 Binary files /dev/null and b/_images/sources/form/form-custom-type-postal-address.dia differ diff --git a/_images/sources/form/form-field-parts.dia b/_images/sources/form/form-field-parts.dia new file mode 100644 index 00000000000..d6ed2dfc3fe Binary files /dev/null and b/_images/sources/form/form-field-parts.dia differ diff --git a/_images/sources/form/form_events.dia b/_images/sources/form/form_events.dia new file mode 100644 index 00000000000..8e7afb1cb83 Binary files /dev/null and b/_images/sources/form/form_events.dia differ diff --git a/_images/sources/form/form_prepopulation_workflow.dia b/_images/sources/form/form_prepopulation_workflow.dia new file mode 100644 index 00000000000..1d6d450fed1 Binary files /dev/null and b/_images/sources/form/form_prepopulation_workflow.dia differ diff --git a/_images/sources/form/form_submission_workflow.dia b/_images/sources/form/form_submission_workflow.dia new file mode 100644 index 00000000000..cc08f117878 Binary files /dev/null and b/_images/sources/form/form_submission_workflow.dia differ diff --git a/_images/sources/form/form_workflow.dia b/_images/sources/form/form_workflow.dia new file mode 100644 index 00000000000..30f9acabe2b Binary files /dev/null and b/_images/sources/form/form_workflow.dia differ diff --git a/_images/sources/http/request-flow.dia b/_images/sources/http/request-flow.dia new file mode 100644 index 00000000000..ca09a05504e Binary files /dev/null and b/_images/sources/http/request-flow.dia differ diff --git a/_images/sources/http/xkcd-full.dia b/_images/sources/http/xkcd-full.dia new file mode 100644 index 00000000000..a730d01c3ef Binary files /dev/null and b/_images/sources/http/xkcd-full.dia differ diff --git a/_images/sources/http/xkcd-request.dia b/_images/sources/http/xkcd-request.dia new file mode 100644 index 00000000000..3796228bf1d Binary files /dev/null and b/_images/sources/http/xkcd-request.dia differ diff --git a/_images/sources/http_kernel/http-workflow.dia b/_images/sources/http_kernel/http-workflow.dia new file mode 100644 index 00000000000..2b84bc46aec Binary files /dev/null and b/_images/sources/http_kernel/http-workflow.dia differ diff --git a/_images/sources/mercure/discovery.dia b/_images/sources/mercure/discovery.dia new file mode 100644 index 00000000000..3db5c86f020 Binary files /dev/null and b/_images/sources/mercure/discovery.dia differ diff --git a/_images/sources/mercure/hub.dia b/_images/sources/mercure/hub.dia new file mode 100644 index 00000000000..b0dfb9d88d2 Binary files /dev/null and b/_images/sources/mercure/hub.dia differ diff --git a/_images/sources/rate_limiter/fixed_window.dia b/_images/sources/rate_limiter/fixed_window.dia new file mode 100644 index 00000000000..16282a2dcce Binary files /dev/null and b/_images/sources/rate_limiter/fixed_window.dia differ diff --git a/_images/sources/rate_limiter/sliding_window.dia b/_images/sources/rate_limiter/sliding_window.dia new file mode 100644 index 00000000000..e16275d8995 Binary files /dev/null and b/_images/sources/rate_limiter/sliding_window.dia differ diff --git a/_images/sources/rate_limiter/token_bucket.dia b/_images/sources/rate_limiter/token_bucket.dia new file mode 100644 index 00000000000..16761971337 Binary files /dev/null and b/_images/sources/rate_limiter/token_bucket.dia differ diff --git a/_images/sources/security/authentication-guard-methods.dia b/_images/sources/security/authentication-guard-methods.dia new file mode 100644 index 00000000000..d655be780fe Binary files /dev/null and b/_images/sources/security/authentication-guard-methods.dia differ diff --git a/_images/sources/security/security_events.dia b/_images/sources/security/security_events.dia new file mode 100644 index 00000000000..0a8afa73179 Binary files /dev/null and b/_images/sources/security/security_events.dia differ diff --git a/_images/sources/serializer/serializer_workflow.dia b/_images/sources/serializer/serializer_workflow.dia new file mode 100644 index 00000000000..3e2ea62558f Binary files /dev/null and b/_images/sources/serializer/serializer_workflow.dia differ diff --git a/_images/translation/pseudolocalization-interface-original.png b/_images/translation/pseudolocalization-interface-original.png new file mode 100644 index 00000000000..d89f4e63a24 Binary files /dev/null and b/_images/translation/pseudolocalization-interface-original.png differ diff --git a/_images/translation/pseudolocalization-interface-translated.png b/_images/translation/pseudolocalization-interface-translated.png new file mode 100644 index 00000000000..496d5a0f86f Binary files /dev/null and b/_images/translation/pseudolocalization-interface-translated.png differ diff --git a/_images/translation/pseudolocalization-symfony-demo-disabled.png b/_images/translation/pseudolocalization-symfony-demo-disabled.png new file mode 100644 index 00000000000..1a7472bd41f Binary files /dev/null and b/_images/translation/pseudolocalization-symfony-demo-disabled.png differ diff --git a/_images/translation/pseudolocalization-symfony-demo-enabled.png b/_images/translation/pseudolocalization-symfony-demo-enabled.png new file mode 100644 index 00000000000..a23300a7271 Binary files /dev/null and b/_images/translation/pseudolocalization-symfony-demo-enabled.png differ diff --git a/_includes/_rewrite_rule_tip.rst.inc b/_includes/_rewrite_rule_tip.rst.inc new file mode 100644 index 00000000000..fe69882c4f7 --- /dev/null +++ b/_includes/_rewrite_rule_tip.rst.inc @@ -0,0 +1,6 @@ +.. tip:: + + By using rewrite rules in your + :doc:`web server configuration `, + the ``index.php`` won't be needed and you will have beautiful, clean URLs + (e.g. ``/show``). diff --git a/best_practices.rst b/best_practices.rst new file mode 100644 index 00000000000..2c393cae9c6 --- /dev/null +++ b/best_practices.rst @@ -0,0 +1,460 @@ +The Symfony Framework Best Practices +==================================== + +This article describes the **best practices for developing web applications with +Symfony** that fit the philosophy envisioned by the original Symfony creators. + +If you don't agree with some of these recommendations, they might be a good +**starting point** that you can then **extend and fit to your specific needs**. +You can even ignore them completely and continue using your own best practices +and methodologies. Symfony is flexible enough to adapt to your needs. + +This article assumes that you already have experience developing Symfony +applications. If you don't, read first the :doc:`Getting Started ` +section of the documentation. + +.. tip:: + + Symfony provides a sample application called `Symfony Demo`_ that follows + all these best practices, so you can experience them in practice. + +Creating the Project +-------------------- + +Use the Symfony Binary to Create Symfony Applications +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Symfony binary is an executable command created in your machine when you +`download Symfony`_. It provides multiple utilities, including the simplest way +to create new Symfony applications: + +.. code-block:: terminal + + $ symfony new my_project_directory + +Under the hood, this Symfony binary command executes the needed `Composer`_ +command to :ref:`create a new Symfony application ` +based on the current stable version. + +Use the Default Directory Structure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Unless your project follows a development practice that imposes a certain +directory structure, follow the default Symfony directory structure. It's flat, +self-explanatory and not coupled to Symfony: + +.. code-block:: text + + your_project/ + ├─ assets/ + ├─ bin/ + │ └─ console + ├─ config/ + │ ├─ packages/ + │ ├─ routes/ + │ └─ services.yaml + ├─ migrations/ + ├─ public/ + │ ├─ build/ + │ └─ index.php + ├─ src/ + │ ├─ Kernel.php + │ ├─ Command/ + │ ├─ Controller/ + │ ├─ DataFixtures/ + │ ├─ Entity/ + │ ├─ EventSubscriber/ + │ ├─ Form/ + │ ├─ Repository/ + │ ├─ Security/ + │ └─ Twig/ + ├─ templates/ + ├─ tests/ + ├─ translations/ + ├─ var/ + │ ├─ cache/ + │ └─ log/ + └─ vendor/ + +Configuration +------------- + +Use Environment Variables for Infrastructure Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The values of these options change from one machine to another (e.g. from your +development machine to the production server), but they don't modify the +application behavior. + +:ref:`Use env vars in your project ` to define these options +and create multiple ``.env`` files to :ref:`configure env vars per environment `. + +.. _use-secret-for-sensitive-information: + +Use Secrets for Sensitive Information +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When your application has sensitive configuration, like an API key, you should +store those securely via :doc:`Symfony’s secrets management system `. + +Use Parameters for Application Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These are the options used to modify the application behavior, such as the sender +of email notifications, or the enabled `feature toggles`_. Their value doesn't +change per machine, so don't define them as environment variables. + +Define these options as :ref:`parameters ` in the +``config/services.yaml`` file. You can override these options per +:ref:`environment ` in the ``config/services_dev.yaml`` +and ``config/services_prod.yaml`` files. + +Unless the application configuration is reused multiple times and needs +rigid validation, do *not* use the :doc:`Config component ` +to define the options. + +Use Short and Prefixed Parameter Names +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider using ``app.`` as the prefix of your :ref:`parameters ` +to avoid collisions with Symfony and third-party bundles/libraries parameters. +Then, use just one or two words to describe the purpose of the parameter: + +.. code-block:: yaml + + # config/services.yaml + parameters: + # don't do this: 'dir' is too generic, and it doesn't convey any meaning + app.dir: '...' + # do this: short but easy to understand names + app.contents_dir: '...' + # it's OK to use dots, underscores, dashes or nothing, but always + # be consistent and use the same format for all the parameters + app.dir.contents: '...' + app.contents-dir: '...' + +Use Constants to Define Options that Rarely Change +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Configuration options like the number of items to display in some listing rarely +change. Instead of defining them as :ref:`configuration parameters `, +define them as PHP constants in the related classes. Example:: + + // src/Entity/Post.php + namespace App\Entity; + + class Post + { + public const NUMBER_OF_ITEMS = 10; + + // ... + } + +The main advantage of constants is that you can use them everywhere, including +Twig templates and Doctrine entities, whereas parameters are only available +from places with access to the :doc:`service container `. + +The only notable disadvantage of using constants for this kind of configuration +values is that it's complicated to redefine their values in your tests. + +Business Logic +-------------- + +.. _best-practice-no-application-bundles: + +Don't Create any Bundle to Organize your Application Logic +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When Symfony 2.0 was released, applications used :doc:`bundles ` to +divide their code into logical features: UserBundle, ProductBundle, +InvoiceBundle, etc. However, a bundle is meant to be something that can be +reused as a stand-alone piece of software. + +If you need to reuse some feature in your projects, create a bundle for it (in a +private repository, do not make it publicly available). For the rest of your +application code, use PHP namespaces to organize code instead of bundles. + +Use Autowiring to Automate the Configuration of Application Services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:doc:`Service autowiring ` is a feature that +reads the type-hints on your constructor (or other methods) and automatically +passes the correct services to each method, making it unnecessary to configure +services explicitly and simplifying the application maintenance. + +Use it in combination with :ref:`service autoconfiguration ` +to also add :doc:`service tags ` to the services +needing them, such as Twig extensions, event subscribers, etc. + +Services Should be Private Whenever Possible +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Make services private ` to prevent you from accessing +those services via ``$container->get()``. Instead, you will need to use proper +dependency injection. + +Use the YAML Format to Configure your own Services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you use the :ref:`default services.yaml configuration `, +most services will be configured automatically. However, in some edge cases +you'll need to configure services (or parts of them) manually. + +YAML is the format recommended configuring services because it's friendly to +newcomers and concise, but Symfony also supports XML and PHP configuration. + +Use Attributes to Define the Doctrine Entity Mapping +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Doctrine entities are plain PHP objects that you store in some "database". +Doctrine only knows about your entities through the mapping metadata configured +for your model classes. + +Doctrine supports several metadata formats, but it's recommended to use PHP +attributes because they are by far the most convenient and agile way of setting +up and looking for mapping information. + +Controllers +----------- + +Make your Controller Extend the ``AbstractController`` Base Controller +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Symfony provides a :ref:`base controller ` +which includes shortcuts for the most common needs such as rendering templates +or checking security permissions. + +Extending your controllers from this base controller couples your application +to Symfony. Coupling is generally wrong, but it may be OK in this case because +controllers shouldn't contain any business logic. Controllers should contain +nothing more than a few lines of *glue-code*, so you are not coupling the +important parts of your application. + +.. _best-practice-controller-annotations: +.. _best-practice-controller-attributes: + +Use Attributes to Configure Routing, Caching, and Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using attributes for routing, caching, and security simplifies +configuration. You don't need to browse several files created with different +formats (YAML, XML, PHP): all the configuration is just where you require it, +and it only uses one format. + +Use Dependency Injection to Get Services +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you extend the base ``AbstractController``, you can only get access to the most +common services (e.g ``twig``, ``router``, ``doctrine``, etc.), directly from the +container via ``$this->container->get()``. +Instead, you must use dependency injection to fetch services by +:ref:`type-hinting action method arguments ` or +constructor arguments. + +Use Entity Value Resolvers If They Are Convenient +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're using :doc:`Doctrine `, then you can *optionally* use +the :ref:`EntityValueResolver ` to +automatically query for an entity and pass it as an argument to your +controller. It will also show a 404 page if no entity can be found. + +If the logic to get an entity from a route variable is more complex, instead of +configuring the EntityValueResolver, it's better to make the Doctrine query +inside the controller (e.g. by calling to a :doc:`Doctrine repository method `). + +Templates +--------- + +Use Snake Case for Template Names and Variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use lowercase snake_case for template names, directories, and variables (e.g. +``user_profile`` instead of ``userProfile`` and ``product/edit_form.html.twig`` +instead of ``Product/EditForm.html.twig``). + +Prefix Template Fragments with an Underscore +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Template fragments, also called *"partial templates"*, allow to +:ref:`reuse template contents `. Prefix their names +with an underscore to better differentiate them from complete templates (e.g. +``_user_metadata.html.twig`` or ``_caution_message.html.twig``). + +Forms +----- + +Define your Forms as PHP Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Creating :ref:`forms in classes ` allows reusing +them in different parts of the application. Besides, not creating forms in +controllers simplifies the code and maintenance of the controllers. + +Add Form Buttons in Templates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Form classes should be agnostic to where they will be used. For example, the +button of a form used to both create and edit items should change from "Add new" +to "Save changes" depending on where it's used. + +Instead of adding buttons in form classes or the controllers, it's recommended +to add buttons in the templates. This also improves the separation of concerns +because the button styling (CSS class and other attributes) is defined in the +template instead of in a PHP class. + +However, if you create a :doc:`form with multiple submit buttons ` +you should define them in the controller instead of the template. Otherwise, you +won't be able to check which button was clicked when handling the form in the controller. + +Define Validation Constraints on the Underlying Object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Attaching :doc:`validation constraints ` to form fields +instead of to the mapped object prevents the validation from being reused in +other forms or other places where the object is used. + +.. _best-practice-handle-form: + +Use a Single Action to Render and Process the Form +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:ref:`Rendering forms ` and :ref:`processing forms ` +are two of the main tasks when handling forms. Both are too similar (most of the +time, almost identical), so it's much simpler to let a single controller action +handle both. + +.. _best-practice-internationalization: + +Internationalization +-------------------- + +Use the XLIFF Format for Your Translation Files +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Of all the translation formats supported by Symfony (PHP, Qt, ``.po``, ``.mo``, +JSON, CSV, INI, etc.), ``XLIFF`` and ``gettext`` have the best support in the tools used +by professional translators. And since it's based on XML, you can validate ``XLIFF`` +file contents as you write them. + +Symfony also supports notes in XLIFF files, making them more user-friendly for +translators. At the end, good translations are all about context, and these +XLIFF notes allow you to define that context. + +Use Keys for Translations Instead of Content Strings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using keys simplifies the management of the translation files because you can +change the original contents in templates, controllers, and services without +having to update all the translation files. + +Keys should always describe their *purpose* and *not* their location. For +example, if a form has a field with the label "Username", then a nice key +would be ``label.username``, *not* ``edit_form.label.username``. + +Security +-------- + +Define a Single Firewall +~~~~~~~~~~~~~~~~~~~~~~~~ + +Unless you have two legitimately different authentication systems and users +(e.g. form login for the main site and a token system for your API only), it's +recommended to have only one firewall to keep things simple. + +Additionally, you should use the ``anonymous`` key under your firewall. If you +require users to be logged in for different sections of your site, use the +:doc:`access_control ` option. + +Use the ``auto`` Password Hasher +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :ref:`auto password hasher ` automatically +selects the best possible encoder/hasher depending on your PHP installation. +Currently, the default auto hasher is ``bcrypt``. + +Use Voters to Implement Fine-grained Security Restrictions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your security logic is complex, you should create custom +:doc:`security voters ` instead of defining long expressions +inside the ``#[Security]`` attribute. + +Web Assets +---------- + +.. _use-webpack-encore-to-process-web-assets: + +Use AssetMapper to Manage Web Assets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Web assets are the CSS, JavaScript, and image files that make the frontend of +your site look and work great. :doc:`AssetMapper ` lets +you write modern JavaScript and CSS without the complexity of using a bundler +such as `Webpack`_ (directly or via :doc:`Webpack Encore `). + +Tests +----- + +Smoke Test your URLs +~~~~~~~~~~~~~~~~~~~~ + +In software engineering, `smoke testing`_ consists of *"preliminary testing to +reveal simple failures severe enough to reject a prospective software release"*. +Using `PHPUnit data providers`_ you can define a functional test that +checks that all application URLs load successfully:: + + // tests/ApplicationAvailabilityFunctionalTest.php + namespace App\Tests; + + use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + + class ApplicationAvailabilityFunctionalTest extends WebTestCase + { + /** + * @dataProvider urlProvider + */ + public function testPageIsSuccessful($url): void + { + $client = self::createClient(); + $client->request('GET', $url); + + $this->assertResponseIsSuccessful(); + } + + public function urlProvider(): \Generator + { + yield ['/']; + yield ['/posts']; + yield ['/post/fixture-post-1']; + yield ['/blog/category/fixture-category']; + yield ['/archives']; + // ... + } + } + +Add this test while creating your application because it requires little effort +and checks that none of your pages returns an error. Later, you'll add more +specific tests for each page. + +.. _hardcode-urls-in-a-functional-test: + +Hard-code URLs in a Functional Test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In Symfony applications, it's recommended to :ref:`generate URLs ` +using routes to automatically update all links when a URL changes. However, if a +public URL changes, users won't be able to browse it unless you set up a +redirection to the new URL. + +That's why it's recommended to use raw URLs in tests instead of generating them +from routes. Whenever a route changes, tests will fail, and you'll know that +you must set up a redirection. + +.. _`Symfony Demo`: https://github.com/symfony/demo +.. _`download Symfony`: https://symfony.com/download +.. _`Composer`: https://getcomposer.org/ +.. _`feature toggles`: https://en.wikipedia.org/wiki/Feature_toggle +.. _`smoke testing`: https://en.wikipedia.org/wiki/Smoke_testing_(software) +.. _`Webpack`: https://webpack.js.org/ +.. _`PHPUnit data providers`: https://docs.phpunit.de/en/9.6/writing-tests-for-phpunit.html#data-providers diff --git a/book/bundles.rst b/book/bundles.rst deleted file mode 100644 index f63d0d4e7b0..00000000000 --- a/book/bundles.rst +++ /dev/null @@ -1,236 +0,0 @@ -.. index:: - single: Bundles; Best Practices - -Bundles -======= - -A bundle is a directory that has a well-defined structure and can host anything -from classes to controllers and web resources. Even if bundles are very -flexible, you should follow some best practices if you want to distribute them. - -.. index:: - pair: Bundles; Naming Conventions - -.. _bundles-naming-conventions: - -Bundle Name ------------ - -A bundle is also a PHP namespace. The namespace must follow the technical -interoperability `standards`_ for PHP 5.3 namespaces and class names: it -starts with a vendor segment, followed by zero or more category segments, and -it ends with the namespace short name, which must end with a ``Bundle`` -suffix. - -A namespace becomes a bundle as soon as you add a bundle class to it. The -bundle class name must follow these simple rules: - -* Use only alphanumeric characters and underscores; -* Use a CamelCased name; -* Use a descriptive and short name (no more than 2 words); -* Prefix the name with the concatenation of the vendor (and optionally the - category namespaces); -* Suffix the name with ``Bundle``. - -Here are some valid bundle namespaces and class names: - -=================================== ============================== -Namespace Bundle Class Name -=================================== ============================== -``Sensio\Bundle\BlogBundle`` ``SensioBlogBundle`` -``Sensio\Bundle\Social\BlogBundle`` ``SensioSocialBlogBundle`` -``Sensio\BlogBundle`` ``SensioBlogBundle`` -=================================== ============================== - -By convention, the ``getName()`` method of the bundle class should return the -class name. - -Directory Structure -------------------- - -The basic directory structure of a ``HelloBundle`` bundle must read as -follows: - -.. code-block:: text - - XXX/... - HelloBundle/ - HelloBundle.php - Controller/ - Resources/ - meta/ - LICENSE - config/ - doc/ - index.rst - translations/ - views/ - public/ - Tests/ - -The ``XXX`` directory(ies) reflects the namespace structure of the bundle. - -The following files are mandatory: - -* ``HelloBundle.php``; -* ``Resources/meta/LICENSE``: The full license for the code; -* ``Resources/doc/index.rst``: The root file for the Bundle documentation. - -.. note:: - - These conventions ensure that automated tools can rely on this default - structure to work. - -The depth of sub-directories should be kept to the minimal for most used -classes and files (2 levels at a maximum). More levels can be defined for -non-strategic, less-used files. - -The bundle directory is read-only. If you need to write temporary files, store -them under the ``cache/`` or ``log/`` directory of the host application. Tools -can generate files in the bundle directory structure, but only if the generated -files are going to be part of the repository. - -The following classes and files have specific emplacements: - -========================= =========================== -Type Directory -========================= =========================== -Controllers ``Controller/`` -Translation files ``Resources/translations/`` -Templates ``Resources/views/`` -Unit and Functional Tests ``Tests/`` -Web Resources ``Resources/public/`` -Configuration ``Resources/config/`` -Commands ``Command/`` -========================= =========================== - -Classes -------- - -The bundle directory structure is used as the namespace hierarchy. For -instance, a ``HelloController`` controller is stored in -``Bundle/HelloBundle/Controller/HelloController.php`` and the fully qualified -class name is ``Bundle\HelloBundle\Controller\HelloController``. - -All classes and files must follow the Symfony2 coding :doc:`standards -`. - -Some classes should be seen as facades and should be as short as possible, like -Commands, Helpers, Listeners, and Controllers. - -Classes that connects to the Event Dispatcher should be suffixed with -``Listener``. - -Exceptions classes should be stored in an ``Exception`` sub-namespace. - -Vendors -------- - -A bundle must not embed third-party PHP libraries. It should rely on the -standard Symfony2 autoloading instead. - -A bundle should not embed third-party libraries written in JavaScript, CSS, or -any other language. - -Tests ------ - -A bundle should come with a test suite written with PHPUnit and stored under -the ``Tests/`` directory. Tests should follow the following principles: - -* The test suite must be executable with a simple ``phpunit`` command run from - a sample application; -* The functional tests should only be used to test the response output and - some profiling information if you have some; -* The code coverage should at least covers 95% of the code base. - -.. note:: - A test suite must not contain ``AllTests.php`` scripts, but must rely on the - existence of a ``phpunit.xml.dist`` file. - -Documentation -------------- - -All classes and functions must come with full PHPDoc. - -Extensive documentation should also be provided in the :doc:`reStructuredText -` format, under the ``Resources/doc/`` -directory; the ``Resources/doc/index.rst`` file is the only mandatory file. - -Controllers ------------ - -Controllers in a bundle must not extend -:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller`. They can -implement -:class:`Symfony\\Foundation\\DependencyInjection\\ContainerAwareInterface` or -extend :class:`Symfony\\Foundation\\DependencyInjection\\ContainerAware` -instead. - -.. note:: - - If you have a look at - :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` methods, - you will see that they are only nice shortcuts to ease the learning curve. - -Templates ---------- - -If a bundle provides templates, they must use Twig. A bundle must not provide -a main layout, except if it provides a full working application. - -Translation Files ------------------ - -If a bundle provides message translations, they must be defined in the XLIFF -format; the domain should be named after the bundle name (``bundle.hello``). - -A bundle must not override existing messages from another bundle. - -Configuration -------------- - -To provide more flexibility, a bundle can provide configurable settings by -using the Symfony2 built-in mechanisms. - -For simple configuration settings, rely on the default ``parameters`` entry of -the Symfony2 configuration. Symfony2 parameters are simple key/value pairs; a -value being any valid PHP value. Each parameter name must start with a -lower-cased version of the bundle name (``hello`` for ``HelloBundle``, or -``sensio.social.blog`` for ``Sensio\Social\BlogBundle`` for instance). - -The end user can provide values in any configuration file: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - parameters: - hello.email.from: fabien@example.com - - .. code-block:: xml - - - - fabien@example.com - - - .. code-block:: php - - // app/config/config.php - $container->setParameter('hello.email.from', 'fabien@example.com'); - - .. code-block:: ini - - [parameters] - hello.email.from = fabien@example.com - -Retrieve the configuration parameters in your code from the container:: - - $container->getParameter('hello.email.from'); - -Even if this mechanism is simple enough, you are highly encouraged to use the -semantic configuration described in the cookbook. - -.. _standards: http://groups.google.com/group/php-standards/web/psr-0-final-proposal diff --git a/book/controller.rst b/book/controller.rst deleted file mode 100644 index 52f3c3118d9..00000000000 --- a/book/controller.rst +++ /dev/null @@ -1,704 +0,0 @@ -.. index:: - single: Controller - -The Controller -============== - -A controller is a PHP function you create that takes information from the -HTTP request and constructs and returns an HTTP response (as a Symfony2 -``Response`` object). The response could be the an HTML page, an XML document, -a serialized JSON array, an image, a redirect, a 404 error or anything else -you can dream up. The controller contains whatever arbitrary logic *your -application* needs to create that response. - -Along the way, your controller might read information from the request, load -a database resource, send an email, or set information on the user's session. -But in all cases, the controller's final job is to return the ``Response`` -object that will be delivered back to the client. There's no magic and no -other requirements to worry about. Here are a few common examples: - -* *Controller A* prepares a ``Response`` object representing the content - for the homepage of the site. - -* *Controller B* reads the ``slug`` parameter from the request to load a - blog entry from the database and create a ``Response`` object displaying - that blog. If the ``slug`` can't be found in the database, it creates and - returns a ``Response`` object with a 404 status code. - -* *Controller C* handles the form submission of a contact form. It reads - the form information from the request, saves the contact information to - the database and emails the contact information to the webmaster. Finally, - it creates a ``Response`` object that redirects the client's browser to - the contact form "thank you" page. - -.. index:: - single: Controller; Request-controller-response lifecycle - -Requests, Controller, Response Lifecycle ----------------------------------------- - -Every request handled by a Symfony2 project goes through the same basic lifecycle. -The framework takes care of the repetitive tasks and ultimately executes a -controller, which houses your custom application code: - -* Each request is handled by a single front controller file (e.g. ``app.php`` - or ``index.php``) that's responsible for bootstrapping the framework; - -* The ``Router`` reads the request information, matches that information to - a specific route, and determines from that route which controller should - be called; - -* The controller is executed and the code inside the controller creates and - returns a ``Response`` object; - -* The HTTP headers and content of the ``Response`` object are sent back to - the client. - -Creating a page is as easy as creating a controller and making a route that -maps a URI to that controller. - -.. note:: - - Though similarly named, a "front controller" is different from the - "controllers" we'll talk about in this guide. A front controller - is a short PHP file that lives in your web directory and through which - all requests are directed. A typical application will have a production - front controller (e.g. ``app.php``) and a development front controller - (e.g. ``app_dev.php``). You'll likely never need to edit, view or worry - about the front controllers in your application. - -.. index:: - single: Controller; Simple example - -A Simple Controller -------------------- - -The controller is a PHP callable responsible for returning a representation -of the resource (most of the time an HTML representation). Though a controller -can be any PHP callable (a function, a method on an object, or a ``Closure``), -in Symfony2, a controller is usually a single method inside a controller -object. Controllers are also called *actions*. - -.. code-block:: php - - // src/Sensio/HelloBundle/Controller/HelloController.php - - namespace Sensio\HelloBundle\Controller; - use Symfony\Component\HttpFoundation\Response; - - class HelloController - { - public function indexAction($name) - { - return new Response('Hello '.$name.'!'); - } - } - -.. tip:: - - Note that the *controller* is the ``indexAction`` method, which lives - inside a *controller class* (``HelloController``). Don't be confused - by the naming: a *controller class* is simply a convenient way to group - several controllers together. Typically, the controller class will house - several controllers (e.g. ``updateAction``, ``deleteAction``, etc). A - controller is also sometimes referred to as an *action*. - -This controller is pretty straightforward, but let's walk through it: - -* *line 3*: Symfony2 takes advantage of PHP 5.3 namespace functionality to - namespace the entire controller class. The ``use`` keyword imports the - ``Response`` class, which our controller must return. - -* *line 6*: The class name is the concatenation of a name for the controller - class and the word ``Controller``. This is a convention that provides consistency - to controllers and allows them to be referenced only by the first part of - the name (i.e. ``Hello``) in the routing configuration. - -* *line 8*: Each action in a controller class is suffixed with ``Action`` - and is referenced in the routing configuration by the action's name (``index``). - In the next section, we'll use a route to map a URI to this action and - show how the route's placeholders (``{name}``) become arguments on the - action (``$name``). - -* *line 10*: The controller creates and returns a ``Response`` object. - -.. index:: - single: Controller; Routes and controllers - -Mapping a URI to a Controller ------------------------------ - -Our new controller returns a simple HTML page. To render this controller -at a specific URL, we need to create a route to it. - -We'll talk about the ``Routing`` component in detail in the :doc:`Routing guide`, -but let's create a simple route to our controller: - -.. configuration-block:: - - .. code-block:: yaml - - # src/Sensio/HelloBundle/Resources/config/routing.yml - hello: - pattern: /hello/{name} - defaults: { _controller: HelloBundle:Hello:index } - - .. code-block:: xml - - - - HelloBundle:Hello:index - - - .. code-block:: php - - // src/Sensio/HelloBundle/Resources/config/routing.php - $collection->add('hello', new Route('/hello/{name}', array( - '_controller' => 'HelloBundle:Hello:index', - ))); - -Going to ``/hello/ryan`` now executes the ``HelloController::indexAction()`` -controller and passes in ``ryan`` for the ``$name`` variable. Creating a -"page" means simply creating a controller method and associated route. There's -no hidden layers or behind-the-scenes magic. - -Notice the syntax used to refer to the controller: ``HelloBundle:Hello:index``. -Symfony2 uses a flexible string notation to refer to different controllers. -This is the most common syntax and tells Symfony2 to look for a controller -class called ``HelloController`` inside a bundle named ``HelloBundle``. The -method ``indexAction()`` is then executed. - -For more details on the string format used to reference different controllers, -see :ref:`controller-string-syntax`. - -.. tip:: - - Notice that since our controller lives in the ``HelloBundle``, we've - placed the routing configuration inside the ``HelloBundle`` to stay - organized. To load routing configuration that lives inside a bundle, it - must be imported from your application's main routing resource. See - :ref:`routing-include-external-resources` for more information. - -.. index:: - single: Controller; Route parameters as controller arguments - -.. _route-parameters-controller-arguments: - -Route Parameters as Controller Arguments -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We already know now that the ``_controller`` parameter ``HelloBundle:Hello:index`` -refers to a ``HelloController::indexAction()`` method that lives inside the -``HelloBundle`` bundle. What's more interesting is the arguments that are -passed to that method: - -.. code-block:: php - - - - HelloBundle:Hello:index - green - - - .. code-block:: php - - // src/Sensio/HelloBundle/Resources/config/routing.php - $collection->add('hello', new Route('/hello/{first_name}/{last_name}', array( - '_controller' => 'HelloBundle:Hello:index', - 'color' => 'green', - ))); - -The controller for this can take several arguments:: - - public function indexAction($first_name, $last_name, $color) - { - // ... - } - -Notice that both placeholder variables (``{{first_name}}``, ``{{last_name}}``) -as well as the default ``color`` variable are available as arguments in the -controller. When a route is matched, the placeholder variables are merged -with the ``defaults`` to make one array that's available to your controller. - -Mapping route parameters to controller arguments is easy and flexible. Keep -the following guidelines in mind while you develop. - -The order of the controller arguments does not matter. -...................................................... - -Symfony2 is able to matches the parameter names from the route to the variable -names in the controller method's signature. In other words, it realizes that -the ``last_name`` parameter matches up with the ``$last_name`` argument. -The arguments of the controller could be totally reordered and still work -perfectly:: - - public function indexAction($last_name, $color, $first_name) - { - // .. - } - -Each required controller argument must match up with a routing parameter. -......................................................................... - -The following would throw a ``RuntimeException`` because there is no ``foo`` -parameter defined in the route:: - - public function indexAction($first_name, $last_name, $color, $foo) - { - // .. - } - -Making the argument optional, however, is perfectly ok. The following -example would not throw an exception:: - - public function indexAction($first_name, $last_name, $color, $foo = 'bar') - { - // .. - } - -Not all routing parameters need to be arguments on your controller. -................................................................... - -If, for example, the ``last_name`` weren't important for your controller, -you could omit it entirely:: - - public function indexAction($first_name, $color) - { - // .. - } - -In fact, the ``_controller`` route parameter itself is technically available -as a controller argument since it's in the ``defaults`` of the route. Of -course, it's generally not very useful, so it's omitted from our controller. - -.. tip:: - Every route also has a special ``_route`` parameter, which is equal to - the name of the route that was matched (e.g. ``hello``). Though not usually - useful, this is equally available as a controller argument. - -The Base Controller Class -------------------------- - -For convenience, Symfony2 comes with a base ``Controller`` class that assists -with some of the most common controller tasks and gives your controller class -access to any resource it might need. By extending this ``Controller`` class, -you can take advantage of several helper methods. - -Add the ``use`` statement atop the ``Controller`` class and then modify the -``HelloController`` to extend it. That's all there is to it. - -.. code-block:: php - - // src/Sensio/HelloBundle/Controller/HelloController.php - - namespace Sensio\HelloBundle\Controller; - use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use Symfony\Component\HttpFoundation\Response; - - class HelloController extends Controller - { - public function indexAction($name) - { - return new Response('Hello '.$name.'!'); - } - } - -So far, extending the base ``Controller`` class hasn't changed anything. In -the next section, we'll walk through several helper methods that the base -controller class makes available. These methods are just shortcuts to using -core Symfony2 functionality that's available to you with or without the use of -the base ``Controller`` class. A great way to see the core functionality in -action is to look in the -:class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` class -itself. - -.. tip:: - - Extending the base class is a *choice* in Symfony; it contains useful - shortcuts but nothing mandatory. You can also extend - :class:`Symfony\\Component\\DependencyInjection\\ContainerAware`. The - service container object will then be accessible via the ``container`` - property and this is the only object you need to create any controller. - -.. note:: - - You can also define your :doc:`Controllers as Services - `. - -.. index:: - single: Controller; Common Tasks - -Common Controller Tasks ------------------------ - -Though a controller can do virtually anything, most controllers will perform -the same basic tasks over and over again. These tasks, such as redirecting, -forwarding, rendering templates and accessing core services, are very easy -to manage in Symfony2. - -.. index:: - single: Controller; Redirecting - -Redirecting -~~~~~~~~~~~ - -If you want to redirect the user to another page, use a special ``RedirectResponse`` -class, which is designed specifically to redirect the user to another URL:: - - // ... - use Symfony\Component\HttpFoundation\RedirectResponse; - - class HelloController extends Controller - { - public function indexAction() - { - return new RedirectResponse($this->generateUrl('hello', array('name' => 'Lucas'))); - } - } - -The ``generateUrl()`` method is just a shortcut that calls ``generate()`` -on the ``router`` service. It takes the route name and an array of parameters -as arguments and returns the associated friendly URL. See the :doc:`Routing ` -guide for more information. - -By default, the ``redirect`` method does a 302 (temporary) redirect. To perform -a 301 (permanent) redirect, modify the second argument:: - - public function indexAction() - { - return new RedirectResponse($this->generateUrl('hello', array('name' => 'Lucas')), 301); - } - -.. index:: - single: Controller; Forwarding - -Forwarding -~~~~~~~~~~ - -You can also easily forward to another action internally with the ``forward()`` -method. Instead of redirecting the user's browser, it makes an internal sub-request, -and calls the specified controller. The ``forward()`` method returns the ``Response`` -object to allow for further modification if the need arises. That ``Response`` -object is the end-product of the internal sub-request:: - - public function indexAction($name) - { - $response = $this->forward('HelloBundle:Hello:fancy', array( - 'name' => $name, - 'color' => 'green' - )); - - // further modify the response or return it directly - - return $response; - } - -Notice that the `forward()` method uses the same string representation of -the controller used in the routing configuration. The array passed to the -method becomes the arguments on the resulting controller. This same interface -is used when embedding controllers into templates (see :ref:`templating-embedding-controller`). -The target controller method should look something like the following:: - - public function fancyAction($name, $green) - { - // ... create and return a Response object - } - -And just like when creating a controller for a route, the order of the arguments -to ``fancyAction`` doesn't matter. Symfony2 matches the index key names -(e.g. ``name``) with the method argument names (e.g. ``$name``). If you -change the order of the arguments, Symfony2 will still pass the correct -value to each variable. - -.. tip:: - - Like other base ``Controller`` methods, the ``forward`` method is just - a shortcut for core Symfony2 functionality. A forward can be accomplished - directly via the ``http_kernel`` service. A forward returns a ``Response`` - object:: - - $httpKernel = $this->container->get('http_kernel'); - $response = $httpKernel->forward('HelloBundle:Hello:fancy', array( - 'name' => $name, - 'color' => 'green', - )); - -.. index:: - single: Controller; Rendering templates - -Rendering Templates -~~~~~~~~~~~~~~~~~~~ - -Though not a requirement, most controllers will ultimately render a template -that's responsible for generating the HTML (or other format) for the controller. -The ``renderView()`` method renders a template and returns its content. The -content from the template can be used to create a ``Response`` object:: - - $content = $this->renderView('HelloBundle:Hello:index.html.twig', array('name' => $name)); - - return new Response($content); - -This can even be done in just one step with the ``render()`` method, which -returns a ``Response`` object with the content from the template:: - - return $this->render('HelloBundle:Hello:index.html.twig', array('name' => $name)); - -The Symfony templating engine is explained in great detail in the :doc:`Templating ` -guide. - -.. tip:: - - The ``renderView`` method is a shortcut to direct use of the ``templating`` - service. The ``templating`` service can also be used directly:: - - $templating = $this->get('templating'); - $content = $templating->render('HelloBundle:Hello:index.html.twig', array('name' => $name)); - -.. index:: - single: Controller; Accessing services - -Accessing other Services -~~~~~~~~~~~~~~~~~~~~~~~~ - -When extending the base controller class, you can access any Symfony2 service -via the ``get()`` method. Here are several common services you might need:: - - $request = $this->get('request'); - - $response = $this->get('response'); - - $templating = $this->get('templating'); - - $router = $this->get('router'); - - $mailer = $this->get('mailer'); - -The are countless other services available and you are encouraged to define -your own. For more information, see the :doc:`Extending Symfony ` -guide. - -.. index:: - single: Controller; Managing errors - -Managing Errors ---------------- - -When things are not found, you should play well with the HTTP protocol and -return a 404 response. This is easily done by throwing a built-in HTTP -exception: - -.. code-block:: php - - use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; - - public function indexAction() - { - $product = // retrieve the object from database - if (!$product) { - throw new NotFoundHttpException('The product does not exist.'); - } - - return $this->render(...); - } - -The ``NotFoundHttpException`` will return a 404 HTTP response back to the -browser. When viewing a page in debug mode, a full exception with stacktrace -is displayed so that the cause of the exception can be easily tracked down. - -Of course, you're free to throw any ``Exception`` class in your controller -- Symfony2 will automatically return a 500 HTTP response code. - -.. code-block:: php - - throw new \Exception('Something went wrong!'); - -In every case, a styled error page is shown to the end user and a full debug -error page is shown to the developer (when viewing the page in debug mode). -Both of these error pages can be customized. - -.. note:: - - Read the ":doc:`/cookbook/controller/error_pages`" recipe to learn more. - -.. index:: - single: Controller; The session - single: Session - -Managing the Session --------------------- - -Even if the HTTP protocol is stateless, Symfony2 provides a nice session object -that represents the client (be it a real person using a browser, a bot, or a -web service). Between two requests, Symfony2 stores the attributes in a cookie -by using the native PHP sessions. - -Storing and retrieving information from the session can be easily achieved -from any controller:: - - $session = $this->get('request')->getSession(); - - // store an attribute for reuse during a later user request - $session->set('foo', 'bar'); - - // in another controller for another request - $foo = $session->get('foo'); - - // set the user locale - $session->setLocale('fr'); - -These attributes will remain on the user for the remainder of that user's -session. - -.. index:: - single Session; Flash messages - -Flash Messages -~~~~~~~~~~~~~~ - -You can also store small messages that will be stored on the user's session -for exactly one additional request. This is useful when processing a form: -you want to redirect and have a special message shown on the *next* request. -These types of messages are called "flash" messages. - -Let's show an example where we're processing a form submit:: - - public function updateAction() - { - if ('POST' === $this->get('request')->getMethod()) { - // do some sort of processing - - $this->get('session')->setFlash('notice', 'Your changes were saved!'); - - return new RedirectResponse($this->generateUrl(...)); - } - - return $this->render(...); - } - -After processing the request, the controller sets a ``notice`` flash message -and then redirects. In the template of the next action, the following code -could be used to render the message: - -.. configuration-block:: - - .. code-block:: html+jinja - - {% if app.session.hasFlash('notice') %} -
- {{ app.session.flash('notice') }} -
- {% endif %} - - .. code-block:: php - - hasFlash('notice') ?> -
- getFlash('notice') ?> -
- - -By design, flash messages are meant to only live for exactly one request -(they're "gone in a flash"). They're designed to be used across redirects -exactly as we've done in this example. - -.. index:: - single: Controller; Response - -The Response Object -------------------- - -The only requirement for a controller is to return a ``Response`` object. The -:class:`Symfony\\Component\\HttpFoundation\\Response` class is a PHP -abstraction around the HTTP response - the text-based message filled with HTTP -headers and content that's sent back to the client:: - - // create a simple Response with a 200 status code (the default) - $response = new Response('Hello '.$name, 200); - - // create a JSON-response with a 200 status code - $response = new Response(json_encode(array('name' => $name))); - $response->headers->set('Content-Type', 'application/json'); - -.. tip:: - - The ``headers`` property is a - :class:`Symfony\\Component\\HttpFoundation\\HeaderBag` object with several - useful methods for reading and mutating the ``Response`` headers. The - header names are normalized so that using ``Content-Type`` is equivalent - to ``content-type`` or even ``content_type``. - -.. index:: - single: Controller; Request - -The Request Object ------------------- - -Besides the values of the routing placeholders, the controller also has access -to the ``Request`` object when extending the base ``Controller`` class:: - - $request = $this->get('request'); - - $request->isXmlHttpRequest(); // is it an Ajax request? - - $request->getPreferredLanguage(array('en', 'fr')); - - $request->query->get('page'); // get a $_GET parameter - - $request->request->get('page'); // get a $_POST parameter - -Like the ``Response`` object, the request headers are stored in a ``HeaderBag`` -object and are easily accessible. - -.. index:: - single: Controller; Overview - -Overview --------- - -In Symfony, a controller is nothing more than a PHP function that contains -whatever arbitrary logic is needed to create and return a ``Response`` object. -The controller allows us to have an application with many pages while keeping -the logic for each page organized into different controller classes and action -methods. - -Symfony2 decides which controller should handle each request by matching -a route and resolving the string format of its ``_controller`` parameter -to a real Symfony2 controller. The arguments on that controller correspond -to the parameters on the route, allowing your controller access to the information -form the request. - -The controller can do anything and contain any logic, as long as it returns -a ``Response`` object. If you extend the base ``Controller`` class, you -instantly have access to all of the Symfony2 core service objects as well -as shortcut methods to performing the most common tasks. \ No newline at end of file diff --git a/book/doctrine/dbal/configuration.rst b/book/doctrine/dbal/configuration.rst deleted file mode 100644 index 9c548f5d15b..00000000000 --- a/book/doctrine/dbal/configuration.rst +++ /dev/null @@ -1,127 +0,0 @@ -.. index:: - single: Configuration; Doctrine DBAL - single: Doctrine; DBAL configuration - -Configuration -============= - -One example configuration with a MySQL database could look like this following -example: - -.. code-block:: yaml - - # app/config/config.yml - doctrine: - dbal: - driver: pdo_mysql - dbname: Symfony2 - user: root - password: null - -The DoctrineBundle supports all parameters that all the default doctrine drivers -accept, converted to the XML or YAML naming standards that Symfony enforces. -See the Doctrine DBAL `documentation`_ for more information. Additionally -there are some Symfony related options that you can configure. The following -block shows all possible configuration keys without explaining their meaning -further: - -.. configuration-block:: - - .. code-block:: yaml - - doctrine: - dbal: - dbname: database - host: localhost - port: 1234 - user: user - password: secret - driver: pdo_mysql - driver_class: MyNamespace\MyDriverImpl - options: - foo: bar - path: %kernel.data_dir%/data.sqlite - memory: true - unix_socket: /tmp/mysql.sock - wrapper_class: MyDoctrineDbalConnectionWrapper - charset: UTF-8 - logging: %kernel.debug% - platform_service: MyOwnDatabasePlatformService - - .. code-block:: xml - - - - - - - - -There are also a bunch of dependency injection container parameters -that allow you to specify which classes are used (with their default values): - -.. code-block:: yaml - - parameters: - doctrine.dbal.logger_class: Symfony\Bundle\DoctrineBundle\Logger\DbalLogger - doctrine.dbal.configuration_class: Doctrine\DBAL\Configuration - doctrine.data_collector.class: Symfony\Bundle\DoctrineBundle\DataCollector\DoctrineDataCollector - doctrine.dbal.event_manager_class: Doctrine\Common\EventManager - doctrine.dbal.events.mysql_session_init.class: Doctrine\DBAL\Event\Listeners\MysqlSessionInit - doctrine.dbal.events.oracle_session_init.class: Doctrine\DBAL\Event\Listeners\OracleSessionInit - doctrine.dbal.logging: false - -If you want to configure multiple connections you can do so by simply listing -them under the key named ``connections``. All the parameters shown above -can also be specified in the connections subkeys. - -.. code-block:: yaml - - doctrine: - dbal: - default_connection: default - connections: - default: - dbname: Symfony2 - user: root - password: null - host: localhost - customer: - dbname: customer - user: root - password: null - host: localhost - -If you have defined multiple connections you can use the -``$this->get('doctrine.dbal.[connectionname]_connection)`` -as well but you must pass it an argument with the -connection name that you want get:: - - class UserController extends Controller - { - public function indexAction() - { - $defaultConn1 = $this->get('doctrine.dbal.connection'); - $defaultConn2 = $this->get('doctrine.dbal.default_connection'); - // $defaultConn1 === $defaultConn2 - - $customerConn = $this->get('doctrine.dbal.customer_connection'); - } - } - -.. _documentation: http://www.doctrine-project.org/projects/dbal/2.0/docs/en diff --git a/book/doctrine/dbal/index.rst b/book/doctrine/dbal/index.rst deleted file mode 100644 index c9bf74f606c..00000000000 --- a/book/doctrine/dbal/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -Database Abstraction Layer -========================== - -Learn about Doctrine's Database Abstraction Layer and how it can help you -perform almost any complex task in a database-agnostic, object-oriented -way. - -.. toctree:: - :maxdepth: 2 - - Overview - configuration diff --git a/book/doctrine/dbal/overview.rst b/book/doctrine/dbal/overview.rst deleted file mode 100644 index 3a6523cf4b3..00000000000 --- a/book/doctrine/dbal/overview.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. index:: - pair: Doctrine; DBAL - -DBAL -==== - -The `Doctrine`_ Database Abstraction Layer (DBAL) is an abstraction layer that -sits on top of `PDO`_ and offers an intuitive and flexible API for -communicating with the most popular relational databases that exist today! - -.. tip:: - - You can read more about the Doctrine DBAL on the official `documentation`_ - website. - -To get started you just need to enable and configure the DBAL: - -.. code-block:: yaml - - # app/config/config.yml - - doctrine: - dbal: - driver: pdo_mysql - dbname: Symfony2 - user: root - password: null - -You can then access the Doctrine DBAL connection by accessing the -``database_connection`` service:: - - class UserController extends Controller - { - public function indexAction() - { - $conn = $this->get('database_connection'); - - $users = $conn->fetchAll('SELECT * FROM users'); - } - } - -.. _PDO: http://www.php.net/pdo -.. _documentation: http://www.doctrine-project.org/projects/dbal/2.0/docs/en -.. _Doctrine: http://www.doctrine-project.org diff --git a/book/doctrine/index.rst b/book/doctrine/index.rst deleted file mode 100644 index 9861ec0835b..00000000000 --- a/book/doctrine/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -Doctrine -======== - -Learn about the Doctrine integration with Symfony2: - -.. toctree:: - :maxdepth: 2 - - orm/index - dbal/index - migrations/index - mongodb-odm/index diff --git a/book/doctrine/migrations/index.rst b/book/doctrine/migrations/index.rst deleted file mode 100644 index 259ebb34c41..00000000000 --- a/book/doctrine/migrations/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Database Migrations -=================== - -Learn about Doctrine's database migration tool and start migrating your database -schema safer and more effectively. - -.. toctree:: - :maxdepth: 2 - - Overview \ No newline at end of file diff --git a/book/doctrine/migrations/overview.rst b/book/doctrine/migrations/overview.rst deleted file mode 100644 index 55ec1d29648..00000000000 --- a/book/doctrine/migrations/overview.rst +++ /dev/null @@ -1,114 +0,0 @@ -.. index:: - pair: Doctrine; Migrations - -Migrations -========== - -The database migrations feature is an extension of the database abstraction -layer and offers you the ability to programmatically deploy new versions of -your database schema in a safe and standardized way. - -.. tip:: - - You can read more about the Doctrine Database Migrations on the projects - `documentation`_. - -All of the migrations functionality is contained in a few console commands: - -.. code-block:: bash - - doctrine:migrations - :diff Generate a migration by comparing your current database to your mapping information. - :execute Execute a single migration version up or down manually. - :generate Generate a blank migration class. - :migrate Execute a migration to a specified version or the latest available version. - :status View the status of a set of migrations. - :version Manually add and delete migration versions from the version table. - -Every bundle manages its own migrations so when working with the above commands -you must specify the bundle you want to work with. For example to see the -status of a bundle migrations you can run the ``status`` command: - -.. code-block:: bash - - $ php app/console doctrine:migrations:status --bundle="HelloBundle" - - == Configuration - - >> Name: HelloBundle Migrations - >> Configuration Source: manually configured - >> Version Table Name: hello_bundle_migration_versions - >> Migrations Namespace: Sensio\HelloBundle\DoctrineMigrations - >> Migrations Directory: /path/to/symfony-sandbox/src/Bundle/HelloBundle/DoctrineMigrations - >> Current Version: 0 - >> Latest Version: 0 - >> Executed Migrations: 0 - >> Available Migrations: 0 - >> New Migrations: 0 - -Now, we can start working with migrations by generating a new blank migration -class: - -.. code-block:: bash - - $ php app/console doctrine:migrations:generate --bundle="HelloBundle" - Generated new migration class to "/path/to/project/src/Sensio/HelloBundle/DoctrineMigrations/Version20100621140655.php" - -.. tip:: - - You may need to create the folder ``/path/to/project/src/Sensio/HelloBundle/DoctrineMigrations`` - before running the ``doctrine:migrations:generate`` command. - -Have a look at the newly generated migration class and you will see something -like the following:: - - namespace Sensio\HelloBundle\DoctrineMigrations; - - use Doctrine\DBAL\Migrations\AbstractMigration, - Doctrine\DBAL\Schema\Schema; - - class Version20100621140655 extends AbstractMigration - { - public function up(Schema $schema) - { - - } - - public function down(Schema $schema) - { - - } - } - -If you were to run the ``status`` command for the ``HelloBundle`` it will show -that you have one new migration to execute: - -.. code-block:: bash - - $ php app/console doctrine:migrations:status --bundle="HelloBundle" - - == Configuration - - >> Name: HelloBundle Migrations - >> Configuration Source: manually configured - >> Version Table Name: hello_bundle_migration_versions - >> Migrations Namespace: Sensio\HelloBundle\DoctrineMigrations - >> Migrations Directory: /path/to/symfony-sandbox/src/Sensio/HelloBundle/DoctrineMigrations - >> Current Version: 0 - >> Latest Version: 2010-06-21 14:06:55 (20100621140655) - >> Executed Migrations: 0 - >> Available Migrations: 1 - >> New Migrations: 1 - - == Migration Versions - - >> 2010-06-21 14:06:55 (20100621140655) not migrated - -Now you can add some migration code to the ``up()`` and ``down()`` methods and -migrate: - -.. code-block:: bash - - $ php app/console doctrine:migrations:migrate --bundle="HelloBundle" - -.. _documentation: http://www.doctrine-project.org/projects/migrations/2.0/docs/en diff --git a/book/doctrine/mongodb-odm/configuration.rst b/book/doctrine/mongodb-odm/configuration.rst deleted file mode 100644 index 987f0061a16..00000000000 --- a/book/doctrine/mongodb-odm/configuration.rst +++ /dev/null @@ -1,320 +0,0 @@ -.. index:: - single: Configuration; Doctrine MongoDB ODM - single: Doctrine; MongoDB ODM configuration - -Configuration -============= - -.. code-block:: yaml - - # app/config/config.yml - doctrine_mongo_db: - server: mongodb://localhost:27017 - default_database: hello_%kernel.environment% - options: - connect: true - metadata_cache_driver: array # array, apc, xcache, memcache - -If you wish to use memcache to cache your metadata, you need to configure the -``Memcache`` instance you can do the following: - -.. code-block:: yaml - - # app/config/config.yml - doctrine_mongo_db: - server: mongodb://localhost:27017 - default_database: hello_%kernel.environment% - options: - connect: true - metadata_cache_driver: - type: memcache - class: Doctrine\Common\Cache\MemcacheCache - host: localhost - port: 11211 - instance_class: Memcache - -Mapping Configuration -~~~~~~~~~~~~~~~~~~~~~ - -Explicit definition of all the mapped documents is the only necessary -configuration for the ODM and there are several configuration options that you -can control. The following configuration options exist for a mapping: - -- ``type`` One of "annotations", "xml", "yml", "php" or "static-php". This - specifies which type of metadata type your mapping uses. -- ``dir`` Path to the mapping or entity files (depending on the driver). If - this path is relative it is assumed to be relative to the bundle root. This - only works if the name of your mapping is a bundle name. If you want to use - this option to specify absolute paths you should prefix the path with the - kernel parameters that exist in the DIC (for example %kernel.dir%). -- ``prefix`` A common namespace prefix that all documents of this mapping - share. This prefix should never conflict with prefixes of other defined - mappings otherwise some of your documents cannot be found by Doctrine. This - option defaults to the bundle namespace + ``Document``, for example for an - application bundle called "Hello" prefix would be - ``Sensio\Hello\Document``. -- ``alias`` Doctrine offers a way to alias document namespaces to simpler, - shorter names to be used in queries or for Repository access. -- ``is_bundle`` This option is a derived value from ``dir`` and by default is - set to true if dir is relative proved by a ``file_exists()`` check that - returns false. It is false if the existence check returns true. In this case - an absolute path was specified and the metadata files are most likely in a - directory outside of a bundle. - -To avoid having to configure lots of information for your mappings you should -follow these conventions: - -1. Put all your entities in a directory ``Document/`` inside your bundle. For - example ``Sensio/Hello/Document/``. -2. If you are using xml, yml or php mapping put all your configuration files - into the ``Resources/config/doctrine/metadata/doctrine/mongodb/`` directory - sufficed with dcm.xml, dcm.yml or dcm.php respectively. -3. Annotations is assumed if an ``Document/`` but no - ``Resources/config/doctrine/metadata/doctrine/mongodb/`` directory is found. - -The following configuration shows a bunch of mapping examples: - -.. code-block:: yaml - - doctrine_mongo_db: - mappings: - MyBundle1: ~ - MyBundle2: yml - MyBundle3: { type: annotation, dir: Documents/ } - MyBundle4: { type: xml, dir: Resources/config/doctrine/mapping } - MyBundle5: - type: yml - dir: my-bundle-mappings-dir - alias: BundleAlias - doctrine_extensions: - type: xml - dir: %kernel.dir%/../src/vendor/DoctrineExtensions/lib/DoctrineExtensions/Documents - prefix: DoctrineExtensions\Documents\ - alias: DExt - -Registering Event Listeners and Subscribers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Doctrine uses the lightweight ``Doctrine\Common\EventManager`` class to trigger -a number of different events which you can hook into. You can register Event -Listeners or Subscribers by tagging the respective services with -``doctrine.odm.mongodb._event_listener`` or -``doctrine.odm.mongodb._event_subscriber`` using the Dependency Injection -container. - -You have to use the name of the MongoDB connection to clearly identify which -connection the listeners should be registered with. If you are using multiple -connections you can hook different events into each connection. - -Multiple Connections -~~~~~~~~~~~~~~~~~~~~ - -If you need multiple connections and document managers you can use the -following syntax: - -.. code-block:: yaml - - doctrine_mongo_db: - default_database: hello_%kernel.environment% - default_connection: conn2 - default_document_manager: dm2 - metadata_cache_driver: apc - connections: - conn1: - server: mongodb://localhost:27017 - options: - connect: true - conn2: - server: mongodb://localhost:27017 - options: - connect: true - document_managers: - dm1: - connection: conn1 - metadata_cache_driver: xcache - dm2: - connection: conn2 - -Now you can retrieve the configured services connection services:: - - $conn1 = $container->get('doctrine.odm.mongodb.conn1_connection'); - $conn2 = $container->get('doctrine.odm.mongodb.conn2_connection'); - -And you can also retrieve the configured document manager services which utilize the above -connection services:: - - $dm1 = $container->get('doctrine.odm.mongodb.dm1_document_manager'); - $dm2 = $container->get('doctrine.odm.mongodb.dm2_document_manager'); - -XML -~~~ - -You can specify the same configuration via XML if you prefer that. Here are -the same examples from above in XML. - -Simple Single Connection: - -.. code-block:: xml - - - - - - - - Doctrine\Common\Cache\MemcacheCache - localhost - 11211 - Memcache - - - true - - - - -Multiple Connections: - -.. code-block:: xml - - - - - - - - - - true - - - - - true - - - - - - - - - - -Writing Document Classes ------------------------- - -You can start writing document classes just how you normally would write some -PHP classes. The only difference is that you must map the classes to the -MongoDB ODM. You can provide the mapping information via xml, yaml or -annotations. In this example, for simplicity and ease of reading we will use -annotations. - -First, lets write a simple User class:: - - // src/Sensio/HelloBundle/Document/User.php - - namespace Sensio\HelloBundle\Document; - - class User - { - protected $id; - protected $name; - - public function getId() - { - return $this->id; - } - - public function setName($name) - { - $this->name = $name; - } - - public function getName() - { - return $this->name; - } - } - -This class can be used independent from any persistence layer as it is a -regular PHP class and does not have any dependencies. Now we need to annotate -the class so Doctrine can read the annotated mapping information from the doc -blocks:: - - // ... - - /** @mongodb:Document(collection="users") */ - class User - { - /** @mongodb:Id */ - protected $id; - - /** @mongodb:String */ - protected $name; - - // ... - } - -Using Documents ---------------- - -Now that you have a PHP class that has been mapped properly you can begin -working with instances of that document persisting to and retrieving from -MongoDB. - -From your controllers you can access the ``DocumentManager`` instance from the -container:: - - class UserController extends Controller - { - public function createAction() - { - $user = new User(); - $user->setName('Jonathan H. Wage'); - - $dm = $this->get('doctrine.odm.mongodb.document_manager'); - $dm->persist($user); - $dm->flush(); - - // ... - } - } - -Later you can retrieve the persisted document by its id:: - - class UserController extends Controller - { - public function editAction($id) - { - $dm = $this->get('doctrine.odm.mongodb.document_manager'); - $user = $dm->find('HelloBundle:User', $id); - - // ... - } - } - -Registering Event Listeners and Subscribers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Registering events works like described in the :ref:`ORM Bundle documentation `. -The MongoDB event tags are called "doctrine.odm.mongodb.default_event_listener" and -"doctrine.odm.mongodb.default_event_subscriber" respectively where "default" is the name of the -MongoDB document manager. - -.. _MongoDB: http://www.mongodb.org/ -.. _documentation: http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/en diff --git a/book/doctrine/mongodb-odm/index.rst b/book/doctrine/mongodb-odm/index.rst deleted file mode 100644 index a33695564f1..00000000000 --- a/book/doctrine/mongodb-odm/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -MongoDB Object Document Mapper -============================== - -Doctrine's MongoDB Object Document Mapper allows for PHP objects to be persisted -to and retrieved from a MongoDB document database. - -.. toctree:: - :maxdepth: 2 - - Overview - configuration diff --git a/book/doctrine/mongodb-odm/overview.rst b/book/doctrine/mongodb-odm/overview.rst deleted file mode 100644 index a4725eb5a5f..00000000000 --- a/book/doctrine/mongodb-odm/overview.rst +++ /dev/null @@ -1,120 +0,0 @@ -.. index:: - pair: Doctrine; MongoDB ODM - -MongoDB ODM -=========== - -The `MongoDB`_ Object Document Mapper is much like the Doctrine2 ORM in the way -it works and architecture. You only deal with plain PHP objects and they are -persisted transparently without imposing on your domain model. - -.. tip:: - - You can read more about the Doctrine MongoDB Object Document Mapper on the - projects `documentation`_. - -To get started working with Doctrine and the MongoDB Object Document Mapper you -just need to enable it and specify the bundle that contains your mapped documents: - -.. code-block:: yaml - - # app/config/config.yml - - doctrine_mongo_db: - mappings: - HelloBundle: ~ - -Now you can start writing documents and mapping them with annotations, xml, or -yaml. In this example we will use annotations:: - - // Sensio/HelloBundle/Document/User.php - - namespace Sensio\HelloBundle\Document; - - /** - * @mongodb:Document(collection="users") - */ - class User - { - /** - * @mongodb:Id - */ - protected $id; - - /** - * @mongodb:String - */ - protected $name; - - /** - * Get id - * - * @return integer $id - */ - public function getId() - { - return $this->id; - } - - /** - * Set name - * - * @param string $name - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * Get name - * - * @return string $name - */ - public function getName() - { - return $this->name; - } - } - -Now, use your document and manage its persistent state with Doctrine:: - - use Sensio\HelloBundle\Document\User; - - class UserController extends Controller - { - public function createAction() - { - $user = new User(); - $user->setName('Jonathan H. Wage'); - - $dm = $this->get('doctrine.odm.mongodb.document_manager'); - $dm->persist($user); - $dm->flush(); - - // ... - } - - public function editAction($id) - { - $dm = $this->get('doctrine.odm.mongodb.document_manager'); - $user = $dm->createQuery('find all from HelloBundle:User where id = ?', $id); - $user->setBody('new body'); - $dm->flush(); - - // ... - } - - public function deleteAction($id) - { - $dm = $this->get('doctrine.odm.entity_manager'); - $user = $dm->createQuery('find all from HelloBundle:User where id = ?', $id); - $dm->remove($user); - $dm->flush(); - - // ... - } - } - -.. _MongoDB: http://www.mongodb.org/ -.. _documentation: http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/en diff --git a/book/doctrine/orm/configuration.rst b/book/doctrine/orm/configuration.rst deleted file mode 100644 index 522bf00e721..00000000000 --- a/book/doctrine/orm/configuration.rst +++ /dev/null @@ -1,257 +0,0 @@ -.. index:: - single: Configuration; Doctrine ORM - single: Doctrine; ORM Configuration - -Configuration -============= - -In the overview we already described the only necessary configuration option -"mappings" to get the Doctrine ORM running with Symfony 2. All the other -configuration options are used with reasonable default values. - -This following configuration example shows all the configuration defaults that -the ORM resolves to: - -.. code-block:: yaml - - doctrine: - orm: - mappings: - HelloBundle: ~ - auto_generate_proxy_classes: true - proxy_namespace: Proxies - proxy_dir: %kernel.cache_dir%/doctrine/orm/Proxies - default_entity_manager: default - default_connection: default - metadata_cache_driver: array - query_cache_driver: array - result_cache_driver: array - -There are lots of other configuration options that you can use to overwrite -certain classes, but those are for very advanced use-cases only. You should -look at the "orm.xml" file in the DoctrineBundle to get an overview of all the -supported options. - -For the caching drivers you can specifiy the values "array", "apc", "memcache" -or "xcache". - -The following example shows an overview of the caching configurations: - -.. code-block:: yaml - - doctrine: - orm: - mappings: - HelloBundle: ~ - metadata_cache_driver: apc - query_cache_driver: xcache - result_cache_driver: - type: memcache - host: localhost - port: 11211 - instance_class: Memcache - -Mapping Configuration -~~~~~~~~~~~~~~~~~~~~~ - -Explicit definition of all the mapped entities is the only necessary -configuration for the ORM and there are several configuration options that you -can control. The following configuration options exist for a mapping: - -- ``type`` One of "annotation", "xml", "yml", "php" or "static-php". This - specifies which type of metadata type your mapping uses. -- ``dir`` Path to the mapping or entity files (depending on the driver). If - this path is relative it is assumed to be relative to the bundle root. This - only works if the name of your mapping is a bundle name. If you want to use - this option to specifiy absolute paths you should prefix the path with the - kernel parameters that exist in the DIC (for example %kernel.dir%). -- ``prefix`` A common namespace prefix that all entities of this mapping - share. This prefix should never conflict with prefixes of other defined - mappings otherwise some of your entities cannot be found by Doctrine. This - option defaults to the bundle namespace + ``Entity``, for example for an - application bundle called "Hello" prefix would be - ``Sensio\Hello\Entity``. -- ``alias`` Doctrine offers a way to alias entity namespaces to simpler, - shorter names to be used in DQL queries or for Repository access. -- ``is_bundle`` This option is a derived value from ``dir`` and by default is - set to true if dir is relative proved by a ``file_exists()`` check that - returns false. It is false if the existence check returns true. In this case - an absolute path was specified and the metadata files are most likely in a - directory outside of a bundle. - -To avoid having to configure lots of information for your mappings you should -follow these conventions: - -1. Put all your entities in a directory ``Entity/`` inside your bundle. For - example ``Sensio/Hello/Entity/``. -2. If you are using xml, yml or php mapping put all your configuration files - into the "Resources/config/doctrine/metadata/doctrine/orm/" directory sufficed - with dcm.xml, dcm.yml or dcm.php respectively. -3. Annotations is assumed if an ``Entity/`` but no - "Resources/config/doctrine/metadata/doctrine/orm/" directory is found. - -The following configuration shows a bunch of mapping examples: - -.. code-block:: yaml - - doctrine: - orm: - mappings: - MyBundle1: ~ - MyBundle2: yml - MyBundle3: { type: annotation, dir: Entity/ } - MyBundle4: { type: xml, dir: Resources/config/doctrine/mapping } - MyBundle5: - type: yml - dir: my-bundle-mappings-dir - alias: BundleAlias - doctrine_extensions: - type: xml - dir: %kernel.dir%/../src/vendor/DoctrineExtensions/lib/DoctrineExtensions/Entity - prefix: DoctrineExtensions\Entity\ - alias: DExt - -Registering Event Listeners and Subscribers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Doctrine uses the lightweight ``Doctrine\Common\EventManager`` class to trigger -a number of different events which you can hook into. You can register Event -Listeners or Subscribers by tagging the respective services with -``doctrine.dbal._event_listener`` or -``doctrine.dbal._event_subscriber`` using the Dependency Injenction -container. - -You have to use the name of the DBAL connection to clearly identify which -connection the listeners should be registered with. If you are using multiple -connections you can hook different events into each connection. - -.. code-block:: xml - - - - - - - - - - - - - - - - - -Although the Event Listener and Subscriber tags are prefixed with ``doctrine.dbal`` -these tags also work for the ORM events. Internally Doctrine re-uses the EventManager -that is registered with the connection for the ORM. - -Multiple Entity Managers -~~~~~~~~~~~~~~~~~~~~~~~~ - -You can use multiple EntityManagers in a Symfony application. This is -necessary if you are using different databases or even vendors with entirely -different sets of entities. - -The following configuration code shows how to define two EntityManagers: - -.. code-block:: yaml - - doctrine: - orm: - default_entity_manager: default - cache_driver: apc # array, apc, memcache, xcache - entity_managers: - default: - connection: default - customer: - connection: customer - -Just like the DBAL, if you have configured multiple ``EntityManager`` -instances and want to get a specific one you can use the full service name to -retrieve it from the Symfony Dependency Injection Container:: - - class UserController extends Controller - { - public function indexAction() - { - $em = $this->get('doctrine.orm.entity_manager'); - $defaultEm = $this->get('doctrine.orm.default_entity_manager'); - $customerEm = $this->get('doctrine.orm.customer_entity_manager'); - - // $em === $defaultEm => true - // $defaultEm === $customerEm => false - } - } - -The service "doctrine.orm.entity_manager" is an alias for the default entity -manager defined in the "default_entity_manager" configuration option. - -.. _doctrine-event-config: - -Registering Event Listeners and Subscribers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Doctrine ships with an event system that allows to hook into many different -events happening during the lifecycle of entities or at other occasions. - -To register services to act as event listeners or subscribers (listeners from here) -you have to tag them with the appropriate names. Depending on your use-case you can hook -a listener into every DBAL Connection and ORM Entity Manager or just into one -specific DBAL connection and all the EntityManagers that use this connection. - -.. configuration-block:: - - .. code-block:: yaml - - doctrine: - dbal: - default_connection: default - connections: - default: - driver: pdo_sqlite - memory: true - - services: - my.listener: - class: MyEventListener - tags: - - { name: doctrine.common.event_listener } - my.listener2: - class: MyEventListener2 - tags: - - { name: doctrine.dbal.default_event_listener } - my.subscriber: - class: MyEventSubscriber - tags: - - { name: doctrine.dbal.default_event_subscriber } - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/book/doctrine/orm/console.rst b/book/doctrine/orm/console.rst deleted file mode 100644 index d3881e4e44c..00000000000 --- a/book/doctrine/orm/console.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. index:: - single: Doctrine; ORM Console Commands - single: CLI; Doctrine ORM - -Console Commands -================ - -The Doctrine2 ORM integration offers several console commands under the -``doctrine`` namespace. To view the command list you can run the console -without any arguments or options: - - $ php app/console - ... - - doctrine - :ensure-production-settings Verify that Doctrine is properly configured for a production environment. - :schema-tool Processes the schema and either apply it directly on EntityManager or generate the SQL output. - doctrine:cache - :clear-metadata Clear all metadata cache for a entity manager. - :clear-query Clear all query cache for a entity manager. - :clear-result Clear result cache for a entity manager. - doctrine:data - :load Load data fixtures to your database. - doctrine:database - :create Create the configured databases. - :drop Drop the configured databases. - doctrine:generate - :entities Generate entity classes and method stubs from your mapping information. - :entity Generate a new Doctrine entity inside a bundle. - :proxies Generates proxy classes for entity classes. - :repositories Generate repository classes from your mapping information. - doctrine:mapping - :convert Convert mapping information between supported formats. - :convert-d1-schema Convert a Doctrine1 schema to Doctrine2 mapping files. - :import Import mapping information from an existing database. - doctrine:query - :dql Executes arbitrary DQL directly from the command line. - :sql Executes arbitrary SQL directly from the command line. - doctrine:schema - :create Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output. - :drop Processes the schema and either drop the database schema of EntityManager Storage Connection or generate the SQL output. - :update Processes the schema and either update the database schema of EntityManager Storage Connection or generate the SQL output. - - ... diff --git a/book/doctrine/orm/form.rst b/book/doctrine/orm/form.rst deleted file mode 100644 index 7146fb4ed83..00000000000 --- a/book/doctrine/orm/form.rst +++ /dev/null @@ -1,82 +0,0 @@ -Form Integration -================ - -There is a tight integration between Doctrine ORM and the Symfony2 Form -component. Since Doctrine Entities are plain old php objects they nicely -integrate into the Form component by default, at least for the primitive data -types such as strings, integers and fields. However you can also integrate -them nicely with associations. - -This is done by the help of ValueTransformers, which are form field extension -points. There are currently three transformers that allow you to transform -Doctrine ORM Collections and Entities into their identifier values that can be -used with the Form component. Furthermore they translate form values back to -the Doctrine representation in the most efficient way possible, issuing as few -queries as possible. - -CollectionToChoiceTransformer ------------------------------ - -This transformer allows you to transform a Collection of Entities into an -array of ids. This transformer should be used with the ChoiceField or any -compatible field that handles arrays of values:: - - use Symfony\Component\Form\ChoiceField; - use Symfony\Bundle\DoctrineBundle\Form\ValueTransformer\CollectionToChoiceTransformer; - - $productTransformer = new CollectionToChoiceTransformer(array( - 'em' => $em, - 'className' => 'Product', - )); - - $field = new ChoiceField('products', array( - 'choices' => $productChoices, - 'multiple' => true, - 'expanded' => true, - 'value_transformer' => $productTransformer, - )); - - $form->addField($field); - -The 'em' property expects the EntityManager, the 'className' property expects -the Entity Class name as an argument. - -CollectionToStringTransformer ------------------------------ - -This transformer allows you to transform a Collection of Entities into a -string separated by a separator. This is useful for lists of tags, usernames -or similar unique fields of your Entities. - -EntityToIDTransformer ---------------------- - -This transformer converts an Entity into its ID and back to allow to select -many-to-one or one-to-one entities in choice fields. See this extended example -on how it works. In this case a list of all users is used in a Choice field to -be chosen from:: - - use Symfony\Bundle\DoctrineBundle\Form\ValueTransformer\EntityToIDTransformer; - use Symfony\Component\Form\ChoiceField; - - $userChoices = array(); - $users = $em->getRepository('User')->findAll(); - foreach ($users as $user) { - $userChoices[$user->id] = $user->name; - } - - $userTransformer = new EntityToIDTransformer(array( - 'em' => $em, - 'className' => 'User', - )); - $engineerField = new ChoiceField('engineer', array( - 'choices' => $userChoices, - 'value_transformer' => $userTransformer, - )); - $reporterField = new ChoiceField('reporter', array( - 'choices' => $userChoices, - 'value_transformer' => $userTransformer, - )); - - $form->add($engineerField); - $form->add($reporterField); diff --git a/book/doctrine/orm/index.rst b/book/doctrine/orm/index.rst deleted file mode 100644 index bfc015b9770..00000000000 --- a/book/doctrine/orm/index.rst +++ /dev/null @@ -1,13 +0,0 @@ -Object Relational Mapper -======================== - -Doctrine's Object Relational Mapper allows for PHP objects to be persisted -to and retrieved from almost any relational database. - -.. toctree:: - :maxdepth: 2 - - Overview - Configuration - Console Commands - Form
\ No newline at end of file diff --git a/book/doctrine/orm/overview.rst b/book/doctrine/orm/overview.rst deleted file mode 100644 index b70f1a243d1..00000000000 --- a/book/doctrine/orm/overview.rst +++ /dev/null @@ -1,227 +0,0 @@ -.. index:: - pair: Doctrine; ORM - -ORM -=== - -`Doctrine`_ is an Object relational mapper (ORM) for PHP that sits on top of a -powerful DataBase Abstraction Layer (DBAL). It provides transparent -persistence for PHP objects. - -.. tip:: - - You can read more about the Doctrine Object Relational Mapper on the - official `documentation`_ website. - -To get started, enable and configure the :doc:`Doctrine DBAL -`, then enable the ORM. The minimal -necessary configuration is to specify the bundle name which contains your entities. - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - doctrine: - orm: - mappings: - HelloBundle: ~ - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - $container->loadFromExtension('doctrine', array('orm' => array( - "mappings" => array("HelloBundle" => array())), - )); - -As Doctrine provides transparent persistence for PHP objects, it works with -any PHP class:: - - // Sensio/HelloBundle/Entity/User.php - namespace Sensio\HelloBundle\Entity; - - class User - { - protected $id; - protected $name; - - public function getId() - { - return $this->id; - } - - public function setName($name) - { - $this->name = $name; - } - - public function getName() - { - return $this->name; - } - } - -.. tip:: - - When defining your entities, you can omit the getter/setter methods and - let Doctrine create them for you with the ``doctrine:generate:entities`` - command. This only works after you create the mapping information (see - below). - -To let Doctrine manage your classes (entities in Doctrine2 speak), you need to -write mapping information with annotations, XML, or YAML: - -.. configuration-block:: - - .. code-block:: php - - // Sensio/HelloBundle/Entity/User.php - namespace Sensio\HelloBundle\Entity; - - /** - * @orm:Entity - */ - class User - { - /** - * @orm:Id - * @orm:Column(type="integer") - * @orm:GeneratedValue(strategy="AUTO") - */ - protected $id; - - /** - * @orm:Column(type="string", length="255") - */ - protected $name; - } - - .. code-block:: yaml - - # Sensio/HelloBundle/Resources/config/doctrine/metadata/orm/Sensio.HelloBundle.Entity.User.dcm.yml - Sensio\HelloBundle\Entity\User: - type: entity - table: user - id: - id: - type: integer - generator: - strategy: AUTO - fields: - name: - type: string - length: 50 - - .. code-block:: xml - - - - - - - - - - - - - -.. note:: - - If you use YAML or XML to describe your entities, you can omit the creation - of the Entity class, and let the ``doctrine:generate:entities`` command do - it for you. - -Create the database and the schema related to your metadata information with -the following commands: - -.. code-block:: bash - - $ php app/console doctrine:database:create - $ php app/console doctrine:schema:create - -Eventually, use your entity and manage its persistent state with Doctrine:: - - // Sensio/HelloBundle/Controller/UserController.php - namespace Sensio\HelloBundle\Controller; - - use Sensio\HelloBundle\Entity\User; - - class UserController extends Controller - { - public function createAction() - { - $user = new User(); - $user->setName('Jonathan H. Wage'); - - $em = $this->get('doctrine.orm.entity_manager'); - $em->persist($user); - $em->flush(); - - // ... - } - - public function editAction($id) - { - $em = $this->get('doctrine.orm.entity_manager'); - $user = $em->find('HelloBundle:User', $id); - $user->setBody('new body'); - $em->persist($user); - $em->flush(); - - // ... - } - - public function deleteAction($id) - { - $em = $this->get('doctrine.orm.entity_manager'); - $user = $em->find('HelloBundle:User', $id); - $em->remove($user); - $em->flush(); - - // ... - } - } - -Now the scenario arises where you want to change your mapping information and -update your development database schema without blowing away everything and -losing your existing data. So first lets just add a new property to our ``User`` -entity:: - - namespace Sensio\HelloBundle\Entity; - - /** @orm:Entity */ - class User - { - /** @orm:Column(type="string") */ - protected $new; - - // ... - } - -Once you've done that, to get your database schema updated with the new column -you just need to run the following command: - - $ php app/console doctrine:schema:update - -Now your database will be updated and the new column added to the database -table. - - -.. _documentation: http://www.doctrine-project.org/projects/orm/2.0/docs/en -.. _Doctrine: http://www.doctrine-project.org diff --git a/book/forms/fields.rst b/book/forms/fields.rst deleted file mode 100644 index 23b0a4d8ee2..00000000000 --- a/book/forms/fields.rst +++ /dev/null @@ -1,218 +0,0 @@ -Form Fields -=========== - -A form consists of one or more form fields. Each field is an object whose -class implements :class:`Symfony\\Component\\Form\\FormFieldInterface`. -Fields convert data between normalized and human representations. - -Let's look at the ``DateField`` for example. While your application stores -dates as strings or ``DateTime`` objects, users prefer to choose a date in -drop downs. ``DateField`` handles the rendering and type conversion for you. - -Core Field Options ------------------- - -All built-in fields accept an array of options in their constructor. For -convenience, these core fields are subclasses of -:class:`Symfony\\Component\\Form\\Field` which predefines a couple of options. - -``data`` -~~~~~~~~ - -When you create a form, each field initially displays the value of the -corresponding property of the form's domain object. If you want to override -this initial value, you can set it in the ``data`` option. - -.. code-block:: php - - use Symfony\Component\Form\HiddenField - - $field = new HiddenField('token', array( - 'data' => 'abcdef', - )); - - assert('abcdef' === $field->getData()); - -.. note:: - - When you set the ``data`` option, the field will also not write the the - domain object, because the ``property_path`` option will implicitely be - ``null``. Read :ref:`form-field-property_path` for more information. - -``required`` -~~~~~~~~~~~~ - -By default, each ``Field`` assumes that its value is required, so no empty -value should be submitted. This setting affects the behaviour and rendering of -some fields. The ``ChoiceField``, for example, includes an empty choice if -it is not required. - -.. code-block:: php - - use Symfony\Component\Form\ChoiceField - - $field = new ChoiceField('status', array( - 'choices' => array('tbd' => 'To be done', 'rdy' => 'Ready'), - 'required' => false, - )); - -``disabled`` -~~~~~~~~~~~~ - -If you don't want a user to modify the value of a field, you can set the -``disabled`` option to ``true``. Any submitted value will be ignored. - -.. code-block:: php - - use Symfony\Component\Form\TextField - - $field = new TextField('status', array( - 'data' => 'Old data', - 'disabled' => true, - )); - $field->submit('New data'); - - assert('Old data' === $field->getData()); - -``trim`` -~~~~~~~~ - -Many users accidentally type leading or trailing spaces into input fields. -The form framework automatically removes these spaces. If you want to keep them, -set the ``trim`` option to ``false``. - -.. code-block:: php - - use Symfony\Component\Form\TextField - - $field = new TextField('status', array( - 'trim' => false, - )); - $field->submit(' Data '); - - assert(' Data ' === $field->getData()); - -.. _form-field-property_path: - -``property_path`` -~~~~~~~~~~~~~~~~~ - -Fields display a property value of the form's domain object by default. When -the form is submitted, the submitted value is written back into the object. - -If you want to override the property that a field reads from and writes to, -you can set the ``property_path`` option. Its default value is the field's -name. - -.. code-block:: php - - use Symfony\Component\Form\Form - use Symfony\Component\Form\TextField - - $author = new Author(); - $author->setFirstName('Your name...'); - - $form = new Form('author'); - $form->add(new TextField('name', array( - 'property_path' => 'firstName', - ))); - $form->bind($request, $author); - - assert('Your name...' === $form['name']->getData()); - -For a property path, the class of the domain object needs to have - -1. A matching public property, or -2. A public setter and getter with the prefix "set"/"get", followed by the - property path. - -Property paths can also refer to nested objects by using dots. - -.. code-block:: php - - use Symfony\Component\Form\Form - use Symfony\Component\Form\TextField - - $author = new Author(); - $author->getEmail()->setAddress('me@example.com'); - - $form = new Form('author'); - $form->add(new EmailField('email', array( - 'property_path' => 'email.address', - ))); - $form->bind($request, $author); - - assert('me@example.com' === $form['email']->getData()); - -You can refer to entries of nested arrays or objects implementing -``\Traversable`` using squared brackets. - -.. code-block:: php - - use Symfony\Component\Form\Form - use Symfony\Component\Form\TextField - - $author = new Author(); - $author->setEmails(array(0 => 'me@example.com')); - - $form = new Form('author'); - $form->add(new EmailField('email', array( - 'property_path' => 'emails[0]', - ))); - $form->bind($request, $author); - - assert('me@example.com' === $form['email']->getData()); - -If the property path is ``null``, the field will neither read from nor write -to the domain object. This is useful if you want to have fields with fixed -values. - -.. code-block:: php - - use Symfony\Component\Form\HiddenField - - $field = new HiddenField('token', array( - 'data' => 'abcdef', - 'property_path' => null, - )); - -Because this is such a common scenario, ``property_path`` is always ``null`` -if you set the ``data`` option. So the last code example can be simplified to: - -.. code-block:: php - - use Symfony\Component\Form\HiddenField - - $field = new HiddenField('token', array( - 'data' => 'abcdef', - )); - -.. note:: - - If you want to set a custom default value but still write to the domain - object, you need to pass ``property_path`` manually. - - .. code-block:: php - - use Symfony\Component\Form\TextField - - $field = new TextField('name', array( - 'data' => 'Custom default...', - 'property_path' => 'token', - )); - - Usually this is not necessary, because you should rather the default value - of the ``token`` property in your domain object. - -Built-in Fields ---------------- - -Symfony2 ships with the following fields: - -.. toctree:: - :hidden: - - fields/index - -.. include:: fields/map.rst.inc - diff --git a/book/forms/fields/BirthdayField.rst b/book/forms/fields/BirthdayField.rst deleted file mode 100644 index c2c446b3b36..00000000000 --- a/book/forms/fields/BirthdayField.rst +++ /dev/null @@ -1,5 +0,0 @@ -BirthdayField -============= - -Documentation for the :class:`Symfony\\Component\\Form\\BirthdayField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/CheckboxField.rst b/book/forms/fields/CheckboxField.rst deleted file mode 100644 index 31ef80ecb92..00000000000 --- a/book/forms/fields/CheckboxField.rst +++ /dev/null @@ -1,5 +0,0 @@ -CheckboxField -============= - -Documentation for the :class:`Symfony\\Component\\Form\\CheckboxField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/ChoiceField.rst b/book/forms/fields/ChoiceField.rst deleted file mode 100644 index 077562024f2..00000000000 --- a/book/forms/fields/ChoiceField.rst +++ /dev/null @@ -1,5 +0,0 @@ -ChoiceField -=========== - -Documentation for the :class:`Symfony\\Component\\Form\\ChoiceField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/CollectionField.rst b/book/forms/fields/CollectionField.rst deleted file mode 100644 index 263d5c1843b..00000000000 --- a/book/forms/fields/CollectionField.rst +++ /dev/null @@ -1,25 +0,0 @@ -CollectionField -=============== - -``CollectionField`` is a special field group for manipulating arrays or objects -that implements the interface ``Traversable``. To demonstrate this, we will -extend the ``Customer`` class to store three email addresses:: - - class Customer - { - // other properties ... - - public $emails = array('', '', ''); - } - -We will now add a ``CollectionField`` to manipulate these addresses:: - - use Symfony\Component\Form\CollectionField; - - $form->add(new CollectionField('emails', array( - 'prototype' => new EmailField(), - ))); - -If you set the option "modifiable" to ``true``, you can even add or remove -rows in the collection via JavaScript! The ``CollectionField`` will notice it -and resize the underlying array accordingly. \ No newline at end of file diff --git a/book/forms/fields/CountryField.rst b/book/forms/fields/CountryField.rst deleted file mode 100644 index f868b4b4154..00000000000 --- a/book/forms/fields/CountryField.rst +++ /dev/null @@ -1,5 +0,0 @@ -CountryField -============ - -Documentation for the :class:`Symfony\\Component\\Form\\CountryField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/DateField.rst b/book/forms/fields/DateField.rst deleted file mode 100644 index 56480dc48fa..00000000000 --- a/book/forms/fields/DateField.rst +++ /dev/null @@ -1,5 +0,0 @@ -DateField -========= - -Documentation for the :class:`Symfony\\Component\\Form\\DateField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/DateTimeField.rst b/book/forms/fields/DateTimeField.rst deleted file mode 100644 index 6541616d73f..00000000000 --- a/book/forms/fields/DateTimeField.rst +++ /dev/null @@ -1,5 +0,0 @@ -DateTimeField -============= - -Documentation for the :class:`Symfony\\Component\\Form\\DateTimeField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/EntityChoiceField.rst b/book/forms/fields/EntityChoiceField.rst deleted file mode 100644 index 6cfcd3029cd..00000000000 --- a/book/forms/fields/EntityChoiceField.rst +++ /dev/null @@ -1,5 +0,0 @@ -EntityChoiceField -================= - -Documentation for the :class:`Symfony\\Component\\Form\\EntityChoiceField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/FileField.rst b/book/forms/fields/FileField.rst deleted file mode 100644 index 88e7ac47a6c..00000000000 --- a/book/forms/fields/FileField.rst +++ /dev/null @@ -1,5 +0,0 @@ -FileField -========= - -Documentation for the :class:`Symfony\\Component\\Form\\FileField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/HiddenField.rst b/book/forms/fields/HiddenField.rst deleted file mode 100644 index fe99815759c..00000000000 --- a/book/forms/fields/HiddenField.rst +++ /dev/null @@ -1,5 +0,0 @@ -HiddenField -=========== - -Documentation for the :class:`Symfony\\Component\\Form\\HiddenField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/IntegerField.rst b/book/forms/fields/IntegerField.rst deleted file mode 100644 index 330e233fab1..00000000000 --- a/book/forms/fields/IntegerField.rst +++ /dev/null @@ -1,5 +0,0 @@ -IntegerField -============ - -Documentation for the :class:`Symfony\\Component\\Form\\IntegerField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/LanguageField.rst b/book/forms/fields/LanguageField.rst deleted file mode 100644 index 9177c5de156..00000000000 --- a/book/forms/fields/LanguageField.rst +++ /dev/null @@ -1,5 +0,0 @@ -LanguageField -============= - -Documentation for the :class:`Symfony\\Component\\Form\\LanguageField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/LocaleField.rst b/book/forms/fields/LocaleField.rst deleted file mode 100644 index e30f31a8132..00000000000 --- a/book/forms/fields/LocaleField.rst +++ /dev/null @@ -1,5 +0,0 @@ -LocaleField -=========== - -Documentation for the :class:`Symfony\\Component\\Form\\LocaleField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/MoneyField.rst b/book/forms/fields/MoneyField.rst deleted file mode 100644 index cf128174bfb..00000000000 --- a/book/forms/fields/MoneyField.rst +++ /dev/null @@ -1,5 +0,0 @@ -MoneyField -========== - -Documentation for the :class:`Symfony\\Component\\Form\\MoneyField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/NumberField.rst b/book/forms/fields/NumberField.rst deleted file mode 100644 index 484034aae91..00000000000 --- a/book/forms/fields/NumberField.rst +++ /dev/null @@ -1,5 +0,0 @@ -NumberField -=========== - -Documentation for the :class:`Symfony\\Component\\Form\\NumberField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/PasswordField.rst b/book/forms/fields/PasswordField.rst deleted file mode 100644 index 11329bfd3dd..00000000000 --- a/book/forms/fields/PasswordField.rst +++ /dev/null @@ -1,5 +0,0 @@ -PasswordField -============= - -Documentation for the :class:`Symfony\\Component\\Form\\PasswordField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/PercentField.rst b/book/forms/fields/PercentField.rst deleted file mode 100644 index 725323c838f..00000000000 --- a/book/forms/fields/PercentField.rst +++ /dev/null @@ -1,5 +0,0 @@ -PercentField -============ - -Documentation for the :class:`Symfony\\Component\\Form\\PercentField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/RepeatedField.rst b/book/forms/fields/RepeatedField.rst deleted file mode 100644 index 5d82f45bcfd..00000000000 --- a/book/forms/fields/RepeatedField.rst +++ /dev/null @@ -1,12 +0,0 @@ -RepeatedField -============= - -The ``RepeatedField`` is an extended field group that allows you to output a -field twice. The repeated field will only validate if the user enters the same -value in both fields:: - - use Symfony\Component\Form\RepeatedField; - - $form->add(new RepeatedField(new TextField('email'))); - -This is a very useful field for querying email addresses or passwords! \ No newline at end of file diff --git a/book/forms/fields/TextField.rst b/book/forms/fields/TextField.rst deleted file mode 100644 index d04b6af92dd..00000000000 --- a/book/forms/fields/TextField.rst +++ /dev/null @@ -1,5 +0,0 @@ -TextField -========= - -Documentation for the :class:`Symfony\\Component\\Form\\TextField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/TextareaField.rst b/book/forms/fields/TextareaField.rst deleted file mode 100644 index 748418b626d..00000000000 --- a/book/forms/fields/TextareaField.rst +++ /dev/null @@ -1,5 +0,0 @@ -TextareaField -============= - -Documentation for the :class:`Symfony\\Component\\Form\\TextareaField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/TimeField.rst b/book/forms/fields/TimeField.rst deleted file mode 100644 index ac277c9ca60..00000000000 --- a/book/forms/fields/TimeField.rst +++ /dev/null @@ -1,5 +0,0 @@ -TimeField -========= - -Documentation for the :class:`Symfony\\Component\\Form\\TimeField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/TimezoneField.rst b/book/forms/fields/TimezoneField.rst deleted file mode 100644 index 5d4c550c62f..00000000000 --- a/book/forms/fields/TimezoneField.rst +++ /dev/null @@ -1,5 +0,0 @@ -TimezoneField -============= - -Documentation for the :class:`Symfony\\Component\\Form\\TimezoneField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/UrlField.rst b/book/forms/fields/UrlField.rst deleted file mode 100644 index 7f8c2041a89..00000000000 --- a/book/forms/fields/UrlField.rst +++ /dev/null @@ -1,5 +0,0 @@ -UrlField -======== - -Documentation for the :class:`Symfony\\Component\\Form\\UrlField` -class is currently only available via the generated API. \ No newline at end of file diff --git a/book/forms/fields/index.rst b/book/forms/fields/index.rst deleted file mode 100644 index e72a473c036..00000000000 --- a/book/forms/fields/index.rst +++ /dev/null @@ -1,34 +0,0 @@ -Built-in Fields -=============== - -Symfony2 ships with the following fields: - -.. toctree:: - :maxdepth: 2 - :hidden: - - BirthdayField - CheckboxField - ChoiceField - CollectionField - CountryField - DateField - DateTimeField - EntityChoiceField - FileField - HiddenField - IntegerField - LanguageField - LocaleField - MoneyField - NumberField - PasswordField - PercentField - RepeatedField - TextareaField - TextField - TimeField - TimezoneField - UrlField - -.. include:: map.rst.inc diff --git a/book/forms/fields/map.rst.inc b/book/forms/fields/map.rst.inc deleted file mode 100644 index 39c14b411fe..00000000000 --- a/book/forms/fields/map.rst.inc +++ /dev/null @@ -1,23 +0,0 @@ -* :doc:`BirthdayField ` -* :doc:`CheckboxField ` -* :doc:`ChoiceField ` -* :doc:`CollectionField ` -* :doc:`CountryField ` -* :doc:`DateField ` -* :doc:`DateTimeField ` -* :doc:`EntityChoiceField ` -* :doc:`FileField ` -* :doc:`HiddenField ` -* :doc:`IntegerField ` -* :doc:`LanguageField ` -* :doc:`LocaleField ` -* :doc:`MoneyField ` -* :doc:`NumberField ` -* :doc:`PasswordField ` -* :doc:`PercentField ` -* :doc:`RepeatedField ` -* :doc:`TextareaField ` -* :doc:`TextField ` -* :doc:`TimeField ` -* :doc:`TimezoneField ` -* :doc:`UrlField ` diff --git a/book/forms/index.rst b/book/forms/index.rst deleted file mode 100644 index bf49e608bce..00000000000 --- a/book/forms/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -Symfony2 Forms -============== - -.. toctree:: - :maxdepth: 2 - - overview - fields - view diff --git a/book/forms/overview.rst b/book/forms/overview.rst deleted file mode 100755 index 10aaa6829de..00000000000 --- a/book/forms/overview.rst +++ /dev/null @@ -1,370 +0,0 @@ -.. index:: - single: Forms - -Working with Forms -================== - -Symfony2 comes with a built-in form component. It deals with displaying, -rendering and submitting HTML forms. - -While it is possible to process form submissions with Symfony2's -:class:`Symfony\\Component\\HttpFoundation\\Request` class alone, the form -component takes care of a number of common form-related tasks, such as: - -1. Displaying an HTML form with automatically generated form fields -2. Converting the submitted data to PHP data types -3. Reading from and writing data into POPOs (plain old PHP objects) -4. Validating submitted form data with Symfony2's ``Validator`` -5. Protecting form submissions against CSRF attacks - -Overview --------- - -The component deals with these concepts: - -*Field* - A class that converts submitted data to normalized values. - -*Form* - A collection of fields that knows how to validate itself. - -*Template* - A file that renders a form or a field in HTML. - -*Domain objects* - An object a form uses to populate default values and where submitted - data is written. - -The form component only relies on the HttpFoundation and Validator -components to work. If you want to use the internationalization features, -PHP's intl extension is required as well. - -Form Objects ------------- - -A Form object encapsulates a collection of fields that convert submitted -data to the format used in your application. Form classes are created as -subclasses of :class:`Symfony\\Component\\Form\\Form`. You should implement the -method ``configure()`` to initialize the form with a set of fields. - -.. code-block:: php - - // src/Sensio/HelloBundle/Contact/ContactForm.php - namespace Sensio\HelloBundle\Contact; - - use Symfony\Component\Form\Form; - use Symfony\Component\Form\TextField; - use Symfony\Component\Form\TextareaField; - use Symfony\Component\Form\CheckboxField; - - class ContactForm extends Form - { - protected function configure() - { - $this->add(new TextField('subject', array( - 'max_length' => 100, - ))); - $this->add(new TextareaField('message')); - $this->add(new TextField('sender')); - $this->add(new CheckboxField('ccmyself', array( - 'required' => false, - ))); - } - } - -A form consists of ``Field`` objects. In this case, our form has the fields -``subject``, ``message``, ``sender`` and ``ccmyself``. ``TextField``, -``TextareaField`` and ``CheckboxField`` are only three of the -available form fields; a full list can be found in :doc:`Form fields -`. - -Using a Form in a Controller ----------------------------- - -The standard pattern for using a form in a controller looks like this: - -.. code-block:: php - - // src/Sensio/HelloBundle/Controller/HelloController.php - public function contactAction() - { - $contactRequest = new ContactRequest($this->get('mailer')); - $form = ContactForm::create($this->get('form.context'), 'contact'); - - // If a POST request, write the submitted data into $contactRequest - // and validate the object - $form->bind($this->get('request'), $contactRequest); - - // If the form has been submitted and is valid... - if ($form->isValid()) { - $contactRequest->send(); - } - - // Display the form with the values in $contactRequest - return $this->render('HelloBundle:Hello:contact.html.twig', array( - 'form' => $form - )); - } - -There are two code paths there: - -1. If the form has not been submitted or is invalid, it is simply passed to - the template. -2. If the form has been submitted and is valid, the contact request is sent. - -We created the form with the static ``create()`` method. This method expects -a form context that contains all default services (for example a ``Validator``) -and settings that a form needs to work. - -.. note: - - If you don't use Symfony2 or its service container, don't worry. You can - easily create a ``FormContext`` and a ``Request`` manually: - - .. code-block:: php - - use Symfony\Component\Form\FormContext; - use Symfony\Component\HttpFoundation\Request; - - $context = FormContext::buildDefault(); - $request = Request::createFromGlobals(); - -Forms and Domain Objects ------------------------- - -In the last example a ``ContactRequest`` was bound to the form. The property -values of this object are used to populate the form fields. After binding, -the submitted values are written into the object again. The ``ContactRequest`` -class could look like this: - -.. code-block:: php - - // src/Sensio/HelloBundle/Contact/ContactRequest.php - namespace Sensio\HelloBundle\Contact; - - class ContactRequest - { - protected $subject = 'Subject...'; - - protected $message; - - protected $sender; - - protected $ccmyself = false; - - protected $mailer; - - public function __construct(\Swift_Mailer $mailer) - { - $this->mailer = $mailer; - } - - public function setSubject($subject) - { - $this->subject = $subject; - } - - public function getSubject() - { - return $this->subject; - } - - // Setters and getters for the other properties - // ... - - public function send() - { - // Send the contact mail - $message = \Swift_Message::newInstance() - ->setSubject($this->subject) - ->setFrom($this->sender) - ->setTo('me@example.com') - ->setBody($this->message); - - $this->mailer->send($message); - } - } - -.. note:: - - See :doc:`Emails ` for more information on sending mails. - -For each field in your form, the class of the domain object needs to have - -1. A public property with the field's name, or -2. A public setter and getter with the prefix "set"/"get", followed by the - field's name with a first capital letter. - -Validating Submitted Data -------------------------- - -The form uses the ``Validator`` component to validate submitted form values. -All constraints on the domain object, on the form and on its fields will be -validated when ``bind()`` is called. We will add a few constraints to -``ContactRequest`` to make sure that nobody can submit the form with invalid -data. - -.. code-block:: php - - // src/Sensio/HelloBundle/Contact/ContactRequest.php - namespace Sensio\HelloBundle\Contact; - - class ContactRequest - { - /** - * @validation:MaxLength(100) - * @validation:NotBlank - */ - protected $subject = 'Subject...'; - - /** - * @validation:NotBlank - */ - protected $message; - - /** - * @validation:Email - * @validation:NotBlank - */ - protected $sender; - - /** - * @validation:AssertType("boolean") - */ - protected $ccmyself = false; - - // Other code... - } - -If any constraint fails, the error is displayed next to the corresponding -form field. You can learn more about constraints in :doc:`Validation -Constraints `. - -Creating Form Fields Automatically ----------------------------------- - -If you use Doctrine2 or Symfony's ``Validator``, Symfony already knows quite -a lot about your domain classes. It knows which data type is used to persist -a property in the database, what validation constraints the property has etc. -The Form component can use this information to "guess" which field type should -be created with which settings. - -To use this feature, a form needs to know the class of the related domain -object. You can set this class within the ``configure()`` method of the form -by using ``setDataClass()`` and passing the fully qualified class name as -a string. Calling ``add()`` with only the name of the property will then -automatically create the best-matching field. - -.. code-block:: php - - // src/Sensio/HelloBundle/Contact/ContactForm.php - class ContactForm extends Form - { - protected function configure() - { - $this->setDataClass('Sensio\\HelloBundle\\Contact\\ContactRequest'); - $this->add('subject'); // TextField with max_length=100 because - // of the @MaxLength constraint - $this->add('message'); // TextField - $this->add('sender'); // EmailField because of the @Email constraint - $this->add('ccmyself'); // CheckboxField because of @AssertType("boolean") - } - } - -These field guesses are obviously not always right. For the property ``message`` -Symfony created a ``TextField``, it couldn't know from the validation constraints -that you wanted a ``TextareaField`` instead. So you have to create this field -manually. You can also tweak the options of the generated fields by passing -them in the second parameter. We will add a ``max_length`` option to the -``sender`` field to limit its length. - -.. code-block:: php - - // src/Sensio/HelloBundle/Contact/ContactForm.php - class ContactForm extends Form - { - protected function configure() - { - $this->setDataClass('Sensio\\HelloBundle\\Contact\\ContactRequest'); - $this->add('subject'); - $this->add(new TextareaField('message')); - $this->add('sender', array('max_length' => 50)); - $this->add('ccmyself'); - } - } - -Generating form fields automatically helps you to increase your development -speed and reduces code duplication. You can store information about class -properties once and let Symfony2 do the other work for you. - -Rendering Forms as HTML ------------------------ - -In the controller we passed the form to the template in the ``form`` variable. -In the template we can use the ``form_field`` helper to output a raw prototype -of the form. - -.. code-block:: html+jinja - - # src/Sensio/HelloBundle/Resources/views/Hello/contact.html.twig - {% extends 'HelloBundle::layout.html.twig' %} - - {% block content %} - - {{ form_field(form) }} - - - - {% endblock %} - -Customizing the HTML Output ---------------------------- - -In most applications you will want to customize the HTML of the form. You -can do so by using the other built-in form rendering helpers. - -.. code-block:: html+jinja - - # src/Sensio/HelloBundle/Resources/views/Hello/contact.html.twig - {% extends 'HelloBundle::layout.html.twig' %} - - {% block content %} -
- {{ form_errors(form) }} - - {% for field in form %} - {% if not field.ishidden %} -
- {{ form_errors(field) }} - {{ form_label(field) }} - {{ form_field(field) }} -
- {% endif %} - {% endfor %} - - {{ form_hidden(form) }} - -
- {% endblock %} - -Symfony2 comes with the following helpers: - -*``form_enctype``* - Outputs the ``enctype`` attribute of the form tag. Required for file uploads. - -*``form_errors``* - Outputs the a ``
    `` tag with errors of a field or a form. - -*``form_label``* - Outputs the ``