diff --git a/guides/validator.rst b/guides/validator.rst index 5ce63091802..ca1a269bdd3 100644 --- a/guides/validator.rst +++ b/guides/validator.rst @@ -2,19 +2,19 @@ single: Forms; Validators single: Validators -Validator +Validador ========= -The Basics +O Básico ---------- -The new Validator component is based on the `JSR303 Bean Validation -specification`_. What? A Java specification in PHP? You heard right, but -it's not as bad as it sounds. Let's look at how we use it in PHP. +O novo componente validador é baseado na `Especificação de Validação JSR303 Bean`_. +O quê? A especificação do Java no PHP? Você ouviu direito, +mas não é tão ruim quanto parece. Vamos ver como usá-la em PHP. -The Validator is designed to validate objects against different constraints. -These constraints can be put on the class itself, on properties and on -methods prefixed with "get" or "is". Let's look at a sample configuration:: +O Validador é projetado para validar objetos de encontro a diferentes constraints. +Estas constraints podem ser colocadas na própria classe, em propriedades e nos +métodos prefixados com "get" ou "is". Vejamos um exemplo de configuração:: class Author { @@ -28,7 +28,7 @@ methods prefixed with "get" or "is". Let's look at a sample configuration:: /** * @Validation({ - * @Email(message="Ok, seriously now. Your email address please") + * @Email(message="Ok, sério agora. Seu endereço de e-mail, por favor") * }) */ public function getEmail() @@ -36,14 +36,14 @@ methods prefixed with "get" or "is". Let's look at a sample configuration:: return 'foobar'; } } - -This snippet shows a very simple ``Author`` class with a property and a getter. -Each constraint has a name, most of them also have a couple of options. Here we -configured the constraints with annotations, but Symfony2 also offers many -other configuration drivers. -Because the annotation driver depends on the Doctrine library, it is not enabled -by default. You can enable it in your ``config.yml``: +Este trecho de código mostra uma classe ``Author`` muito simples com uma propriedade +e um getter. Cada constraint tem um nome, e a maioria deles também tem algumas +opções. Aqui nós configuramos as constraints com anotações, mas o Symfony2 também +oferece muitos outros drivers de configuração. + +Devido ao driver de anotação depender da biblioteca Doctrine, ele não é habilitado +por padrão. Você pode habilitá-lo em seu ``config.yml``: .. code-block:: yaml @@ -51,7 +51,7 @@ by default. You can enable it in your ``config.yml``: web.validation: annotations: true -Now let's try to validate an object:: +Agora vamos tentar validar um objeto:: $validator = $this->container->getValidatorService(); @@ -60,72 +60,72 @@ Now let's try to validate an object:: print $validator->validate($author); -You should see the following output:: +Você deverá ver o seguinte resultado:: Author.firstName: This value is too short. It should have 4 characters or more Author.email: - Ok, seriously now. Your email address please + Ok, sério agora. Seu endereço de email, por favor -The ``validate()`` method returns a ``ConstraintViolationList`` object that can -simply be printed or processed in your code. That was easy! +O método ``validate()`` retorna um objeto ``ConstraintViolationList`` que pode +simplesmente ser impresso ou processado em seu código. Essa foi fácil! .. index:: single: Validators; Constraints -The Constraints ---------------- +AS Constraints +-------------- -Symfony bundles many different constraints. The following list will show you -which ones are available and how you can use and configure them. Some -constraints have a default option. If you only set this option, you can leave -away the option name:: +O Symfony possui muitas constraints diferentes. A lista a seguir irá mostrar-lhe +quais estão disponíveis e como você pode usar e configurá-las. Algumas +constraints têm uma opção padrão. Se você apenas definir essa opção, +você pode omitir o seu nome:: /** @Validation({ @Min(limit=3) }) */ -is identical to:: +é idêntico à:: /** @Validation({ @Min(3) }) */ AssertFalse ~~~~~~~~~~~ -Validates that a value is ``false``. Very useful for testing return values of -methods:: +Valida se um valor é ``false``. Muito útil para testar os valores de retorno dos +métodos:: /** @Validation({ @AssertFalse }) */ public function isInjured(); -Options: +Opções: -* message: The error message if validation fails +* message: A mensagem de erro se a validação falhar AssertTrue ~~~~~~~~~~ -Works like ``AssertFalse``. +Funciona como o ``AssertFalse``. NotBlank ~~~~~~~~ -Validates that a value is not empty:: +Valida se um valor não está vazio:: /** @Validation({ @NotBlank }) */ private $firstName; -Options: +Opções: -* message: The error message if validation fails +* message: A mensagem de erro se a validação falhar Blank ~~~~~ -Works like ``NotBlank``. +Funciona como o ``NotBlank``. NotNull ~~~~~~~ -Validates that a value is not ``NULL``:: +Valida se um valor não é ``NULL``:: /** @Validation({ @NotNull }) */ private $firstName; @@ -133,59 +133,59 @@ Validates that a value is not ``NULL``:: Null ~~~~ -Works like ``NotNull``. +Funciona como o ``NotNull``. AssertType ~~~~~~~~~~ -Validates that a value has a specific data type:: +Valida se um valor tem um tipo de dados específico:: /** @Validation({ @AssertType("integer") }) */ private $age; -Options: +Opções: * type (default): The type Choice ~~~~~~ -Validates that a value is one or more of a list of choices:: +Valida se um valor é um ou mais de uma lista de opções:: /** @Validation({ @Choice({"male", "female"}) }) */ private $gender; -Options: +Opções: -* choices (default): The available choices -* callback: Can be used instead of ``choices``. A static callback method - returning the choices. If you set this to a string, the method is expected - to be in the validated class. -* multiple: Whether multiple choices are allowed. Default: ``false`` -* min: The minimum amount of selected choices -* max: The maximum amount of selected choices -* message: The error message if validation fails -* minMessage: The error message if ``min`` validation fails -* maxMessage: The error message if ``max`` validation fails +* choices (default): As opções disponíveis +* callback: Pode ser usado em vez do ``choices``. Um método callback estático + retornando as escolhas. Se você definir como uma string, o método deve estar + na classe validada. +* multiple: Se são permitidas escolhas múltiplas. Default: ``false`` +* min: A quantidade mínima de opções selecionadas +* max: A quantidade máxima de opções selecionadas +* message: A mensagem de erro se a validação falhar +* minMessage: A mensagem de erro se a validação ``min`` falhar +* maxMessage: A mensagem de erro se a validação ``max`` falhar Valid ~~~~~ -Validates that an object is valid. Can be put on properties or getters to -validate related objects:: +Valida se um objeto é válido. Pode ser colocado em propriedades ou getters para +validar objetos relacionados:: /** @Validation({ @Valid }) */ private $address; -Options: +Opções: -* class: The expected class of the object (optional) -* message: The error message if the class doesn't match +* class: A classe esperada do objeto (opcional) +* message: A mensagem de erro se a classe não corresponde Collection ~~~~~~~~~~ -Validates array entries against different constraints:: +Valida entradas de array comparando a diferentes constraints:: /** * @Validation({ @Collection( @@ -198,167 +198,163 @@ Validates array entries against different constraints:: */ private $options = array(); -Options: - -* fields (default): An associative array of array keys and one or more - constraints -* allowMissingFields: Whether some of the keys may not be present in the - array. Default: ``false`` -* allowExtraFields: Whether the array may contain keys not present in the - ``fields`` option. Default: ``false`` -* missingFieldsMessage: The error message if the ``allowMissingFields`` - validation fails -* allowExtraFields: The error message if the ``allowExtraFields`` validation - fails +Opções: + +* fields (default): Um array associativo de chaves de array e uma ou mais constraints +* allowMissingFields: Se alguma das chaves não estão presentes no array. Default: ``false`` +* allowExtraFields: Se o array pode conter chaves não presentes na opção + ``fields``. Default: ``false`` +* missingFieldsMessage: A mensagem de erro se a validação ``allowMissingFields`` + falhar +* allowExtraFields: A mensagem de erro se a validação ``allowExtraFields`` falhar Date ~~~~ -Validates that a value is a valid date string with format ``YYYY-MM-DD``:: +Valida se um valor é uma string de data válida com o formato ``YYYY-MM-DD``:: /** @Validation({ @Date }) */ private $birthday; -Options: +Opções: -* message: The error message if the validation fails +* message: A mensagem de erro se a validação falhar DateTime ~~~~~~~~ -Validates that a value is a valid datetime string with format ``YYYY-MM-DD +Valida se um valor é uma string datetime válida com o formato ``YYYY-MM-DD HH:MM:SS``:: /** @Validation({ @DateTime }) */ private $createdAt; -Options: +Opções: -* message: The error message if the validation fails +* message: A mensagem de erro se a validação falhar Time ~~~~ -Validates that a value is a valid time string with format ``HH:MM:SS``:: +Valida se um valor é uma string de tempo válida com o formato ``HH:MM:SS``:: /** @Validation({ @Time }) */ private $start; -Options: +Opções: -* message: The error message if the validation fails +* message: A mensagem de erro se a validação falhar Email ~~~~~ -Validates that a value is a valid email address:: +Valida se um valor é um endereço de e-mail válido:: /** @Validation({ @Email }) */ private $email; -Options: +Opções: -* message: The error message if the validation fails -* checkMX: Whether MX records should be checked for the domain. Default: ``false`` +* message: A mensagem de erro se a validação falhar +* checkMX: Se os registros MX devem ser verificados para o domínio. Default: ``false`` File ~~~~ -Validates that a value is an existing file:: +Valida se um valor é um arquivo existentee:: /** @Validation({ @File(maxSize="64k") }) */ private $filename; -Options: +Opções: -* maxSize: The maximum allowed file size. Can be provided in bytes, kilobytes - (with the suffix "k") or megabytes (with the suffix "M") -* mimeTypes: One or more allowed mime types -* notFoundMessage: The error message if the file was not found -* notReadableMessage: The error message if the file could not be read -* maxSizeMessage: The error message if ``maxSize`` validation fails -* mimeTypesMessage: The error message if ``mimeTypes`` validation fails +* maxSize: O tamanho máximo permitido. Pode ser fornecido em bytes, kilobytes (com o sufixo "k") ou megabytes (com o sufixo "M") +* mimeTypes: Um ou mais tipos mime permitidos +* notFoundMessage: A mensagem de erro se o arquivo não foi encontrado +* notReadableMessage: A mensagem de erro se o arquivo não pôde ser lido +* maxSizeMessage: A mensagem de erro se a validação ``maxSize`` falhar +* mimeTypesMessage: A mensagem de erro se a validação ``mimeTypes`` falhar Max ~~~ -Validates that a value is at most the given limit:: +Valida se um valor está no máximo do limite estabelecido:: /** @Validation({ @Max(99) }) */ private $age; -Options: +Opções: -* limit (default): The limit -* message: The error message if validation fails +* limit (default): O limite +* message: A mensagem de erro se a validação falhar Min ~~~ -Works like ``Max``. +Funciona como o ``Max``. MaxLength ~~~~~~~~~ -Validates that the string length of a value is at most the given limit:: +Valida se o comprimento da string do valor está no máximo do limite estabelecido:: /** @Validation({ @MaxLength(32) }) */ private $hash; -Options: +Opções: -* limit (default): The size limit -* message: The error message if validation fails +* limit (default): O tamanho do limite +* message: A mensagem de erro se a validação falhar MinLength ~~~~~~~~~ -Works like ``MaxLength``. +Funciona como o ``MaxLength``. Regex ~~~~~ -Validates that a value matches the given regular expression:: +Valida se um valor corresponde à expressão regular fornecida:: /** @Validation({ @Regex("/\w+/") }) */ private $title; -Options: +Opções: -* pattern (default): The regular expression pattern -* match: Whether the pattern must be matched or must not be matched. +* pattern (default): O padrão da expressão regular +* match: Se o padrão deve ou não corresponder. Default: ``true`` -* message: The error message if validation fails +* message: A mensagem de erro se a validação falhar Url ~~~ -Validates that a value is a valid URL:: +Valida se um valor é uma URL válida:: /** @Validation({ @Url }) */ private $website; -Options: +Opções: -* protocols: A list of allowed protocols. Default: "http", "https", "ftp" - and "ftps". -* message: The error message if validation fails +* protocols: A lista de protocolos permitidos. Default: "http", "https", "ftp" + e "ftps". +* message: A mensagem de erro se a validação falhar .. index:: single: Validators; Configuration -Other Configuration Drivers ---------------------------- +Outros drivers de configuração +------------------------------ -As always in Symfony, there are multiple ways of configuring the constraints -for your classes. Symfony supports the following four drivers. +Como sempre no Symfony, existem várias maneiras de configurar as constraints para +as suas classes. O Symfony suporta os quatro seguintes drivers. -XML Configuration -~~~~~~~~~~~~~~~~~ +Configuração XML +~~~~~~~~~~~~~~~~ -The XML driver is a little verbose, but has the benefit that the XML file can be -validated to prevent errors. To use the driver, simply put a file called -``validation.xml`` in the ``Resources/config/`` directory of your bundle: +O driver XML é um pouco prolixo, mas tem a vantagem de que o arquivo XML pode +ser validado para evitar erros. Para usar o driver, basta colocar um arquivo +chamado ``validation.xml`` no diretório ``Resources/config/`` do seu pacote (bundle): .. code-block:: xml @@ -381,12 +377,12 @@ validated to prevent errors. To use the driver, simply put a file called -YAML Configuration -~~~~~~~~~~~~~~~~~~ +Configuração YAML +~~~~~~~~~~~~~~~~~ -The YAML driver offers the same functionality as the XML driver. To use it, -put the file ``validation.yml`` in the ``Resources/config/`` directory of your -bundle: +O driver YAML oferece a mesma funcionalidade do driver XML. Para usá-lo, +coloque o arquivo ``validation.yml`` no diretório``Resources/config/`` do seu +pacote (bundle): .. code-block:: yaml @@ -398,13 +394,13 @@ bundle: getters: email: - - Email: { message: "Ok, seriously now. Your email address please" } + - Email: { message: "Ok, sério agora. Seu endereço de e-mail, por favor" } -PHP Configuration -~~~~~~~~~~~~~~~~~ +Configuração PHP +~~~~~~~~~~~~~~~~ -If you prefer to write configurations in plain old PHP, you can add the static -method ``loadValidatorMetadata()`` to the classes that you want to validate:: +Se você preferir gravar as configurações em velho plain PHP, você pode adicionar +o método estático ``loadValidatorMetadata()`` para as classes que você deseja validar: use Symfony\Components\Validator\Constraints; use Symfony\Components\Validator\Mapping\ClassMetadata; @@ -421,7 +417,7 @@ method ``loadValidatorMetadata()`` to the classes that you want to validate:: } } -You can use either of the configuration drivers, or all together. Symfony will -merge all the information it can find. +Você pode usar qualquer um dos drivers de configuração, ou todos juntos. +O symfony irá fazer o merge de todas as informações que puder encontrar. -.. _JSR303 Bean Validation specification: http://jcp.org/en/jsr/detail?id=303 +.. _Especificação de Validação JSR303 Bean: http://jcp.org/en/jsr/detail?id=303 diff --git a/pt_BR/contributing/code/bugs.rst b/pt_BR/contributing/code/bugs.rst new file mode 100644 index 00000000000..2648968a06c --- /dev/null +++ b/pt_BR/contributing/code/bugs.rst @@ -0,0 +1,32 @@ +Reporting a Bug +=============== + +Whenever you find a bug in Symfony, we kindly ask you to report it. It helps +us make a better Symfony. + +.. caution:: + If you think you've found a security issue, please use the special + doc:`procedure ` instead. + +Before submitting a bug: + + * Double-check the official documentation to see if you're not misusing the + framework; + + * Ask assistance on the users mailing-list or on the #symfony IRC channel if + you're not sure if your issue is really a bug. + +If your problem definitely looks like a bug, report it using the official bug +`tracker`_ and follow some basic rules: + + * Use the title field to clearly describe the issue; + + * Describe the steps needed to reproduce the bug with short code examples + (providing a unit test that illustrates the bug is better); + + * Give as much details as possible about your environment (OS, PHP version, + Symfony version, extension enabled, ...); + + * *(optional)* Attach a :doc:`patch `. + +.. _tracker: http://trac.symfony-project.org/ diff --git a/pt_BR/contributing/code/index.rst b/pt_BR/contributing/code/index.rst new file mode 100644 index 00000000000..fd6a1506202 --- /dev/null +++ b/pt_BR/contributing/code/index.rst @@ -0,0 +1,12 @@ +Contributing Code +================= + +.. toctree:: + :maxdepth: 2 + + bugs + patches + security + standards + tests + license diff --git a/pt_BR/contributing/code/license.rst b/pt_BR/contributing/code/license.rst new file mode 100644 index 00000000000..ba7e7345e92 --- /dev/null +++ b/pt_BR/contributing/code/license.rst @@ -0,0 +1,37 @@ +Symfony2 License +================ + +Symfony2 is released under the MIT license. + +According to `Wikipedia`_: + + "It is a permissive license, meaning that it permits reuse within + proprietary software on the condition that the license is distributed with + that software. The license is also GPL-compatible, meaning that the GPL + permits combination and redistribution with software that uses the MIT + License." + +The License +----------- + +Copyright (c) 2004-2010 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +.. _Wikipedia: http://en.wikipedia.org/wiki/MIT_License diff --git a/pt_BR/contributing/code/patches.rst b/pt_BR/contributing/code/patches.rst new file mode 100644 index 00000000000..be11f39ee6e --- /dev/null +++ b/pt_BR/contributing/code/patches.rst @@ -0,0 +1,143 @@ +Submitting a Patch +================== + +Patches are the best way to provide a bug fix or to propose enhancements to +Symfony. + +Initial Setup +------------- + +Before working on Symfony2, setup a friendly environment with the following +software: + +* Git; + +* PHP version 5.3.2 or above; + +* PHPUnit 3.5.0 or above. + +Set up your user information with your real name and a working email address: + +.. code-block:: bash + + $ git config --global user.name "Your Name" + $ git config --global user.email you@example.com + +.. tip:: + If you are new to Git, we highly recommend you to read the excellent and free + `ProGit`_ book. + +Get the Symfony2 code source: + +* Create a `Github`_ account and sign in; + +* Fork the `Symfony2 repository`_ (click on the "Fork" button); + +* After the "hardcore forking action" has completed, clone your fork locally + (this will create a `symfony` directory): + +.. code-block:: bash + + $ git clone git@github.com:USERNAME/symfony.git + +* Add the upstream repository as remote: + +.. code-block:: bash + + $ cd symfony + $ git remote add upstream git://github.com/fabpot/symfony.git + +Now that Symfony2 is installed, check that all unit tests pass for your +environment as explained in the dedicated :doc:`document `. + +Working on a Patch +------------------ + +Each time you want to work on a patch for a bug or on an enhancement, create a +topic branch: + +.. code-block:: bash + + $ git checkout -b BRANCH_NAME + +.. tip:: + Use a descriptive name for your branch (`ticket_XXX` where `XXX` is the ticket + number is a good convention for bug fixes). + +The above command automatically switches the code to the newly created branch +(check the branch you are working on with `git branch`.) + +Work on the code as much as you want and commit as much as you want; but keep +in mind the following: + +* Follow the coding :doc:`standards ` (use `git diff --check` to + check for trailing spaces); + +* Add unit tests to prove that the bug is fixed or that the new feature + actually works; + +* Do atomic and logically separate commits (use the power of `git rebase` to + have a clean and logical history); + +* Write good commit messages. + +.. tip:: + A good commit message is composed of a summary (the first line), optionally + followed by a blank line and a more detailed description. The summary should + start with the Component you are working on in square brackets + (`[DependencyInjection]`, `[FoundationBundle]`, ...). Use a verb (`fixed ...`, + `added ...`, ...) to start the summary and don't add a period at the end. + +Submitting a Patch +------------------ + +Before submitting your patch, update your branch (needed if it takes you a +while to finish your changes): + +.. code-block:: bash + + $ git checkout master + $ git fetch upstream + $ git merge upstream/master + $ git checkout BRANCH_NAME + $ git rebase master + +When doing the `rebase` command, you might have to fix merge conflicts. `git +st` gives you the *unmerged* files. Resolve all conflicts, then continue the +rebase: + +.. code-block:: bash + + $ git add ... # add resolved files + $ git rebase --continue + +Check that all tests still pass and push your branch remotely: + +.. code-block:: bash + + $ git push origin BRANCH_NAME + +You can now advertise your patch on the `dev mailing-list`_. The email must +follow the following conventions: + +* Subject must start with `[PATCH]`, followed by a short summary of the + patch (with a reference to the ticket if it's a bug fix - `#XXX`); + +* The body must contain the information about your branch + (`git://github.com/USERNAME/symfony.git BRANCH_NAME`); + +* The body must then describe what the patch does (reference a ticket, or + copy and paste the commit message). + +Based on the feedback, you might need to rework your patch. Before +re-submitting the patch, rebase with master, don't merge; and force the push +to the origin: + +.. code-block:: bash + + $ git push -f origin BRANCH_NAME + +.. _ProGit: http://progit.org/ +.. _Github: https://github.com/signup/free +.. _Symfony2 repository: http://www.github.com/fabpot/symfony +.. _dev mailing-list: http://groups.google.com/group/symfony-devs diff --git a/pt_BR/contributing/code/security.rst b/pt_BR/contributing/code/security.rst new file mode 100644 index 00000000000..b60d21e840f --- /dev/null +++ b/pt_BR/contributing/code/security.rst @@ -0,0 +1,20 @@ +Reporting a Security Issue +========================== + +Found a security issue in Symfony? Don't use the mailing-list or the bug +tracker. All security issues must be sent to **security [at] +symfony-project.com** instead. Emails sent to this address are forwarded to +the Symfony core-team private mailing-list. + +For each report, we first try to confirm the vulnerability. When it is +confirmed, the core-team works on a solution following these steps: + +1. Send an acknowledgement to the reporter; +2. Work on a patch; +3. Write a post describing the vulnerability, the possible exploits, and how + to patch/upgrade affected applications; +4. Apply the patch to all maintained versions of Symfony; +5. Publish the post on the official Symfony blog. + +.. note:: + While we are working on a patch, please do not reveal the issue publicly. diff --git a/pt_BR/contributing/code/standards.rst b/pt_BR/contributing/code/standards.rst new file mode 100644 index 00000000000..989a671d573 --- /dev/null +++ b/pt_BR/contributing/code/standards.rst @@ -0,0 +1,76 @@ +Coding Standards +================ + +When contributing code to Symfony, you must follow its coding standards. To +make a long story short, here is the golden rule: *Imitate the existing +Symfony code*. + +Structure +--------- + +* Never use short tags (`` closing tag; + +* Indentation is done by steps of four spaces (tabs are never allowed); + +* Use the linefeed character (`0x0A`) to end lines; + +* Add a single space after each comma delimiter; + +* Don't put spaces after an opening parenthesis and before a closing one; + +* Add a single space around operators (`==`, `&&`, ...); + +* Add a single space before the opening parenthesis of a control keyword + (`if`, `else`, `for`, `while`, ...); + +* Add a blank line before `return` statements; + +* Don't add trailing spaces at the end of lines; + +* Use braces to indicate control structure body regardless of the number of + statements it contains; + +* Put braces on their own line for classes, methods, and functions + declaration; + +* Separate the conditional statement and the opening brace with a single + space and no blank line; + +* Declare visibility explicitly for class, methods, and properties (usage of + `var` is prohibited); + +* Use lowercase PHP native typed constants: `false`, `true`, and `null`. The + same goes for `array()`; + +* Use uppercase strings for constants with words separated with underscores; + +* Define one class per file; + +* Declare class properties before methods; + +* Declare public methods first, then protected ones and finally private ones. + +Naming Conventions +------------------ + +* Use camelCase, not underscores, for variable, function and method + names; + +* Use underscores for option, argument, parameter names; + +* Use namespaces for all classes; + +* Use `Symfony` as the first namespace level; + +* Suffix interfaces with `Interface`; + +* Use alphanumeric characters and underscores for file names; + +Documentation +------------- + +* Add PHPDoc blocks for all classes, methods, and functions; + +* The `@package` and `@subpackage` annotations are not used. diff --git a/pt_BR/contributing/code/tests.rst b/pt_BR/contributing/code/tests.rst new file mode 100644 index 00000000000..89578ac1eab --- /dev/null +++ b/pt_BR/contributing/code/tests.rst @@ -0,0 +1,90 @@ +Running Symfony2 Tests +====================== + +Before submitting a :doc:`patch ` for inclusion, you need to run the +Symfony2 test suite to check that you have not broken anything. + +PHPUnit +------- + +To run the Symfony2 test suite, install PHPUnit 3.5.0 or later first. As it is +not stable yet, your best bet is to use the latest version from the +repository: + +.. code-block:: bash + + $ git clone git://github.com/sebastianbergmann/phpunit.git + $ cd phpunit + $ pear package + $ pear install PHPUnit-3.5.XXX.tgz + +Dependencies (optional) +----------------------- + +To run the entire test suite, including tests that depend on external +dependencies, Symfony2 needs to be able to autoload them. By default, they are +autoloaded from `vendor/` under the main root directory (see +`autoload.php.dist`). + +The test suite need the following third-party libraries: + +* Doctrine +* Doctrine Migrations +* Phing +* Propel +* Swiftmailer +* Twig +* Zend Framework + +To install them all, run the `install_vendors.sh` script: + +.. code-block:: bash + + $ sh install_vendors.sh + +.. note:: + Note that the script takes some time to finish. + +After installation, you can update the vendors anytime with the +`update_vendors.sh` script: + +.. code-block:: bash + + $ sh update_vendors.sh + +Running +------- + +First, update the vendors (see above). + +Then, run the test suite from the Symfony2 root directory with the following +command: + +.. code-block:: bash + + $ phpunit + +The output should display `OK`. If not, you need to figure out what's going on +and if the tests are broken because of your modifications. + +.. tip:: + Run the test suite before applying your modifications to check that they run + fine on your configuration. + +Code Coverage +------------- + +If you add a new feature, you also need to check the code coverage by using +the `coverage-html` option: + +.. code-block:: bash + + $ phpunit --coverage-html=cov/ + +Check the code coverage by opening the generated `cov/index.html` page in a +browser. + +.. tip:: + The code coverage only works if you have XDebug enabled and all dependencies + installed. + diff --git a/pt_BR/contributing/documentation/format.rst b/pt_BR/contributing/documentation/format.rst new file mode 100644 index 00000000000..a1d087a03ee --- /dev/null +++ b/pt_BR/contributing/documentation/format.rst @@ -0,0 +1,98 @@ +Documentation Format +==================== + +The Symfony2 documentation uses `reStructuredText`_ as its markup language and +`Sphinx`_ for building the output (HTML, PDF, ...). + +reStructuredText +---------------- + +reStructuredText "is an easy-to-read, what-you-see-is-what-you-get plaintext +markup syntax and parser system." + +You can learn more about its syntax by reading existing Symfony2 `documents`_ +or by reading the `reStructuredText Primer`_ on the Sphinx website. + +If you are familiar with Markdown, be careful as things as sometimes very +similar but different: + +* Lists starts at the beginning of a line (no indentation is allowed); + +* Inline code blocks use double-ticks (````like this````). + +Sphinx +------ + +Sphinx is a build system that adds some nice tools to create documentation +from reStructuredText documents. As such, it adds new directives and +interpreted text roles to standard reST `markup`_. + +Syntax Highlighting +~~~~~~~~~~~~~~~~~~~ + +All code examples uses PHP as the default highlighted language. You can change +it with the ``code-block`` directive: + +.. code-block:: rst + + .. code-block:: yaml + + { foo: bar, bar: { foo: bar, bar: baz } } + +If your PHP code begins with ``foobar(); ?> + +.. note:: + A list of supported languages is available on the `Pygments website`_. + +Configuration Blocks +~~~~~~~~~~~~~~~~~~~~ + +Whenever you show a configuration, you must use the ``configuration-block`` +directive to show the configuration in all supported configuration formats +(``PHP``, ``YAML``, and ``XML``): + +.. code-block:: rst + + .. configuration-block:: + + .. code-block:: yaml + + # Configuration in YAML + + .. code-block:: xml + + + + .. code-block:: php + + // Configuration in XML + +The previous reST snippet renders as follow: + +.. configuration-block:: + + .. code-block:: yaml + + # Configuration in YAML + + .. code-block:: xml + + + + .. code-block:: php + + // Configuration in XML + +.. _reStructuredText: http://docutils.sf.net/rst.html +.. _Sphinx: http://sphinx.pocoo.org/ +.. _documents: http://github.com/symfony/symfony-docs +.. _reStructuredText Primer: http://sphinx.pocoo.org/rest.html +.. _markup: http://sphinx.pocoo.org/markup/ +.. _Pygments website: http://pygments.org/languages/ diff --git a/pt_BR/contributing/documentation/index.rst b/pt_BR/contributing/documentation/index.rst new file mode 100644 index 00000000000..b179945b5e6 --- /dev/null +++ b/pt_BR/contributing/documentation/index.rst @@ -0,0 +1,9 @@ +Contributing Documentation +========================== + +.. toctree:: + :maxdepth: 2 + + format + translations + license diff --git a/pt_BR/contributing/documentation/license.rst b/pt_BR/contributing/documentation/license.rst new file mode 100644 index 00000000000..423b33d84a8 --- /dev/null +++ b/pt_BR/contributing/documentation/license.rst @@ -0,0 +1,49 @@ +Symfony2 Documentation License +============================== + +The Symfony2 documentation is licensed under a Creative Commons +Attribution-Share Alike 3.0 Unported `License`_. + +**You are free:** + +* to *Share* — to copy, distribute and transmit the work; + +* to *Remix* — to adapt the work. + +**Under the following conditions:** + +* *Attribution* — You must attribute the work in the manner specified by + the author or licensor (but not in any way that suggests that they + endorse you or your use of the work); + +* *Share Alike* — If you alter, transform, or build upon this work, you + may distribute the resulting work only under the same or similar license + to this one. + +**With the understanding that:** + +* *Waiver* — Any of the above conditions can be waived if you get + permission from the copyright holder; + +* *Public Domain* — Where the work or any of its elements is in the public + domain under applicable law, that status is in no way affected by the + license; + +* *Other Rights* — In no way are any of the following rights affected by the license: + + * Your fair dealing or fair use rights, or other applicable copyright + exceptions and limitations; + + * The author's moral rights; + + * Rights other persons may have either in the work itself or in how + the work is used, such as publicity or privacy rights. + +* *Notice* — For any reuse or distribution, you must make clear to others + the license terms of this work. The best way to do this is with a link + to this web page. + +This is a human-readable summary of the `Legal Code (the full license)`_. + +.. _License: http://creativecommons.org/licenses/by-sa/3.0/ +.. _Legal Code (the full license): http://creativecommons.org/licenses/by-sa/3.0/legalcode diff --git a/pt_BR/contributing/documentation/translations.rst b/pt_BR/contributing/documentation/translations.rst new file mode 100644 index 00000000000..5a4b5444036 --- /dev/null +++ b/pt_BR/contributing/documentation/translations.rst @@ -0,0 +1,81 @@ +Translations +============ + +The Symfony2 documentation is written in English and many people are involved +in the translation process. + +Contributing +------------ + +First, become familiar with the :doc:`markup language ` used by the +documentation. + +Then, subscribe to the `Symfony docs mailing-list`_, as collaboration happens +there. + +Finally, find the *master* repository for the language you want to contribute +for. Here is the list of the official *master* repositories: + +* *English*: http://github.com/symfony/symfony-docs +* ... + +.. note:: + If you want to contribute translations for a new language, read the + :ref:`dedicated section `. + +Joining the Translation Team +---------------------------- + +If you want to help translating some documents for your language or fix some +bugs, consider joining us; it's a very easy process: + +* Introduce yourself on the `Symfony docs mailing-list`_; +* *(optional)* Ask which documents you can work on; +* Fork the *master* repository for your language (click the "Fork" button on + the Github page); +* Translate some documents; +* Ask for a pull request (click on the "Pull Request" from your page on + Github); +* The team manager accepts your modifications and merges them into the master + repository; +* The documentation website is updated every other night from the master + repository. + +.. _translations-adding-a-new-language: + +Adding a new Language +--------------------- + +This section gives some guidelines for starting the translation of the +Symfony2 documentation for a new language. + +As starting a translation is a lot of work, talk about your plan on the +`Symfony docs mailing-list`_ and try to find motivated people willing to help. + +When the team is ready, nominate a team manager; he will be responsible for +the *master* repository. + +Create the repository and copy the *English* documents. + +The team can now start the translation process. + +When the team is confident that the repository is in a consistent and stable +state (everything is translated, or non-translated documents have been removed +from the toctrees -- files named ``index.rst`` and ``map.rst.inc``), the team +manager can ask that the repository is added to the list of official *master* +repositories by sending an email to Fabien (fabien.potencier at +symfony-project.org). + +Maintenance +----------- + +Translation does not end when everything is translated. The documentation is a +moving target (new documents are added, bugs are fixed, paragraphs are +reorganized, ...). The translation team need to closely follow the English +repository and apply changes to the translated documents as soon as possible. + +.. caution:: + Non maintained languages are removed from the official list of + repositories as obsolete documentation is dangerous. + +.. _Symfony docs mailing-list: http://groups.google.com/group/symfony-docs diff --git a/pt_BR/contributing/index.rst b/pt_BR/contributing/index.rst new file mode 100644 index 00000000000..60e00df3c2d --- /dev/null +++ b/pt_BR/contributing/index.rst @@ -0,0 +1,12 @@ +Contributing +============ + +Contribute to Symfony2: + +.. toctree:: + :hidden: + + code/index + documentation/index + +.. include:: map.rst.inc diff --git a/pt_BR/contributing/map.rst.inc b/pt_BR/contributing/map.rst.inc new file mode 100644 index 00000000000..18aac08ae55 --- /dev/null +++ b/pt_BR/contributing/map.rst.inc @@ -0,0 +1,14 @@ +* **Code**: + + * :doc:`Bugs ` | + * :doc:`Patches ` | + * :doc:`Security ` | + * :doc:`Coding Standards` | + * :doc:`Tests ` | + * :doc:`License ` + +* **Documentation**: + + * :doc:`Format ` | + * :doc:`Translations ` | + * :doc:`License ` diff --git a/pt_BR/guides/Twig.rst b/pt_BR/guides/Twig.rst new file mode 100644 index 00000000000..45058f8df53 --- /dev/null +++ b/pt_BR/guides/Twig.rst @@ -0,0 +1,177 @@ +.. index:: + single: Twig + single: View; Twig + +Twig e Symfony2 +=============== + +`Twig`_ é uma linguagem de template PHP flexível, rápida e segura. O Symfony2 +tem suporte nativo ao Twig através do ``TwigBundle``. + +.. index:: + single: Twig; Installation + single: Twig; Configuration + +Instalação e Configuração +------------------------- + +Ative o ``TwigBundle`` em seu kernel:: + + public function registerBundles() + { + $bundles = array( + // ... + new Symfony\Framework\TwigBundle\Bundle(), + ); + + // ... + } + +Em seguida, configure-o: + +.. configuration-block:: + + .. code-block:: yaml + + # config/config.yml + twig.config: ~ + + # config/config_dev.yml + twig.config: + auto_reload: true + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // config/config.php + $container->loadFromExtension('twig', 'config'); + + // config/config_dev.php + $container->loadFromExtension('twig', 'config', array('auto_reload' => true)); + +.. tip:: + As opções de configuração são as mesmas que você passa ao + `construtor`_ ``Twig_Environment``. + +Uso +--- + +Para renderizar um template Twig em vez de um PHP, adicione o sufixo ``:twig`` no +final do nome do template. O controlador abaixo renderiza o template ``index.twig``:: + + public function indexAction($name) + { + return $this->render('HelloBundle:Hello:index:twig', array('name' => $name)); + } + +O sufixo ``:twig`` somente é necessário quando não há contexto, como em um controlador. +Mas quando você estender ou incluir um template dentro um template Twig, o Symfony2 +automaticamente fará a troca da engine padrão para Twig: + +.. code-block:: jinja + + {# index.twig #} + + {# no need to add :twig as this is the default #} + {% extends 'HelloBundle::layout' %} + + {% block content %} + Hello {{ name }} + + {# use the special render tag to render a template #} + {% render 'HelloBundle:Hello:sidebar' %} + {% endblock %} + +Para incorporar um template PHP em um Twig, adicione o sufixo ``:php`` +ao nome do template: + +.. code-block:: jinja + + {# index.twig #} + + {% render 'HelloBundle:Hello:sidebar:php' %} + +E o contrário também é verdadeiro:: + + // index.php + + render('HelloBundle:Hello:sidebar:twig') ?> + +.. index:: + single: Twig; Helpers + +Helpers +------- + +Os helpers padrão do Symfony2 estão disponíveis dentro de um template +Twig através de tags especializadas: + +.. code-block:: jinja + + {# add a javascript #} + {% javascript 'bundles/blog/js/blog.js' %} + + {# add a stylesheet #} + {% stylesheet 'bundles/blog/css/blog.css' with ['media': 'screen'] %} + + {# output the javascripts and stylesheets in the layout #} + {% javascripts %} + {% stylesheets %} + + {# generate a URL for an asset #} + {% asset 'css/blog.css' %} + {% asset 'images/logo.png' %} + + {# generate a route #} + {% route 'blog_post' with ['id': post.id] %} + + {# render a template #} + {% include 'BlogBundle:Post:list' %} + + {# embed another controller response #} + {% render 'BlogBundle:Post:list' with ['path': ['limit': 2], 'alt': 'BlogBundle:Post:error'] %} + +.. _twig_extensions: + +Habilitando Extensões Twig Customizadas +--------------------------------------- + +Para habilitar uma extensão Twig, adicione-a como um serviço regular em uma das suas configurações, e adicione +uma anotação ``twig.extension``: + +.. configuration-block:: + + .. code-block:: yaml + + services: + twig.extension.your_extension_name: + class: Fully\Qualified\Extension\Class\Name + tag: { name: twig.extension } + + .. code-block:: xml + + + + + + .. code-block:: php + + $container + ->register('twig.extension.your_extension_name', 'Fully\Qualified\Extension\Class\Name') + ->addTag('twig.extension') + ; + +.. _Twig: http://www.twig-project.org/ +.. _construtor: http://www.twig-project.org/book/03-Twig-for-Developers diff --git a/pt_BR/guides/bundles/best_practices.rst b/pt_BR/guides/bundles/best_practices.rst new file mode 100644 index 00000000000..0898389b8d6 --- /dev/null +++ b/pt_BR/guides/bundles/best_practices.rst @@ -0,0 +1,175 @@ +.. index:: + single: Bundles; Best Practices + +Bundle Best Practices +===================== + +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 + +Bundle Name +----------- + +A bundle is also a PHP namespace, composed of several segments: + +* The **main namespace**: either ``Bundle``, for reusable bundles, or + ``Application`` for application specific bundles; +* The **vendor namespace** (optional for ``Application`` bundles): something + unique to you or your company (like ``Sensio``); +* *(optional)* The **category namespace(s)** to better organize a large set of + bundles; +* The **bundle name**. + +.. caution:: + The vendor namespace and the category namespaces are only possible as of + Symfony2 PR3. + +The bundle name must follow the following 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 category + namespaces; +* Suffix the name with ``Bundle``. + +Some good bundle names: + +=================================== ========================== +Namespace Bundle Name +=================================== ========================== +``Bundle\Sensio\BlogBundle`` ``SensioBlogBundle`` +``Bundle\Sensio\Social\BlogBundle`` ``SensioSocialBlogBundle`` +``Application\BlogBundle`` ``BlogBundle`` +=================================== ========================== + +Directory Structure +------------------- + +The basic directory structure of a ``HelloBundle`` bundle must read as +follows:: + + XXX/... + HelloBundle/ + HelloBundle.php + Controller/ + Resources/ + meta/ + LICENSE + config/ + doc/ + index.rst + views/ + web/ + 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/`` +Templates ``Resources/views/`` +Unit and Functional Tests ``Tests/`` +Web Resources ``Resources/web/`` +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 `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 have a name that ends +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. + +Templates +--------- + +If a bundle provides templates, they should be defined in plain PHP. A bundle +must not provide a main layout, but extends a default ``base`` template (which +must provide two slots: ``content`` and ``head``). + +.. note:: + The only other template engine supported is Twig, but only for specific + cases. + +Configuration +------------- + +Configuration must be done via the Symfony2 built-in `mechanism`_. A bundle +should provide all its default configurations in XML. + +.. _standards: http://www.symfony-reloaded.org/contributing/Code/Standards +.. _mechanism: http://www.symfony-reloaded.org/guides/Bundles/Configuration diff --git a/pt_BR/guides/bundles/configuration.rst b/pt_BR/guides/bundles/configuration.rst new file mode 100644 index 00000000000..0b3ba90d734 --- /dev/null +++ b/pt_BR/guides/bundles/configuration.rst @@ -0,0 +1,114 @@ +.. index:: + single: Bundles; Configuration + +Bundle Configuration +==================== + +To provide more flexibility, a bundle can provide configurable settings by +using the Symfony2 built-in mechanisms. + +Simple Configuration +-------------------- + +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 XML/YAML/INI configuration file: + +.. code-block:: xml + + + + fabien@example.com + + +.. code-block:: yaml + + parameters: + 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 below. + +.. index:: + single: Configuration; Semantic + single: Bundle; Extension Configuration + +Semantic Configuration +---------------------- + +Semantic configuration provides an even more flexible way to provide +configuration for a bundle with the following advantages over simple +parameters: + +* Possibility to define more than just configuration (services for + instance); +* Better hierarchy in the configuration (you can define nested + configuration); +* Smart merging when several configuration files override an existing + configuration; +* Configuration validation (if you define an XSD file and use XML); +* Completion when you use XSD and XML. + +To define a semantic configuration, create a Dependency Injection extension:: + + // HelloBundle/DependencyInjection/HelloExtension.php + class DocExtension extends LoaderExtension + { + public function configLoad($config) + { + // ... + } + + public function getXsdValidationBasePath() + { + return __DIR__.'/../Resources/config/'; + } + + public function getNamespace() + { + return 'http://www.example.com/symfony/schema/'; + } + + public function getAlias() + { + return 'hello'; + } + } + +Follow these rules: + +* The extension must be stored in the ``DependencyInjection`` sub-namespace; +* The extension must be named after the bundle name and suffixed with + ``Extension`` (``HelloExtension`` for ``HelloBundle``); +* The alias must be unique and named after the bundle name (``hello`` for + ``HelloBundle`` or ``sensio.social.blog`` for ``Sensio\Social\BlogBundle``); +* The extension should provide an XSD schema. + +Eventually, register the extension:: + + class HelloBundle extends BaseBundle + { + public function buildContainer(ContainerInterface $container) + { + Loader::registerExtension(new HelloExtension()); + } + } + +Naming Conventions +------------------ + +All parameter and service names starting with a ``_`` are reserved for the +framework, and new ones must not be defined by bundles. diff --git a/pt_BR/guides/bundles/index.rst b/pt_BR/guides/bundles/index.rst new file mode 100644 index 00000000000..6617561e724 --- /dev/null +++ b/pt_BR/guides/bundles/index.rst @@ -0,0 +1,8 @@ +Bundles +======= + +.. toctree:: + :maxdepth: 2 + + best_practices + configuration diff --git a/pt_BR/guides/doctrine/MongoDB.rst b/pt_BR/guides/doctrine/MongoDB.rst new file mode 100644 index 00000000000..6e0cb986533 --- /dev/null +++ b/pt_BR/guides/doctrine/MongoDB.rst @@ -0,0 +1,253 @@ +.. index:: + single: Doctrine; MongoDB + single: MongoDB + +MongoDB +======= + +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`_. + +Configuration +------------- + +To get started working with Doctrine and the MongoDB Object Document Mapper you just need +to enable it: + +.. code-block:: yaml + + # config/config.yml + doctrine_odm.mongodb: ~ + +The above YAML is the most simple example and uses all of the default values provided, if +you need to customize more you can specify the complete configuration: + +.. code-block:: yaml + + # config/config.yml + doctrine_odm.mongodb: + server: mongodb://localhost:27017 + options: + connect: true + metadata_cache_driver: array # array, apc, xcache, memcache + +If you wish to use memcache to cache your metadata and you need to configure the ``Memcache`` instance you can do the following: + +.. code-block:: yaml + + # config/config.yml + doctrine_odm.mongodb: + server: mongodb://localhost:27017 + options: + connect: true + metadata_cache_driver: + type: memcache + class: Doctrine\Common\Cache\MemcacheCache + host: localhost + port: 11211 + instance_class: Memcache + +Multiple Connections +~~~~~~~~~~~~~~~~~~~~ + +If you need multiple connections and document managers you can use the following syntax: + +.. code-block:: yaml + + doctrine_odm.mongodb: + 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->getService('doctrine.odm.mongodb.conn1_connection'); + $conn2 = $container->getService('doctrine.odm.mongodb.conn2_connection'); + +And you can also retrieve the configured document manager services which utilize the above +connection services:: + + $dm1 = $container->getService('doctrine.odm.mongodb.dm1_connection'); + $dm2 = $container->getService('doctrine.odm.mongodb.dm1_connection'); + +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/Application/HelloBundle/Document/User.php + + namespace Application\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:: + + // ... + + /** @Document(collection="users") */ + class User + { + /** @Id */ + protected $id; + + /** @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`` instances from +the container:: + + class UserController extends Controller + { + public function createAction() + { + $user = new User(); + $user->setName('Jonathan H. Wage'); + + $dm = $this->container->getService('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->container->getService('doctrine.odm.mongodb.document_manager'); + $user = $dm->find('HelloBundle:User', $id); + + // ... + } + } + +.. _MongoDB: http://www.mongodb.org/ +.. _documentation: http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/en diff --git a/pt_BR/guides/doctrine/configuration.rst b/pt_BR/guides/doctrine/configuration.rst new file mode 100644 index 00000000000..6c0927b7bcf --- /dev/null +++ b/pt_BR/guides/doctrine/configuration.rst @@ -0,0 +1,153 @@ +Doctrine Configuration +====================== + +DBAL Configuration +------------------ + +.. code-block:: yaml + + # config/config.yml + doctrine.dbal: + driver: PDOMySql + dbname: Symfony2 + user: root + password: null + +You can also specify some additional configurations on a connection but they +are not required: + +.. code-block:: yaml + + # ... + + doctrine.dbal: + # ... + + host: localhost + port: ~ + path: %kernel.data_dir%/symfony.sqlite + event_manager_class: Doctrine\Common\EventManager + configuration_class: Doctrine\DBAL\Configuration + wrapper_class: ~ + options: [] + +If you want to configure multiple connections you can do so by simply listing them under +the key named ``connections``: + +.. 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 ``getDatabaseConnection()`` as well +but you must pass it an argument with the name of the connection you want to get:: + + class UserController extends Controller + { + public function indexAction() + { + $conn = $this->container->getDatabaseConnection('customer'); + } + } + +ORM Configuration +----------------- + +.. 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 ``getEntityManager()`` method by just passing it an argument +that is the name of the ``EntityManager`` you want:: + + class UserController extends Controller + { + public function indexAction() + { + $em = $this->container->getService('doctrine.orm.customer_entity_manager'); + } + } + +Now the scenario arrises 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 Application\HelloBundle\Entities; + + /** @Entity */ + class User + { + /** @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 hello/console doctrine:schema:update + +Now your database will be updated and the new column added to the database +table. + +Console Commands +---------------- + +The Doctrine2 ORM integration offers several console commands under the ``doctrine`` +namespace. To view a list of the commands you can run the console without any arguments +or options: + + $ php hello/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/pt_BR/guides/doctrine/index.rst b/pt_BR/guides/doctrine/index.rst new file mode 100644 index 00000000000..bfcd552931a --- /dev/null +++ b/pt_BR/guides/doctrine/index.rst @@ -0,0 +1,9 @@ +Doctrine +======== + +.. toctree:: + :maxdepth: 2 + + Overview + migrations + MongoDB diff --git a/pt_BR/guides/doctrine/migrations.rst b/pt_BR/guides/doctrine/migrations.rst new file mode 100644 index 00000000000..fb43fd7f02e --- /dev/null +++ b/pt_BR/guides/doctrine/migrations.rst @@ -0,0 +1,107 @@ +.. index:: + single: Doctrine; Migrations + +Doctrine 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 bundles migrations you can run the ``status`` command: + +.. code-block:: bash + + $ php console doctrine:migrations:status --bundle="Application\HelloBundle" + + == Configuration + + >> Name: HelloBundle Migrations + >> Configuration Source: manually configured + >> Version Table Name: hello_bundle_migration_versions + >> Migrations Namespace: Application\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 console doctrine:migrations:generate --bundle="Application\HelloBundle" + Generated new migration class to "/path/to/symfony-sandbox/src/Bundle/HelloBundle/DoctrineMigrations/Version20100621140655.php" + +Have a look at the newly generated migration class and you will see something +like the following:: + + namespace Application\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 console doctrine:migrations:status --bundle="Application\HelloBundle" + + == Configuration + + >> Name: HelloBundle Migrations + >> Configuration Source: manually configured + >> Version Table Name: hello_bundle_migration_versions + >> Migrations Namespace: Application\HelloBundle\DoctrineMigrations + >> Migrations Directory: /path/to/symfony-sandbox/src/Application/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 console doctrine:migrations:migrate --bundle="Application\HelloBundle" + +.. _documentation: http://www.doctrine-project.org/projects/migrations/2.0/docs/en diff --git a/pt_BR/guides/doctrine/overview.rst b/pt_BR/guides/doctrine/overview.rst new file mode 100644 index 00000000000..c4301f8bb24 --- /dev/null +++ b/pt_BR/guides/doctrine/overview.rst @@ -0,0 +1,179 @@ +.. index:: + single: Doctrine + +Doctrine +======== + +The `Doctrine`_ project is the home of a selected set of PHP libraries +primarily focused on providing persistence services and related functionality. +The integration between Symfony2 and Doctrine2 implements most of the features +the project has to offer for working with relational databases, such as: + +* Database Abstraction Layer +* Object Relational Mapper +* Database Migrations + +.. tip:: + You can learn more about the `DBAL API`_ and `ORM API`_ on the official + Doctrine2 website. + +.. index:: + single: Doctrine; DBAL + +Doctrine DBAL +------------- + +The Doctrine Database Abstraction Layer (DBAL) offers an intuitive and +flexible API for communicating with the most popular relational databases that +exist today. In order to start using the DBAL, configure it: + +.. code-block:: yaml + + # config/config.yml + + doctrine.dbal: + driver: PDOMySql + dbname: Symfony2 + user: root + password: null + +Access the connection from your controllers by getting the +``database_connection`` service:: + + class UserController extends Controller + { + public function indexAction() + { + $conn = $this->container->getService('database_connection'); + + $users = $conn->fetchAll('SELECT * FROM users'); + } + } + +You can then execute a query and fetch the results as show above with the +``fetchAll()`` method. + +.. index:: + single: Doctrine; ORM + +Doctrine Object Relational Mapper +--------------------------------- + +The Doctrine Object Relational Mapper (ORM) is the prize library under the +Doctrine Project umbrella. It is built on top of the Doctrine DBAL (Database +Abstraction Layer) and offers transparent persistence of PHP5 objects to a +relational database. + +Before using the ORM, enable it in the configuration: + +.. code-block:: yaml + + # config/config.yml + + doctrine.orm: ~ + +Next, write your entity classes. A typical entity read as follows:: + + // Application/HelloBundle/Entities/User.php + + namespace Application\HelloBundle\Entities; + + /** + * @Entity + */ + class User + { + /** + * @Id + * @Column(type="integer") + * @GeneratedValue(strategy="IDENTITY") + */ + protected $id; + + /** + * @Column(type="string", length="255") + */ + 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, create the schema by running the following command: + +.. code-block:: bash + + $ php hello/console doctrine:schema:create + +.. note:: + Don't forget to create the database if it does not exist yet. + +Eventually, use your entity and manage its persistent state with Doctrine:: + + use Application\HelloBundle\Entities\User; + + class UserController extends Controller + { + public function createAction() + { + $user = new User(); + $user->setName('Jonathan H. Wage'); + + $em = $this->container->getService('doctrine.orm.entity_manager'); + $em->persist($user); + $em->flush(); + + // ... + } + + public function editAction($id) + { + $em = $this->container->getService('doctrine.orm.entity_manager'); + $user = $em->createQuery('select u from HelloBundle:User where id = ?', $id); + $user->setBody('new body'); + $em->flush(); + + // ... + } + + public function deleteAction($id) + { + $em = $this->container->getService('doctrine.orm.entity_manager'); + $user = $em->createQuery('select e from HelloBundle:User where id = ?', $id); + $em->remove($user); + $em->flush(); + + // ... + } + } + +.. _Doctrine: http://www.doctrine-project.org/ +.. _DBAL API: http://www.doctrine-project.org/projects/dbal/2.0/docs/en +.. _ORM API: http://www.doctrine-project.org/projects/orm/2.0/docs/en diff --git a/pt_BR/guides/emails.rst b/pt_BR/guides/emails.rst new file mode 100644 index 00000000000..ee71b3d5010 --- /dev/null +++ b/pt_BR/guides/emails.rst @@ -0,0 +1,147 @@ +.. index:: + single: Emails + +Emails +====== + +O Symfony2 aproveita o poder do `Swiftmailer`_ para enviar emails. + +Instalação +---------- + +Ative o ``SwiftmailerBundle`` no seu kernel:: + + public function registerBundles() + { + $bundles = array( + // ... + new Symfony\Framework\SwiftmailerBundle\Bundle(), + ); + + // ... + } + +Configuração +------------ + +O único parametro obrigatório de configuração é o ``transport``: + +.. configuration-block:: + + .. code-block:: yaml + + # hello/config/config.yml + swift.mailer: + transport: smtp + encryption: ssl + auth_mode: login + host: smtp.gmail.com + username: your_username + password: your_password + + .. code-block:: xml + + + + + + .. code-block:: php + + // hello/config/config.php + $container->loadFromExtension('swift', 'mailer', array( + 'transport' => "smtp", + 'encryption' => "ssl", + 'auth_mode' => "login", + 'host' => "smtp.gmail.com", + 'username' => "your_username", + 'password' => "your_password", + )); + +Os seguintes atributos de configuração estão disponíveis: + +* ``transport`` (``smtp``, ``mail``, ``sendmail``, or ``gmail``) +* ``username`` +* ``password`` +* ``host`` +* ``port`` +* ``encryption`` (``tls``, or ``ssl``) +* ``auth_mode`` (``plain``, ``login``, or ``cram-md5``) +* ``type`` +* ``delivery_strategy`` (``realtime``, ``spool``, ``single_address``, or ``none``) +* ``delivery_address`` (um endereço de email para onde mandar todos os emails) +* ``disable_delivery`` + +Enviando Emails +--------------- + +O envio de emails é acessivel através do serviço ``mailer``; de uma action:: + + public function indexAction($name) + { + // pega primeiro o mailer (obrigatório para inicializar o Swift Mailer) + $mailer = $this->container['mailer']; + + $message = \Swift_Message::newInstance() + ->setSubject('Hello Email') + ->setFrom('send@example.com') + ->setTo('recipient@example.com') + ->setBody($this->renderView('HelloBundle:Hello:email', array('name' => $name))) + ; + $mailer->send($message); + + return $this->render(...); + } + +.. note:: + Para manter as coisas desacopladas, o corpo do email foi guardado em um template, + renderizado com o método ``renderView()``. + +Usando o Gmail +-------------- + +If you want to use your Gmail account to send emails, use the special +Se você quer usar sua conta do Gmail para enviar emails, use o transporte especial ``gmail``: + +.. configuration-block:: + + .. code-block:: yaml + + # hello/config/config.yml + swift.mailer: + transport: gmail + username: your_gmail_username + password: your_gmail_password + + .. code-block:: xml + + + + + + + + .. code-block:: php + + // hello/config/config.php + $container->loadFromExtension('swift', 'mailer', array( + 'transport' => "gmail", + 'username' => "your_gmail_username", + 'password' => "your_gmail_password", + )); + +.. _`Swiftmailer`: http://www.swiftmailer.org/ diff --git a/pt_BR/guides/event/index.rst b/pt_BR/guides/event/index.rst new file mode 100644 index 00000000000..da97d639e16 --- /dev/null +++ b/pt_BR/guides/event/index.rst @@ -0,0 +1,8 @@ +Event System +============ + +.. toctree:: + :maxdepth: 2 + + Overview + recipes diff --git a/pt_BR/guides/event/overview.rst b/pt_BR/guides/event/overview.rst new file mode 100644 index 00000000000..ac240506b3d --- /dev/null +++ b/pt_BR/guides/event/overview.rst @@ -0,0 +1,207 @@ +.. index:: + single: Event Dispatcher + +The Event Dispatcher +==================== + +Objected Oriented code has gone a long way to ensuring code extensibility. By +creating classes that have well defined responsibilities, your code becomes +more flexible as a developer can extend them with sub-classes to modify their +behaviors. But if he wants to share his changes with other developers who have +also made their own subclasses, code inheritance is moot. + +A real-world example is when you want to provide a plugin system for your +project. A plugin should be able to add methods, or do something before or +after a method is executed, without interfering with other plugins. This is +not an easy problem to solve with single inheritance, and multiple inheritance +(were it possible with PHP) has its own drawbacks. + +The Symfony2 Event Dispatcher implements the `Observer`_ pattern in a simple +and effective way to make all these things possible and make your projects +truly extensible (see the :doc:`recipes` section for some implementation +examples). + +The Event Dispatcher provides *dispatcher* that allows objects to communicate +together without knowing each others. Objects (*listeners*) can *connect* to +the dispatcher to listen to specific events, and some others can *notify* an +*event* to the dispatcher. Whenever an event is notified, the dispatcher will +call all the connected listeners. + +.. index:: + pair: Event Dispatcher; Naming Conventions + +Events +------ + +Unlike many other implementations of the Observer pattern, you don't need to +create a class to define a new event. All events are instead instances of the +``Event`` class and are uniquely identified by their names, a string that +optionally follows simple naming conventions: + +* use only lowercase letters, numbers, and underscores (``_``); + +* prefix names with a namespace followed by a dot (``.``); + +* use a verb to indicate what action will be done. + +Here are some examples of good event names: + +* change_culture +* response.filter_content + +.. note:: + You can of course extends the ``Event`` class to specialize an event further, or + enforce some constraints, but most of the time it adds an unnecessary level of + complexity. + +Besides its name, an ``Event`` instance can store additional data about the +notified event: + +* The *subject* of the event (most of the time, this is the object notifying + the event, but it can be any other object or ``null``); + +* The event name; + +* An array of parameters to pass to the listeners (an empty array by + default). + +These data are passed as arguments to the ``Event`` constructor:: + + use Symfony\Components\EventDispatcher\Event; + + $event = new Event($this, 'user.change_culture', array('culture' => $culture)); + +The event object has several methods to get the event data: + +* ``getName()``: Returns the event name; + +* ``getSubject()``: Gets the subject object attached to the event; + +* ``getParameters()``: Returns the event parameters. + +The event object can also be accessed as an array to get its +parameters:: + + echo $event['culture']; + +The Dispatcher +-------------- + +The dispatcher maintains a register of listeners and calls them whenever an +event is notified:: + + use Symfony\Components\EventDispatcher\EventDispatcher; + + $dispatcher = new EventDispatcher(); + +.. index:: + single: Event Dispatcher; Listeners + +Connecting Listeners +-------------------- + +Obviously, you need to connect some listeners to the dispatcher before it can +be useful. A call to the dispatcher ``connect()`` method associates a PHP +callable to an event:: + + $dispatcher->connect('user.change_culture', $callable); + +The ``connect()`` method takes two arguments: + +* The event name; + +* A PHP callable to call when the event is notified. + +.. note:: + A `PHP callable`_ is a PHP variable that can be used by the + ``call_user_func()`` function and returns ``true`` when passed to the + ``is_callable()`` function. It can be a ``\Closure`` instance, a string + representing a function, or an array representing an object method or a class + method. + +Once a listener is registered with the dispatcher, it waits until the event is +notified. For the above example, the dispatcher calls ``$callable`` whenever the +``user.change_culture`` event is notified; the listener receives an ``Event`` +instance as an argument. + +.. note:: + The listeners are called by the event dispatcher in the same order you + connected them. + +.. index:: + single: Event Dispatcher; Notification + +Notifying Events +---------------- + +Events can be notified by using three methods: + +* ``notify()`` + +* ``notifyUntil()`` + +* ``filter()`` + +``notify`` +~~~~~~~~~~ + +The ``notify()`` method notifies all listeners in turn:: + + $dispatcher->notify($event); + +By using the ``notify()`` method, you make sure that all the listeners +registered for the event are executed but their return values is ignored. + +``notifyUntil`` +~~~~~~~~~~~~~~~ + +In some cases, you need to allow a listener to stop the event and prevent +further listeners from being notified about it. In this case, you should use +``notifyUntil()`` instead of ``notify()``. The dispatcher will then execute all +listeners until one returns ``true``, and then stop the event notification:: + + $dispatcher->notifyUntil($event); + +The listener that stops the chain may also call the ``setReturnValue()`` method +to return back some value to the subject:: + + $event->setReturnValue('foo'); + + return true; + +The notifier can check if a listener has processed the event by calling the +``isProcessed()`` method:: + + if ($event->isProcessed()) { + $ret = $event->getReturnValue(); + + // ... + } + +``filter`` +~~~~~~~~~~ + +The ``filter()`` method asks all listeners to filter a given value, passed by +the notifier as its second argument, and retrieved by the listener callable as +the second argument:: + + $dispatcher->filter($event, $response->getContent()); + + $listener = function (Event $event, $content) + { + // do something with $content + + // don't forget to return the content + return $content; + }; + +All listeners are passed the value and they must return the filtered value, +whether they altered it or not. All listeners are guaranteed to be executed. + +The notifier can get the filtered value by calling the ``getReturnValue()`` +method:: + + $ret = $event->getReturnValue(); + +.. _Observer: http://en.wikipedia.org/wiki/Observer_pattern +.. _PHP callable: http://www.php.net/manual/en/function.is-callable.php diff --git a/pt_BR/guides/event/recipes.rst b/pt_BR/guides/event/recipes.rst new file mode 100644 index 00000000000..139d7213a82 --- /dev/null +++ b/pt_BR/guides/event/recipes.rst @@ -0,0 +1,175 @@ +.. index:: + single: Event Dispatcher; Recipes + +Event Dispatcher Recipes +======================== + +Passing along the Event Dispatcher Object +----------------------------------------- + +If you have a look at the ``EventDispatcher`` class, you will notice that the +class does not act as a Singleton (there is no ``getInstance()`` static method). +That is intentional, as you might want to have several concurrent event +dispatchers in a single PHP request. But it also means that you need a way to +pass the dispatcher to the objects that need to connect or notify events. + +The best practice is to inject the event dispatcher object into your objects, +aka dependency injection. + +You can use constructor injection:: + + class Foo + { + protected $dispatcher = null; + + public function __construct(EventDispatcher $dispatcher) + { + $this->dispatcher = $dispatcher; + } + } + +Or setter injection:: + + class Foo + { + protected $dispatcher = null; + + public function setEventDispatcher(EventDispatcher $dispatcher) + { + $this->dispatcher = $dispatcher; + } + } + +Choosing between the two is really a matter of taste. I tend to prefer the +constructor injection as the objects are fully initialized at construction +time. But when you have a long list of dependencies, using setter injection +can be the way to go, especially for optional dependencies. + +.. tip:: + If you use dependency injection like we did in the two examples above, you can + then easily use the Symfony Dependency Injection Component to elegantly manage + these objects. + +Doing something before or after a Method Call +--------------------------------------------- + +If you want to do something just before, or just after a method is called, you +can notify respectively an event at the beginning or at the end of the method:: + + class Foo + { + // ... + + public function send($foo, $bar) + { + // do something before the method + $event = new Event($this, 'foo.do_before_send', array('foo' => $foo, 'bar' => $bar)); + $this->dispatcher->notify($event); + + // the real method implementation is here + // $ret = ...; + + // do something after the method + $event = new Event($this, 'foo.do_after_send', array('ret' => $ret)); + $this->dispatcher->notify($event); + + return $ret; + } + } + +Adding Methods to a Class +------------------------- + +To allow multiple classes to add methods to another one, you can define the +magic ``__call()`` method in the class you want to be extended like this:: + + class Foo + { + // ... + + public function __call($method, $arguments) + { + // create an event named 'foo.method_is_not_found' + // and pass the method name and the arguments passed to this method + $event = new Event($this, 'foo.method_is_not_found', array('method' => $method, 'arguments' => $arguments)); + + // calls all listeners until one is able to implement the $method + $this->dispatcher->notifyUntil($event); + + // no listener was able to proces the event? The method does not exist + if (!$event->isProcessed()) { + throw new \Exception(sprintf('Call to undefined method %s::%s.', get_class($this), $method)); + } + + // return the listener returned value + return $event->getReturnValue(); + } + } + +Then, create a class that will host the listener:: + + class Bar + { + public function addBarMethodToFoo(Event $event) + { + // we only want to respond to the calls to the 'bar' method + if ('bar' != $event['method']) { + // allow another listener to take care of this unknown method + return false; + } + + // the subject object (the foo instance) + $foo = $event->getSubject(); + + // the bar method arguments + $arguments = $event['parameters']; + + // do something + // ... + + // set the return value + $event->setReturnValue($someValue); + + // tell the world that you have processed the event + return true; + } + } + +Eventually, add the new ``bar`` method to the ``Foo`` class:: + + $dispatcher->connect('foo.method_is_not_found', array($bar, 'addBarMethodToFoo')); + +Modifying Arguments +------------------- + +If you want to allow third party classes to modify arguments passed to a +method just before that method is executed, add a ``filter`` event at the +beginning of the method:: + + class Foo + { + // ... + + public function render($template, $arguments = array()) + { + // filter the arguments + $event = new Event($this, 'foo.filter_arguments'); + $this->dispatcher->filter($event, $arguments); + + // get the filtered arguments + $arguments = $event->getReturnValue(); + // the method starts here + } + } + +And here is a filter example:: + + class Bar + { + public function filterFooArguments(Event $event, $arguments) + { + $arguments['processed'] = true; + + return $arguments; + } + } diff --git a/pt_BR/guides/forms.rst b/pt_BR/guides/forms.rst new file mode 100644 index 00000000000..787d0e981d3 --- /dev/null +++ b/pt_BR/guides/forms.rst @@ -0,0 +1,353 @@ +.. index:: + single: Forms + +Forms +===== + +Symfony2 features a sophisticated Form component that allows you to easily +create mighty HTML forms. + +Your First Form +--------------- + +A form in Symfony2 is a transparent layer on top of your domain model. It +reads properties from an object, displays the values in the form and allows +the user to change them. When the form is submitted, the values are written +back into the object. + +Let's see how this works in a practical example. Let's create a simple +``Customer`` class:: + + class Customer + { + public $name; + + private $age = 20; + + public function getAge() { + return $this->age; + } + + public function setAge($age) { + $this->age = $age; + } + } + +The class contains two properties ``name`` and "age". The property ``$name`` is +public, while ``$age`` can only be modified through setters and getters. + +Now let's create a form to let the visitor fill the data of the object:: + + // src/Application/HelloBundle/Controller/HelloController.php + public function signupAction() + { + $customer = new Customer(); + + $form = new Form('customer', $customer, $this->container->getValidatorService()); + $form->add(new TextField('name')); + $form->add(new IntegerField('age')); + + return $this->render('HelloBundle:Hello:signup', array('form' => $form)); + } + +A form consists of various fields. Each field represents a property in your +class. The property must have the same name as the field and must either be +public or accessible through public getters and setters. Now let's create a +simple template to render the form: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/Hello/signup.php + extend('HelloBundle::layout') ?> + + renderFormTag('#') ?> + renderErrors() ?> + render() ?> + + + +When the user submits the form, we also need to handle the submitted data. +All the data is stored in a POST parameter with the name of the form:: + + # src/Application/HelloBundle/Controller/HelloController.php + public function signupAction() + { + $customer = new Customer(); + $form = new Form('customer', $customer, $this->container->getValidatorService()); + + // form setup... + + if ($this->getRequest()->getMethod() == 'POST') + { + $form->bind($this->getRequest()->getParameter('customer')); + + if ($form->isValid()) + { + // save $customer object and redirect + } + } + + return $this->render('HelloBundle:Hello:signup', array('form' => $form)); + } + +Congratulations! You just created your first fully-functional form with +Symfony2. + +.. index:: + single: Forms; Fields + +Form Fields +----------- + +As you have learned, a form consists of one or more form fields. In Symfony2, +form fields have two responsibilities: + +* Render HTML +* Convert data between normalized and humane representations + +Let's look at the ``DateField`` for example. While you probably prefer to store +dates as strings or ``DateTime`` objects, users rather like to choose them from a +list of drop downs. ``DateField`` handles the rendering and type conversion for you. + +Basic Fields +~~~~~~~~~~~~ + +Symfony2 ships with all fields available in plain HTML: + +============= ================== +Field Name Description +============= ================== +TextField An input tag for entering short text +TextareaField A textarea tag for entering long text +CheckboxField A checkbox +ChoiceField A drop-down or multiple radio-buttons/checkboxes for selecting values +PasswordField A password input tag +HiddenField A hidden input tag +============= ================== + +Localized Fields +~~~~~~~~~~~~~~~~ + +The Form component also features fields that render differently depending on +the locale of the user: + +============= ================== +Field Name Description +============= ================== +NumberField A text field for entering numbers +IntegerField A text field for entering integers +PercentField A text field for entering percent values +MoneyField A text field for entering money values +DateField A text field or multiple drop-downs for entering dates +BirthdayField An extension of DateField for selecting birthdays +TimeField A text field or multiple drop-downs for entering a time +DateTimeField A combination of DateField and TimeField +TimezoneField An extension of ChoiceField for selecting a timezone +============= ================== + +Field Groups +~~~~~~~~~~~~ + +Field groups allow you to combine multiple fields together. While normal fields +only allow you to edit scalar data types, field groups can be used to edit +whole objects or arrays. Let's add a new class ``Address`` to our model:: + + class Address + { + public $street; + public $zipCode; + } + +Now we can add a property ``$address`` to the customer that stores one ``Address`` +object:: + + class Customer + { + // other properties ... + + public $address; + } + +We can use a field group to show fields for the customer and the nested address +at the same time:: + + # src/Application/HelloBundle/Controller/HelloController.php + public function signupAction() + { + $customer = new Customer(); + $customer->address = new Address(); + + // form configuration ... + + $group = new FieldGroup('address'); + $group->add(new TextField('street')); + $group->add(new TextField('zipCode')); + $form->add($group); + + // process form ... + } + +With only these little changes you can now edit also the ``Address`` object! +Cool, ey? + +Repeated Fields +~~~~~~~~~~~~~~~ + +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:: + + $form->add(new RepeatedField(new TextField('email'))); + +This is a very useful field for querying email addresses or passwords! + +Collection Fields +~~~~~~~~~~~~~~~~~ + +The ``CollectionField`` is a special field group for manipulating arrays or +objects that implement 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:: + + $form->add(new CollectionField(new TextField('emails'))); + +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. + +.. index:: + single: Forms; Validation + +Form Validation +--------------- + +You have already learned in the last part of this tutorial how to set up +validation constraints for a PHP class. The nice thing is that this is enough +to validate a Form! Remember that a form is nothing more than a gateway for +changing data in an object. + +What now if there are further validation constraints for a specific form, that +are irrelevant for the underlying class? What if the form contains fields that +should not be written into the object? + +The answer to that question is most of the time to extend your domain model. +We'll demonstrate this approach by extending our form with a checkbox for +accepting terms and conditions. + +Let's create a simple ``Registration`` class for this purpose:: + + class Registration + { + /** @Validation({ @Valid }) */ + public $customer; + + /** @Validation({ @AssertTrue(message="Please accept the terms and conditions") }) */ + public $termsAccepted = false; + + public process() + { + // save user, send emails etc. + } + } + +Now we can easily adapt the form in the controller:: + + # src/Application/HelloBundle/Controller/HelloController.php + public function signupAction() + { + $registration = new Registration(); + $registration->customer = new Customer(); + + $form = new Form('registration', $registration, $this->container->getValidatorService()); + $form->add(new CheckboxField('termsAccepted')); + + $group = new FieldGroup('customer'); + + // add customer fields to this group ... + + $form->add($group); + + if ($this->getRequest()->getMethod() == 'POST') + { + $form->bind($this->getRequest()->getParameter('customer')); + + if ($form->isValid()) + { + $registration->process(); + } + } + + return $this->render('HelloBundle:Hello:signup', array('form' => $form)); + } + +The big benefit of this refactoring is that we can reuse the ``Registration`` +class. Extending the application to allow users to sign up via XML is no +problem at all! + +.. index:: + single: Forms; View + +Customizing the View +-------------------- + +Unfortunately the output of ``$form->render()`` doesn't look too great. Symfony +2.0 makes it very easy though to customize the HTML of a form. You can access +every field and field group in the form by its name. All fields offer the +method ``render()`` for rendering the widget and ``renderErrors()`` for rendering +a ``
    ``-list with the field errors. + +The following example shows you how to refine the HTML of an individual form +field:: + + # src/Application/HelloBundle/Resources/views/Hello/signup.php +
    + +
    + renderErrors() ?> + render() ?> +
    +
    + +You can access fields in field groups in the same way: + +.. code-block:: html+php + + render() ?> + +Forms and field groups can be iterated for conveniently rendering all fields +in the same way. You only need to take care not to create form rows or labels +for your hidden fields: + +.. code-block:: html+php + + + isHidden()): ?> + render() ?> + +
    + ... +
    + + + +By using plain HTML, you have the greatest possible flexibility in designing +your forms. Especially your designers will be happy that they can manipulate +the form output without having to deal with (much) PHP! + +Final Thoughts +-------------- + +This chapter showed you how the Form component of Symfony2 can help you to +rapidly create forms for your domain objects. The component embraces a strict +separation between business logic and presentation. Many fields are +automatically localized to make your visitors feel comfortable on your website. +And with the new architecture, this is just the beginning of many new, mighty +user-created fields! diff --git a/pt_BR/guides/index.rst b/pt_BR/guides/index.rst new file mode 100644 index 00000000000..451ee42849a --- /dev/null +++ b/pt_BR/guides/index.rst @@ -0,0 +1,19 @@ +Manuais +======= + +Mergulhe no Symfony2 através dos manuais: + +.. toctree:: + :hidden: + + testing/index + doctrine/index + emails + forms + validator + Twig + event/index + tools/index + bundles/index + +.. include:: map.rst.inc diff --git a/pt_BR/guides/map.rst.inc b/pt_BR/guides/map.rst.inc new file mode 100644 index 00000000000..2e09f000728 --- /dev/null +++ b/pt_BR/guides/map.rst.inc @@ -0,0 +1,33 @@ +* **Testing**: + + * :doc:`Overview ` | + * :doc:`Configuration ` | + * :doc:`Crawler ` | + * :doc:`Client ` | + * :doc:`Recipes ` + +* **Doctrine**: + + * :doc:`Overview ` | + * :doc:`Migrations ` | + * :doc:`/guides/doctrine/MongoDB` + +* :doc:`/guides/emails` +* :doc:`/guides/forms` +* :doc:`/guides/validator` +* :doc:`Twig ` +* **Event Dispatcher**: + + * :doc:`Overview ` | + * :doc:`Recipes ` + +* **Tools**: + + * :doc:`/guides/tools/autoloader` | + * :doc:`Finder ` | + * :doc:`/guides/tools/YAML` + +* **Bundles**: + + * :doc:`Best Practices ` | + * :doc:`Configuration ` diff --git a/pt_BR/guides/testing/client.rst b/pt_BR/guides/testing/client.rst new file mode 100644 index 00000000000..8d702a5f33c --- /dev/null +++ b/pt_BR/guides/testing/client.rst @@ -0,0 +1,101 @@ +.. index:: + single: Tests; Client + +The Test Client +=============== + +The test Client simulates an HTTP client like a browser. + +.. note:: + The test Client is based on the ``BrowserKit`` and the ``Crawler`` components. + +Making Requests +--------------- + +The client knows how make requests to a Symfony2 application:: + + $crawler = $client->request('GET', '/hello/Fabien'); + +The ``request()`` method takes the HTTP method and a URL as arguments and +returns a ``Crawler`` instance. + +Use the Crawler to find DOM elements in the Response. These elements can then +be used to click on links and submit forms:: + + $link = $crawler->selectLink('Go elsewhere...')->link(); + $crawler = $client->click($link); + + $form = $crawler->selectButton('validate')->form(); + $crawler = $client->submit($form, array('name' => 'Fabien')); + +The ``click()`` and ``submit()`` methods both return a ``Crawler`` object. These +methods is the best way to browse an application as it hides a lot of details. +For instance, when you submit a form, it automatically detects the HTTP method +and the form URL, it gives you a nice API to upload files, and it merges the +submitted values with the form default ones, and more. + +.. tip:: + The Crawler is documented in its own :doc:`section `. Read it to learn more about + the ``Link`` and ``Form`` objects. + +But you can also simulate form submissions and complex requests with the +additional arguments of the ``request()`` method:: + + // Form submission + $client->request('POST', '/submit', array('name' => 'Fabien')); + + // Form submission with a file upload + $client->request('POST', '/submit', array('name' => 'Fabien'), array('photo' => '/path/to/photo')); + + // Specify HTTP headers + $client->request('DELETE', '/post/12', array(), array(), array('PHP_AUTH_USER' => 'username', 'PHP_AUTH_PW' => 'pa$$word')); + +When a request returns a redirect response, the client automatically follows +it. This behavior can be changed with the ``followRedirects()`` method:: + + $client->followRedirects(false); + +When the client does not follow redirects, you can force the redirection with +the ``followRedirect()`` method:: + + $crawler = $client->followRedirect(); + +Last but not the least, you can force each request to be executed in its own +PHP process to avoid any side-effects when working with several clients in the +same script:: + + $client->insulate(); + +Browsing +-------- + +The Client supports many operations that can be done in a real browser:: + + $client->back(); + $client->forward(); + $client->reload(); + + // Clears all cookies and the history + $client->restart(); + +Accessing Internal Objects +-------------------------- + +If you use the client to test your application, you might want to access the +client internal objects:: + + $history = $client->getHistory(); + $cookieJar = $client->getCookieJar(); + +You can also get the objects related to the latest request:: + + $request = $client->getRequest(); + $response = $client->getResponse(); + $crawler = $client->getCrawler(); + $profiler = $client->getProfiler(); + +If your requests are not insulated, you can also access the ``Container`` and +the ``Kernel``:: + + $container = $client->getContainer(); + $kernel = $client->getKernel(); diff --git a/pt_BR/guides/testing/configuration.rst b/pt_BR/guides/testing/configuration.rst new file mode 100644 index 00000000000..8d8ce0b6024 --- /dev/null +++ b/pt_BR/guides/testing/configuration.rst @@ -0,0 +1,99 @@ +.. index:: + pair: Tests; Configuration + +Testing Configuration +===================== + +.. index:: + pair: PHPUnit; Configuration + +PHPUnit Configuration +--------------------- + +Each application has its own PHPUnit configuration, stored in the +``phpunit.xml.dist`` file. You can edit this file to change the defaults or +create a ``phpunit.xml`` file to tweak the configuration for your local machine. + +.. tip:: + Store the ``phpunit.xml.dist`` file in your code repository, and ignore the + ``phpunit.xml`` file. + +By default, only the tests stored in the ``Application`` namespace are run by +the ``phpunit`` command. But you can easily add more namespaces. For instance, +the following configuration adds the tests from the installed third-party +bundles: + +.. code-block:: xml + + + + + ../src/Application/*/Tests + ../src/Bundle/*/Tests + + + +To include other namespaces in the code coverage, also edit the ```` +section: + +.. code-block:: xml + + + + ../src/Application + ../src/Bundle + + ../src/Application/*/Resources + ../src/Application/*/Tests + ../src/Bundle/*/Resources + ../src/Bundle/*/Tests + + + + +Client Configuration +-------------------- + +The Client used by functional tests creates a Kernel that runs in a special +``test`` environment, so you can tweak it as much as you want: + +.. code-block:: yaml + + # config_test.yml + imports: + - { resource: config_dev.yml } + + web.config: + toolbar: false + + zend.logger: + priority: debug + + kernel.test: ~ + +You can also change the default environment (``test``) and override the default +debug mode (``true``) by passing them as options to the createClient() method:: + + $client = $this->createClient(array( + 'environment' => 'my_test_env', + 'debug' => false, + )); + +If your application behaves according to some HTTP headers, pass them as the +second argument of ``createClient()``:: + + $client = $this->createClient(array(), array( + 'HTTP_HOST' => 'en.example.com', + 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', + )); + +You can also override HTTP headers on a per request basis:: + + $client->request('GET', '/', array(), array( + 'HTTP_HOST' => 'en.example.com', + 'HTTP_USER_AGENT' => 'MySuperBrowser/1.0', + )); + +.. tip:: + To provide your own Client, override the ``test.client.class`` parameter, or + define a ``test.client`` service. diff --git a/pt_BR/guides/testing/crawler.rst b/pt_BR/guides/testing/crawler.rst new file mode 100644 index 00000000000..e2a87c64ecc --- /dev/null +++ b/pt_BR/guides/testing/crawler.rst @@ -0,0 +1,198 @@ +.. index:: + single: Tests; Crawler + +The Crawler +=========== + +A Crawler instance is returned each time you make a request with the Client. +It allows you to traverse HTML documents, select nodes, find links and forms. + +Creating a Crawler Instance +--------------------------- + +A Crawler instance is automatically created for you when you make a request +with a Client. But you can create your own easily:: + + use Symfony\Components\DomCrawler\Crawler; + + $crawler = new Crawler($html, $url); + +The constructor takes two arguments: the second one is the URL that is used to +generate absolute URLs for links and forms; the first one can be any of the +following: + +* An HTML document; +* An XML document; +* A ``DOMDocument`` instance; +* A ``DOMNodeList`` instance; +* A ``DOMNode`` instance; +* An array of the above elements. + +After creation, you can add more nodes: + +===================== ================================ +Method Description +===================== ================================ +``addHTMLDocument()`` An HTML document +``addXMLDocument()`` An XML document +``addDOMDocument()`` A ``DOMDocument`` instance +``addDOMNodeList()`` A ``DOMNodeList`` instance +``addDOMNode()`` A ``DOMNode`` instance +``addNodes()`` An array of the above elements +``add()`` Accept any of the above elements +===================== ================================ + +Traversing +---------- + +Like JQuery, the Crawler has methods to traverse the DOM of an HTML/XML +document: + +===================== ========================================= +Method Description +===================== ========================================= +``filter('h1')`` Nodes that match the CSS selector +``filterXpath('h1')`` Nodes that match the XPath expression +``eq(1)`` Node for the specified index +``first()`` First node +``last()`` Last node +``siblings()`` Siblings +``nextAll()`` All following siblings +``previousAll()`` All preceding siblings +``parents()`` Parent nodes +``children()`` Children +``reduce($lambda)`` Nodes for which the callable returns true +===================== ========================================= + +You can iteratively narrow your node selection by chaining method calls as +each method returns a new Crawler instance for the matching nodes:: + + $crawler + ->filter('h1') + ->reduce(function ($node, $i) + { + if (!$node->getAttribute('class')) { + return false; + } + }) + ->first(); + +.. tip:: + Use the ``count()`` function to get the number of nodes stored in a Crawler: + ``count($crawler)`` + +Extracting Information +---------------------- + +The Crawler can extract information from the nodes:: + + // Returns the attribute value for the first node + $crawler->attr('class'); + + // Returns the node value for the first node + $crawler->text(); + + // Extracts an array of attributes for all nodes (_text returns the node value) + $crawler->extract(array('_text', 'href')); + + // Executes a lambda for each node and return an array of results + $data = $crawler->each(function ($node, $i) + { + return $node->getAttribute('href'); + }); + +Links +----- + +You can select links with the traversing methods, but the ``selectLink()`` +shortcut is often more convenient:: + + $crawler->selectLink('Click here'); + +It selects links that contain the given text, or clickable images for which +the ``alt`` attribute contains the given text. + +The Client ``click()`` method takes a ``Link`` instance as returned by the +``link()`` method:: + + $link = $crawler->link(); + + $client->click($link); + +.. tip:: + The ``links()`` method returns an array of ``Link``s for all nodes. + +Forms +----- + +As for links, you select forms with the ``selectButton()`` method:: + + $crawler->selectButton('submit'); + +Notice that we select form buttons and not forms as a form can have several +buttons; if you use the traversing API, keep in mind that you must look for a +button. + +The ``selectButton()`` method can select ``button`` tags and submit ``input`` tags; +it has several heuristics to find them: + +* The ``value`` attribute value; + +* The ``id`` or ``alt`` attribute value for images; + +* The ``id`` or ``name`` attribute value for ``button`` tags. + +When you have a node representing a button, call the ``form()`` method to get a +``Form`` instance for the form wrapping the button node:: + + $form = $crawler->form(); + +When calling the ``form()`` method, you can also pass an array of field values +that overrides the default ones:: + + $form = $crawler->form(array( + 'name' => 'Fabien', + 'like_symfony' => true, + )); + +And if you want to simulate a specific HTTP method for the form, pass it as a +second argument:: + + $form = $crawler->form(array(), 'DELETE'); + +The Client can submit ``Form`` instances:: + + $client->submit($form); + +The field values can also be passed as a second argument of the ``submit()`` +method:: + + $client->submit($form, array( + 'name' => 'Fabien', + 'like_symfony' => true, + )); + +For more complex situations, use the ``Form`` instance as an array to set the +value of each field individually:: + + // Change the value of a field + $form['name'] = 'Fabien'; + +There is also a nice API to manipulate the values of the fields according to +their type:: + + // Select an option or a radio + $form['country']->select('France'); + + // Tick a checkbox + $form['like_symfony']->tick(); + + // Upload a file + $form['photo']->upload('/path/to/lucas.jpg'); + +.. tip:: + You can get the values that will be submitted by calling the ``getValues()`` + method. The uploaded files are available in a separate array returned by + ``getFiles()``. The ``getPhpValues()`` and ``getPhpFiles()`` also return the + submitted values, but in the PHP format (it converts the keys with square + brackets notation to PHP arrays). diff --git a/pt_BR/guides/testing/index.rst b/pt_BR/guides/testing/index.rst new file mode 100644 index 00000000000..76e665dc2fb --- /dev/null +++ b/pt_BR/guides/testing/index.rst @@ -0,0 +1,11 @@ +Testing +======= + +.. toctree:: + :maxdepth: 2 + + Overview + configuration + crawler + client + recipes diff --git a/pt_BR/guides/testing/overview.rst b/pt_BR/guides/testing/overview.rst new file mode 100644 index 00000000000..62fcd53c777 --- /dev/null +++ b/pt_BR/guides/testing/overview.rst @@ -0,0 +1,181 @@ +.. index:: + single: Tests + +Testing +======= + +Whenever you write a new line of code, you also potentially add new bugs. +Automated tests should have you covered and this tutorial shows you how to +write unit and functional tests for your Symfony2 application. + +Testing Framework +----------------- + +Symfony2 tests rely heavily on PHPUnit, its best practices, and some +conventions. This part does not document PHPUnit itself, but if you don't know +it yet, you can read its excellent `documentation`_. + +.. note:: + Symfony2 works with PHPUnit 3.5 or later. + +The default PHPUnit configuration looks for tests under ``Tests/`` +sub-directories of your bundles: + +.. code-block:: xml + + + + + + + ../src/Application/*/Tests + + + + ... + + +Running the test suite for a given application is straightforward: + +.. code-block:: bash + + # specify the configuration directory on the command line + $ phpunit -c hello/ + + # or run phpunit from within the application directory + $ cd hello/ + $ phpunit + +.. tip:: + Code coverage can be generated with the ``--coverage-html`` option. + +.. index:: + single: Tests; Unit Tests + +Unit Tests +---------- + +Writing Symony2 unit tests is no different than writing standard PHPUnit unit +tests. By convention, it's recommended to replicate the bundle directory +structure under its ``Tests/`` sub-directory. So, write tests for the +``Application\HelloBundle\Model\Article`` class in the +``Application/HelloBundle/Tests/Model/ArticleTest.php`` file. + +In a unit test, autoloading is automatically enabled via the +``src/autoload.php`` file (as configured by default in the ``phpunit.xml.dist`` +file). + +Running tests for a given file or directory is also very easy: + +.. code-block:: bash + + # run all tests for the Model + $ phpunit -c hello Application/HelloBundle/Tests/Model/ + + # run tests for the Article class + $ phpunit -c hello Application/HelloBundle/Tests/Model/ArticleTest.php + +.. index:: + single: Tests; Functional Tests + +Functional Tests +---------------- + +Functional tests check the integration of the different layers of an +application (from the routing to the views). They are no different from unit +tests as far as PHPUnit is concerned, but they have a very specific workflow: + +* Make a request; +* Test the response; +* Click on a link or submit a form; +* Test the response; +* Rinse and repeat. + +Requests, clicks, and submissions are done by a client that knows how to talk +to the application. To access such a client, your tests need to extends the +Symfony2 ``WebTestCase`` class. The sandbox provides a simple functional test +for ``HelloController`` that reads as follows:: + + // src/Application/HelloBundle/Tests/Controller/HelloControllerTest.php + namespace Application\HelloBundle\Tests\Controller; + + use Symfony\Framework\FoundationBundle\Test\WebTestCase; + + class HelloControllerTest extends WebTestCase + { + public function testIndex() + { + $client = $this->createClient(); + $crawler = $client->request('GET', '/hello/Fabien'); + + $this->assertEquals(1, $crawler->filter('html:contains("Hello Fabien")')); + } + } + +The ``createClient()`` method returns a client tied to the current application:: + + $crawler = $client->request('GET', 'hello/Fabien'); + +The ``request()`` method returns a ``Crawler`` object which can be used to select +elements in the Response, to click on links, and to submit forms. + +.. tip:: + The Crawler can only be used if the Response content is an XML or an HTML + document. + +Click on a link by first selecting it with the Crawler using either a XPath +expression or a CSS selector, then use the Client to click on it:: + + $link = $crawler->filter('a:contains("Greet")')->eq(1)->link(); + + $crawler = $client->click($link); + +Submitting a form is very similar; select a form button, optionally override +some form values, and submit the corresponding form:: + + $form = $crawler->selectButton('submit'); + + // set some values + $form['name'] = 'Lucas'; + + // submit the form + $crawler = $client->submit($form); + +Each ``Form`` field has specialized methods depending on its type:: + + // fill an input field + $form['name'] = 'Lucas'; + + // select an option or a radio + $form['country']->select('France'); + + // tick a checkbox + $form['like_symfony']->tick(); + + // upload a file + $form['photo']->upload('/path/to/lucas.jpg'); + +Instead of changing one field at a time, you can also pass an array of values +to the ``submit()`` method:: + + $crawler = $client->submit($form, array( + 'name' => 'Lucas', + 'country' => 'France', + 'like_symfony' => true, + 'photo' => '/path/to/lucas.jpg', + )); + +Now that you can easily navigate through an application, use assertions to +test that it actually does what you expect it to. Use the Crawler to make +assertions on the DOM:: + + // Assert that the response matches a given CSS selector. + $this->assertTrue(count($crawler->filter('h1')) > 0); + +Or, test against the Response content directly if you just want to assert that +the content contains some text, or if the Response is not an XML/HTML +document:: + + $this->assertRegExp('/Hello Fabien/', $client->getResponse()->getContent()); + +.. _documentation: http://www.phpunit.de/manual/3.5/en/ diff --git a/pt_BR/guides/testing/recipes.rst b/pt_BR/guides/testing/recipes.rst new file mode 100644 index 00000000000..5aff013c967 --- /dev/null +++ b/pt_BR/guides/testing/recipes.rst @@ -0,0 +1,159 @@ +.. index:: + single: Tests; Recipes + +Testing Recipes +=============== + +Insulating Clients +------------------ + +If you need to simulate an interaction between different Clients (think of a +chat for instance), create several Clients:: + + $harry = $this->createClient(); + $sally = $this->createClient(); + + $harry->request('POST', '/say/sally/Hello'); + $sally->request('GET', '/messages'); + + $this->assertEquals(201, $harry->getResponse()->getStatusCode()); + $this->assertRegExp('/Hello/', $sally->getResponse()->getContent()); + +This works except when your code maintains a global state or if it depends on +third-party libraries that has some kind of global state. In such a case, you +can insulate your clients:: + + $harry = $this->createClient(); + $sally = $this->createClient(); + + $harry->insulate(); + $sally->insulate(); + + $harry->request('POST', '/say/sally/Hello'); + $sally->request('GET', '/messages'); + + $this->assertEquals(201, $harry->getResponse()->getStatusCode()); + $this->assertRegExp('/Hello/', $sally->getResponse()->getContent()); + +Insulated clients transparently execute their requests in a dedicated and +clean PHP process, thus avoiding any side-effects. + +.. tip:: + As an insulated client is slower, you can keep one client in the main process, + and insulate the other ones. + +Testing Redirection +------------------- + +By default, the Client follows HTTP redirects. But if you want to get the +Response before the redirection and redirect yourself, calls the +``followRedirects()`` method:: + + $client->followRedirects(false); + + $crawler = $this->request('GET', '/'); + + // do something with the redirect response + + // follow the redirection manually + $crawler = $this->followRedirect(); + + $client->followRedirects(true); + +.. index:: + single: Tests; HTTP Authorization + +HTTP Authorization +------------------ + +If your application needs HTTP authentication, pass the username and password +as server variables to ``createClient()``:: + + $client = $this->createClient(array(), array( + 'PHP_AUTH_USER' => 'username', + 'PHP_AUTH_PW' => 'pa$$word', + )); + +You can also override it on a per request basis:: + + $client->request('DELETE', '/post/12', array(), array( + 'PHP_AUTH_USER' => 'username', + 'PHP_AUTH_PW' => 'pa$$word', + )); + +.. index:: + single: Tests; Profiling + +Profiling +--------- + +It's highly recommended that a functional test only tests the Response. But if +you write functional tests that monitor your production servers, you might +want to write tests on the profiling data. + +The Symfony2 profiler gathers a lot of data for each request. Use these data +to check the number of database calls, the time spent in the framework, ... +But before writing assertions, always check that the profiler is indeed +available (it is enabled by default in the ``test`` environment):: + + if ($profiler = $client->getProfiler()) { + // check the number of requests + $this->assertTrue($profiler['db']->getQueryCount() < 10); + + // check the time spent in the framework + $this->assertTrue( $profiler['timer']->getTime() < 0.5); + + // check the matching route + $this->assertEquals('blog_post', $profiler['app']->getRoute()); + } + +.. note:: + The profiler information are available even if you insulate the client or if + you use an HTTP layer for your tests. + +Container +--------- + +It's highly recommended that a functional test only tests the Response. But +under certain very rare circumstances, you might want to access some internal +objects to write assertions. In such cases, you can access the dependency +injection container:: + + $container = $client->getContainer(); + +Be warned that this does not work if you insulate the client or if you use an +HTTP layer. + +.. tip:: + If the information you need to check are available from the profiler, use them + instead. + +.. index:: + single: Tests; Assertions + +Useful Assertions +----------------- + +After some time, you will notice that you always write the same kind of +assertions. To get you started faster, here is a list of the most common and +useful assertions:: + + // Assert that the response matches a given CSS selector. + $this->assertTrue(count($crawler->filter($selector)) > 0); + + // Assert that the response matches a given CSS selector n times. + $this->assertEquals($count, $crawler->filter($selector)->count()); + + // Assert the a response header has the given value. + $this->assertTrue($client->getResponse()->headers->contains($key, $value)); + + // Assert that the response content matches a regexp. + $this->assertRegExp($regexp, $client->getResponse()->getContent()); + + // Assert the response status code. + $this->assertTrue($client->getResponse()->isSuccessful()); + $this->assertTrue($client->getResponse()->isNotFound()); + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + + // Assert that the response status code is a redirect. + $this->assertTrue($client->getResponse()->isRedirected('google.com')); diff --git a/pt_BR/guides/tools/YAML.rst b/pt_BR/guides/tools/YAML.rst new file mode 100644 index 00000000000..8abe3d8bbab --- /dev/null +++ b/pt_BR/guides/tools/YAML.rst @@ -0,0 +1,375 @@ +.. index:: + single: YAML + single: Configuration; YAML + +YAML +==== + +`YAML`_ website is "a human friendly data serialization standard for all +programming languages". YAML is a simple language that describes data. As PHP, +it has a syntax for simple types like strings, booleans, floats, or integers. +But unlike PHP, it makes a difference between arrays (sequences) and hashes +(mappings). + +The Symfony2 YAML Component knows how to parse YAML and dump a PHP array to +YAML. + +.. note:: + Even if the YAML format can describe complex nested data structure, this guide + only describes the minimum set of features needed to use YAML as a + configuration file format. + +Reading YAML Files +------------------ + +The ``Parser::parse()`` method parses a YAML string and converts it to a PHP +array:: + + use Symfony\Components\Yaml\Parser; + + $yaml = new Parser(); + $value = $yaml->parse(file_get_contents('/path/to/file.yaml')); + +If an error occurs during parsing, the parser throws an exception indicating +the error type and the line in the original YAML string where the error +occurred:: + + try { + $value = $yaml->parse(file_get_contents('/path/to/file.yaml')); + } catch (\InvalidArgumentException $e) { + // an error occurred during parsing + echo "Unable to parse the YAML string: ".$e->getMessage(); + } + +.. tip:: + As the parser is reentrant, you can use the same parser object to load + different YAML strings. + +When loading a YAML file, it is sometimes better to use the ``Yaml::load()`` +wrapper method:: + + use Symfony\Components\Yaml\Yaml; + + $loader = Yaml::load('/path/to/file.yml'); + +The ``Yaml::load()`` static method takes a YAML string or a file containing +YAML. Internally, it calls the ``Parser::parse()`` method, but with some added +bonuses: + +* It executes the YAML file as if it was a PHP file, so that you can embed + PHP commands in YAML files; + +* When a file cannot be parsed, it automatically adds the file name to the + error message, simplifying debugging when your application is loading + several YAML files. + +Writing YAML Files +------------------ + +The ``Dumper::dump()`` method dumps any PHP array to its YAML representation:: + + use Symfony\Components\Yaml\Dumper; + + $array = array('foo' => 'bar', 'bar' => array('foo' => 'bar', 'bar' => 'baz')); + + $dumper = new Dumper(); + $yaml = $dumper->dump($array); + file_put_contents('/path/to/file.yaml', $yaml); + +.. note:: + There are some limitations: the dumper is not able to dump resources and + dumping PHP objects is considered an alpha feature. + +If you only need to dump one array, you can use the ``Yaml::dump()`` static +method shortcut:: + + $yaml = Yaml::dump($array, $inline); + +The YAML format supports the two YAML array representations. By default, the +dumper uses the inline representation: + +.. code-block:: yaml + + { foo: bar, bar: { foo: bar, bar: baz } } + +But the second argument of the ``dump()`` method customizes the level at which +the output switches from the expanded representation to the inline one:: + + echo $dumper->dump($array, 1); + +.. code-block:: yaml + + foo: bar + bar: { foo: bar, bar: baz } + +.. code-block:: php + + echo $dumper->dump($array, 2); + +.. code-block:: yaml + + foo: bar + bar: + foo: bar + bar: baz + +The YAML Syntax +--------------- + +Strings +~~~~~~~ + +.. code-block:: yaml + + A string in YAML + +.. code-block:: yaml + + 'A singled-quoted string in YAML' + +.. tip:: + In a single quoted string, a single quote ``'`` must be doubled: + + .. code-block:: yaml + + 'A single quote '' in a single-quoted string' + +.. code-block:: yaml + + "A double-quoted string in YAML\n" + +Quoted styles are useful when a string starts or ends with one or more +relevant spaces. + +.. tip:: + The double-quoted style provides a way to express arbitrary strings, by + using ``\`` escape sequences. It is very useful when you need to embed a + ``\n`` or a unicode character in a string. + +When a string contains line breaks, you can use the literal style, indicated +by the pipe (``|``), to indicate that the string will span several lines. In +literals, newlines are preserved: + +.. code-block:: yaml + + | + \/ /| |\/| | + / / | | | |__ + +Alternatively, strings can be written with the folded style, denoted by ``>``, +where each line break is replaced by a space: + +.. code-block:: yaml + + > + This is a very long sentence + that spans several lines in the YAML + but which will be rendered as a string + without carriage returns. + +.. note:: + Notice the two spaces before each line in the previous examples. They + won't appear in the resulting PHP strings. + +Numbers +~~~~~~~ + +.. code-block:: yaml + + # an integer + 12 + +.. code-block:: yaml + + # an octal + 014 + +.. code-block:: yaml + + # an hexadecimal + 0xC + +.. code-block:: yaml + + # a float + 13.4 + +.. code-block:: yaml + + # an exponential number + 1.2e+34 + +.. code-block:: yaml + + # infinity + .inf + +Nulls +~~~~~ + +Nulls in YAML can be expressed with ``null`` or ``~``. + +Booleans +~~~~~~~~ + +Booleans in YAML are expressed with ``true`` and ``false``. + +Dates +~~~~~ + +YAML uses the ISO-8601 standard to express dates: + +.. code-block:: yaml + + 2001-12-14t21:59:43.10-05:00 + +.. code-block:: yaml + + # simple date + 2002-12-14 + +Collections +~~~~~~~~~~~ + +A YAML file is rarely used to describe a simple scalar. Most of the time, it +describes a collection. A collection can be a sequence or a mapping of +elements. Both sequences and mappings are converted to PHP arrays. + +Sequences use a dash followed by a space (``- ``): + +.. code-block:: yaml + + - PHP + - Perl + - Python + +The previous YAML file is equivalent to the following PHP code:: + + array('PHP', 'Perl', 'Python'); + +Mappings use a colon followed by a space (``: ``) to mark each key/value pair: + +.. code-block:: yaml + + PHP: 5.2 + MySQL: 5.1 + Apache: 2.2.20 + +which is equivalent to this PHP code:: + + array('PHP' => 5.2, 'MySQL' => 5.1, 'Apache' => '2.2.20'); + +.. note:: + In a mapping, a key can be any valid scalar. + +The number of spaces between the colon and the value does not matter: + +.. code-block:: yaml + + PHP: 5.2 + MySQL: 5.1 + Apache: 2.2.20 + +YAML uses indentation with one or more spaces to describe nested collections: + +.. code-block:: yaml + + "symfony 1.4": + PHP: 5.2 + Doctrine: 1.2 + "Symfony2": + PHP: 5.3 + Doctrine: 2.0 + +The following YAML is equivalent to the following PHP code:: + + array( + 'symfony 1.4' => array( + 'PHP' => 5.2, + 'Doctrine' => 1.2, + ), + 'Symfony2' => array( + 'PHP' => 5.3, + 'Doctrine' => 2.0, + ), + ); + +There is one important thing you need to remember when using indentation in a +YAML file: *Indentation must be done with one or more spaces, but never with +tabulations*. + +You can nest sequences and mappings as you like: + +.. code-block:: yaml + + 'Chapter 1': + - Introduction + - Event Types + 'Chapter 2': + - Introduction + - Helpers + +YAML can also use flow styles for collections, using explicit indicators +rather than indentation to denote scope. + +A sequence can be written as a comma separated list within square brackets +(``[]``): + +.. code-block:: yaml + + [PHP, Perl, Python] + +A mapping can be written as a comma separated list of key/values within curly +braces (``{}``): + +.. code-block:: yaml + + { PHP: 5.2, MySQL: 5.1, Apache: 2.2.20 } + +You can mix and match styles to achieve a better readability: + +.. code-block:: yaml + + 'Chapter 1': [Introduction, Event Types] + 'Chapter 2': [Introduction, Helpers] + +.. code-block:: yaml + + "symfony 1.4": { PHP: 5.2, Doctrine: 1.2 } + "Symfony2": { PHP: 5.3, Doctrine: 2.0 } + +Comments +~~~~~~~~ + +Comments can be added in YAML by prefixing them with a hash mark (``#``): + +.. code-block:: yaml + + # Comment on a line + "Symfony2": { PHP: 5.3, Doctrine: 2.0 } # Comment at the end of a line + +.. note:: + Comments are simply ignored by the YAML parser and do not need to be + indented according to the current level of nesting in a collection. + +Dynamic YAML files +~~~~~~~~~~~~~~~~~~ + +In Symfony, a YAML file can contain PHP code that is evaluated just before the +parsing occurs:: + + 1.0: + version: + 1.1: + version: "" + +Be careful to not mess up with the indentation. Keep in mind the following +simple tips when adding PHP code to a YAML file: + +* The ```` statements must always start the line or be embedded in a + value. + +* If a ```` statement ends a line, you need to explicitly output a new + line ("\n"). + +.. _YAML: http://yaml.org/ diff --git a/pt_BR/guides/tools/autoloader.rst b/pt_BR/guides/tools/autoloader.rst new file mode 100644 index 00000000000..a1c40acaea0 --- /dev/null +++ b/pt_BR/guides/tools/autoloader.rst @@ -0,0 +1,81 @@ +.. index:: + pair: Autoloader; Configuration + +Autoloader +========== + +Whenever you use an undefined class, PHP uses the autoloading mechanism to +delegate the loading of a file defining the class. Symfony2 provides a +"universal" autoloader, which is able to load classes from files that +implement one of the following conventions: + +* The technical interoperability `standards`_ for PHP 5.3 namespaces and class + names; + +* The `PEAR`_ naming convention for classes. + +If your classes and the third-party libraries you use for your project follow +these standards, the Symfony2 autoloader is the only autoloader you will ever +need. + +Usage +----- + +Registering the autoloader is straightforward:: + + require_once '/path/to/src/Symfony/Foundation/UniversalClassLoader.php'; + + use Symfony\Foundation\UniversalClassLoader; + + $loader = new UniversalClassLoader(); + $loader->register(); + +The autoloader is useful only if you add some libraries to autoload. + +.. note:: + The autoloader is automatically registered in a Symfony2 application (see + ``src/autoload.php``). + +If the classes to autoload use namespaces, use the ``registerNamespace()`` or +``registerNamespaces()`` methods:: + + $loader->registerNamespace('Symfony', __DIR__.'/vendor/symfony/src'); + + $loader->registerNamespaces(array( + 'Symfony' => __DIR__.'/vendor/symfony/src', + 'Zend' => __DIR__.'/vendor/zend/library', + )); + +For classes that follow the PEAR naming convention, use the ``registerPrefix`` +or ``registerPrefixes`` methods:: + + $loader->registerPrefix('Twig_', __DIR__.'/vendor/twig/lib'); + + $loader->registerPrefixes(array( + 'Swift_' => __DIR__.'/vendor/swiftmailer/lib/classes', + 'Twig_' => __DIR__.'/vendor/twig/lib', + )); + +.. note:: + Some libraries also need that their root path be registered in the PHP include + path (``set_include_path()``). + +Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be looked +for in a list of locations to ease the vendoring of a sub-set of classes for +large projects:: + + $loader->registerNamespaces(array( + 'Doctrine\Common' => __DIR__.'/vendor/doctrine/lib/vendor/doctrine-common/lib', + 'Doctrine\DBAL\Migrations' => __DIR__.'/vendor/doctrine-migrations/lib', + 'Doctrine\DBAL' => __DIR__.'/vendor/doctrine/lib/vendor/doctrine-dbal/lib', + 'Doctrine' => __DIR__.'/vendor/doctrine/lib', + )); + +In this example, if you try to use a class in the ``Doctrine\Common`` namespace +or one of its children, the autoloader will first look for the class under the +``doctrine-common`` directory, and it will then fallback to the default +``Doctrine`` directory (the last one configured) if not found, before giving up. +The order of the registrations is significant in this case. + +.. _standards: http://groups.google.com/group/php-standards/web/psr-0-final-proposal +.. _PEAR: http://pear.php.net/manual/en/standards.php diff --git a/pt_BR/guides/tools/finder.rst b/pt_BR/guides/tools/finder.rst new file mode 100644 index 00000000000..7d8c4b2d820 --- /dev/null +++ b/pt_BR/guides/tools/finder.rst @@ -0,0 +1,197 @@ +.. index:: + single: Finder + +The Finder +========== + +The Finder Component helps you find files and directories quickly and easily. + +Usage +----- + +The ``Finder`` class finds files and/or directories:: + + use Symfony\Components\Finder\Finder; + + $finder = new Finder(); + $finder->files()->in(__DIR__); + + foreach ($finder as $file) { + print $file->getRealpath()."\n"; + } + +The ``$file`` is an instance of [``SplFileInfo``][1]. + +The above code prints the names of all the files in the current directory +recursively. The Finder class uses a fluent interface, so all methods return +the Finder instance. + +.. tip:: + A Finder instance is a PHP [``Iterator``][2]. So, instead of iterating over the + Finder with ``foreach``, you can also convert it to an array with the + ``iterator_to_array()`` method, or get the number of items with + ``iterator_count()``. + +Criteria +-------- + +Location +~~~~~~~~ + +The location is the only mandatory criteria. It tells the finder which +directory to use for the search:: + + $finder->in(__DIR__); + +Search in several locations by chaining calls to ``in()``:: + + $finder->files()->in(__DIR__)->in('/elsewhere'); + +Exclude directories from matching with the ``exclude()`` method:: + + $finder->in(__DIR__)->exclude('ruby'); + +As the Finder uses PHP iterators, you can pass any URL with a supported +`protocol`_:: + + $finder->in('ftp://example.com/pub/'); + +And it also works with user-defined streams:: + + use Symfony\Components\Finder\Finder; + + $s3 = new \Zend_Service_Amazon_S3($key, $secret); + $s3->registerStreamWrapper("s3"); + + $finder = new Finder(); + $finder->name('photos*')->size('< 100K')->date('since 1 hour ago'); + foreach ($finder->in('s3://bucket-name') as $file) { + // do something + + print $file->getFilename()."\n"; + } + +.. note:: + Read the `Streams`_ documentation to learn how to create your own streams. + +Files or Directories + +By default, the Finder returns files and directories; but the ``files()`` and +``directories()`` methods controls that:: + + $finder->files(); + + $finder->directories(); + +If you want to follow links, use the ``followLinks()`` method:: + + $finder->files()->followLinks(); + +By default, the iterator ignores popular VCS files. This can be changed with +the ``ignoreVCS()`` method:: + + $finder->ignoreVCS(false); + +Sorting +~~~~~~~ + +Sort the result by name or by type (directories first, then files):: + + $finder->sortByName(); + + $finder->sortByType(); + +.. note:: + Notice that the ``sort*`` methods need to get all matching elements to do their + jobs. For large iterators, it is slow. + +You can also define your own sorting algorithm with ``sort()``:: + + $sort = function (\SplFileInfo $a, \SplFileInfo $b) + { + return strcmp($a->getRealpath(), $b->getRealpath()); + }; + + $finder->sort($sort); + +File Name +~~~~~~~~~ + +Restrict files by name with the ``name()`` method:: + + $finder->files()->name('*.php'); + +The ``name()`` method accepts globs, strings, or regexes:: + + $finder->files()->name('/\.php$/'); + +The ``notNames()`` method excludes files matching a pattern:: + + $finder->files()->notName('*.rb'); + +File Size +~~~~~~~~~ + +Restrict files by size with the ``size()`` method:: + + $finder->files()->size('< 1.5K'); + +Restrict by a size range by chaining calls:: + + $finder->files()->size('>= 1K')->size('<= 2K'); + +The comparison operator can be any of the following: ``>``, ``>=``, ``<``, '<=', +'=='. + +The target value may use magnitudes of kilobytes (``k``, ``ki``), megabytes (``m``, +``mi``), or gigabytes (``g``, ``gi``). Those suffixed with an ``i`` use the +appropriate ``2**n`` version in accordance with the `IEC standard`_. + +File Date +~~~~~~~~~ + +Restrict files by last modified dates with the ``date()`` method:: + + $finder->date('since yesterday'); + +The comparison operator can be any of the following: ``>``, ``>=``, ``<``, '<=', +'=='. You can also use ``since`` or ``after`` as an alias for ``>``, and ``until`` or +``before`` as an alias for ``<``. + +The target value can be any date supported by the [``strtotime()``][6] function. + +Directory Depth +~~~~~~~~~~~~~~~ + +By default, the Finder recursively traverse directories. Restrict the depth of +traversing with ``depth()``:: + + $finder->depth('== 0'); + $finder->depth('< 3'); + +Custom Filtering +~~~~~~~~~~~~~~~~ + +To restrict the matching file with your own strategy, use ``filter()``:: + + $filter = function (\SplFileInfo $file) + { + if (strlen($file) > 10) + { + return false; + } + }; + + $finder->files()->filter($filter); + +The ``filter()`` methods takes a Closure as an argument. For each matching file, +it is called with the file as a [``SplFileInfo``][1] instance. The file is +excluded from the result set if the Closure returns ``false``. + +[1]: http://www.php.net/manual/en/class.splfileinfo.php +[2]: http://www.php.net/manual/en/spl.iterators.php +[6]: http://www.php.net/manual/en/datetime.formats.php + +.. _protocol: http://www.php.net/manual/en/wrappers.php +.. _Streams: http://www.php.net/streams +.. _IEC standard: http://physics.nist.gov/cuu/Units/binary.html diff --git a/pt_BR/guides/tools/index.rst b/pt_BR/guides/tools/index.rst new file mode 100644 index 00000000000..3988c5e9dd9 --- /dev/null +++ b/pt_BR/guides/tools/index.rst @@ -0,0 +1,9 @@ +Tools +===== + +.. toctree:: + :maxdepth: 2 + + autoloader + finder + YAML diff --git a/pt_BR/guides/validator.rst b/pt_BR/guides/validator.rst new file mode 100644 index 00000000000..5ce63091802 --- /dev/null +++ b/pt_BR/guides/validator.rst @@ -0,0 +1,427 @@ +.. index:: + single: Forms; Validators + single: Validators + +Validator +========= + +The Basics +---------- + +The new Validator component is based on the `JSR303 Bean Validation +specification`_. What? A Java specification in PHP? You heard right, but +it's not as bad as it sounds. Let's look at how we use it in PHP. + +The Validator is designed to validate objects against different constraints. +These constraints can be put on the class itself, on properties and on +methods prefixed with "get" or "is". Let's look at a sample configuration:: + + class Author + { + /** + * @Validation({ + * @NotBlank, + * @MinLength(4) + * }) + */ + public $firstName; + + /** + * @Validation({ + * @Email(message="Ok, seriously now. Your email address please") + * }) + */ + public function getEmail() + { + return 'foobar'; + } + } + +This snippet shows a very simple ``Author`` class with a property and a getter. +Each constraint has a name, most of them also have a couple of options. Here we +configured the constraints with annotations, but Symfony2 also offers many +other configuration drivers. + +Because the annotation driver depends on the Doctrine library, it is not enabled +by default. You can enable it in your ``config.yml``: + +.. code-block:: yaml + + # hello/config/config.yml + web.validation: + annotations: true + +Now let's try to validate an object:: + + $validator = $this->container->getValidatorService(); + + $author = new Author(); + $author->firstName = 'B.'; + + print $validator->validate($author); + +You should see the following output:: + + Author.firstName: + This value is too short. It should have 4 characters or more + Author.email: + Ok, seriously now. Your email address please + +The ``validate()`` method returns a ``ConstraintViolationList`` object that can +simply be printed or processed in your code. That was easy! + +.. index:: + single: Validators; Constraints + +The Constraints +--------------- + +Symfony bundles many different constraints. The following list will show you +which ones are available and how you can use and configure them. Some +constraints have a default option. If you only set this option, you can leave +away the option name:: + + /** @Validation({ @Min(limit=3) }) */ + +is identical to:: + + /** @Validation({ @Min(3) }) */ + +AssertFalse +~~~~~~~~~~~ + +Validates that a value is ``false``. Very useful for testing return values of +methods:: + + /** @Validation({ @AssertFalse }) */ + public function isInjured(); + +Options: + +* message: The error message if validation fails + +AssertTrue +~~~~~~~~~~ + +Works like ``AssertFalse``. + +NotBlank +~~~~~~~~ + +Validates that a value is not empty:: + + /** @Validation({ @NotBlank }) */ + private $firstName; + +Options: + +* message: The error message if validation fails + +Blank +~~~~~ + +Works like ``NotBlank``. + +NotNull +~~~~~~~ + +Validates that a value is not ``NULL``:: + + /** @Validation({ @NotNull }) */ + private $firstName; + +Null +~~~~ + +Works like ``NotNull``. + +AssertType +~~~~~~~~~~ + +Validates that a value has a specific data type:: + + /** @Validation({ @AssertType("integer") }) */ + private $age; + +Options: + +* type (default): The type + +Choice +~~~~~~ + +Validates that a value is one or more of a list of choices:: + + /** @Validation({ @Choice({"male", "female"}) }) */ + private $gender; + +Options: + +* choices (default): The available choices +* callback: Can be used instead of ``choices``. A static callback method + returning the choices. If you set this to a string, the method is expected + to be in the validated class. +* multiple: Whether multiple choices are allowed. Default: ``false`` +* min: The minimum amount of selected choices +* max: The maximum amount of selected choices +* message: The error message if validation fails +* minMessage: The error message if ``min`` validation fails +* maxMessage: The error message if ``max`` validation fails + +Valid +~~~~~ + +Validates that an object is valid. Can be put on properties or getters to +validate related objects:: + + /** @Validation({ @Valid }) */ + private $address; + +Options: + +* class: The expected class of the object (optional) +* message: The error message if the class doesn't match + +Collection +~~~~~~~~~~ + +Validates array entries against different constraints:: + + /** + * @Validation({ @Collection( + * fields = { + * "firstName" = @NotNull, + * "lastName" = { @NotBlank, @MinLength(4) } + * }, + * allowMissingFields = true + * )}) + */ + private $options = array(); + +Options: + +* fields (default): An associative array of array keys and one or more + constraints +* allowMissingFields: Whether some of the keys may not be present in the + array. Default: ``false`` +* allowExtraFields: Whether the array may contain keys not present in the + ``fields`` option. Default: ``false`` +* missingFieldsMessage: The error message if the ``allowMissingFields`` + validation fails +* allowExtraFields: The error message if the ``allowExtraFields`` validation + fails + +Date +~~~~ + +Validates that a value is a valid date string with format ``YYYY-MM-DD``:: + + /** @Validation({ @Date }) */ + private $birthday; + +Options: + +* message: The error message if the validation fails + +DateTime +~~~~~~~~ + +Validates that a value is a valid datetime string with format ``YYYY-MM-DD +HH:MM:SS``:: + + /** @Validation({ @DateTime }) */ + private $createdAt; + +Options: + +* message: The error message if the validation fails + +Time +~~~~ + +Validates that a value is a valid time string with format ``HH:MM:SS``:: + + /** @Validation({ @Time }) */ + private $start; + +Options: + +* message: The error message if the validation fails + +Email +~~~~~ + +Validates that a value is a valid email address:: + + /** @Validation({ @Email }) */ + private $email; + +Options: + +* message: The error message if the validation fails +* checkMX: Whether MX records should be checked for the domain. Default: ``false`` + +File +~~~~ + +Validates that a value is an existing file:: + + /** @Validation({ @File(maxSize="64k") }) */ + private $filename; + +Options: + +* maxSize: The maximum allowed file size. Can be provided in bytes, kilobytes + (with the suffix "k") or megabytes (with the suffix "M") +* mimeTypes: One or more allowed mime types +* notFoundMessage: The error message if the file was not found +* notReadableMessage: The error message if the file could not be read +* maxSizeMessage: The error message if ``maxSize`` validation fails +* mimeTypesMessage: The error message if ``mimeTypes`` validation fails + +Max +~~~ + +Validates that a value is at most the given limit:: + + /** @Validation({ @Max(99) }) */ + private $age; + +Options: + +* limit (default): The limit +* message: The error message if validation fails + +Min +~~~ + +Works like ``Max``. + +MaxLength +~~~~~~~~~ + +Validates that the string length of a value is at most the given limit:: + + /** @Validation({ @MaxLength(32) }) */ + private $hash; + +Options: + +* limit (default): The size limit +* message: The error message if validation fails + +MinLength +~~~~~~~~~ + +Works like ``MaxLength``. + +Regex +~~~~~ + +Validates that a value matches the given regular expression:: + + /** @Validation({ @Regex("/\w+/") }) */ + private $title; + +Options: + +* pattern (default): The regular expression pattern +* match: Whether the pattern must be matched or must not be matched. + Default: ``true`` +* message: The error message if validation fails + +Url +~~~ + +Validates that a value is a valid URL:: + + /** @Validation({ @Url }) */ + private $website; + +Options: + +* protocols: A list of allowed protocols. Default: "http", "https", "ftp" + and "ftps". +* message: The error message if validation fails + +.. index:: + single: Validators; Configuration + +Other Configuration Drivers +--------------------------- + +As always in Symfony, there are multiple ways of configuring the constraints +for your classes. Symfony supports the following four drivers. + +XML Configuration +~~~~~~~~~~~~~~~~~ + +The XML driver is a little verbose, but has the benefit that the XML file can be +validated to prevent errors. To use the driver, simply put a file called +``validation.xml`` in the ``Resources/config/`` directory of your bundle: + +.. code-block:: xml + + + + + + + + 4 + + + + + + + + + +YAML Configuration +~~~~~~~~~~~~~~~~~~ + +The YAML driver offers the same functionality as the XML driver. To use it, +put the file ``validation.yml`` in the ``Resources/config/`` directory of your +bundle: + +.. code-block:: yaml + + Application\HelloBundle\Model\Author: + properties: + firstName: + - NotBlank: ~ + - MinLength: 4 + + getters: + email: + - Email: { message: "Ok, seriously now. Your email address please" } + +PHP Configuration +~~~~~~~~~~~~~~~~~ + +If you prefer to write configurations in plain old PHP, you can add the static +method ``loadValidatorMetadata()`` to the classes that you want to validate:: + + use Symfony\Components\Validator\Constraints; + use Symfony\Components\Validator\Mapping\ClassMetadata; + + class Author + { + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('firstName', new Constraints\NotBlank()); + $metadata->addPropertyConstraint('firstName', new Constraints\MinLength(3)); + $metadata->addGetterConstraint('email', new Constraints\Email(array( + 'message' => 'Ok, seriously now. Your email address please', + ))); + } + } + +You can use either of the configuration drivers, or all together. Symfony will +merge all the information it can find. + +.. _JSR303 Bean Validation specification: http://jcp.org/en/jsr/detail?id=303 diff --git a/pt_BR/index.rst b/pt_BR/index.rst new file mode 100644 index 00000000000..2a5d6603587 --- /dev/null +++ b/pt_BR/index.rst @@ -0,0 +1,41 @@ +Symfony2 Documentation +====================== + +Quick Tour +---------- + +Get started fast with the Symfony2 :doc:`Quick Tour `: + +.. toctree:: + :hidden: + + quick_tour/index + +* :doc:`quick_tour/the_big_picture` > +* :doc:`quick_tour/the_view` > +* :doc:`quick_tour/the_controller` > +* :doc:`quick_tour/the_architecture` + +Guides +------ + +Dive into Symfony2 with the topical guides: + +.. toctree:: + :hidden: + + guides/index + +.. include:: guides/map.rst.inc + +Contributing +------------ + +Contribute to Symfony2: + +.. toctree:: + :hidden: + + contributing/index + +.. include:: contributing/map.rst.inc diff --git a/pt_BR/quick_tour/index.rst b/pt_BR/quick_tour/index.rst new file mode 100644 index 00000000000..cedb51b0566 --- /dev/null +++ b/pt_BR/quick_tour/index.rst @@ -0,0 +1,15 @@ +Quick Tour +========== + +Get started fast with the Symfony2 Quick Tour: + +.. toctree:: + :maxdepth: 2 + :glob: + :numbered: + + the_big_picture + the_view + the_controller + the_architecture + diff --git a/pt_BR/quick_tour/the_architecture.rst b/pt_BR/quick_tour/the_architecture.rst new file mode 100644 index 00000000000..d1421ffd020 --- /dev/null +++ b/pt_BR/quick_tour/the_architecture.rst @@ -0,0 +1,293 @@ +The Architecture +================ + +You are my hero! Who would have thought that you would still be here after the +first three parts? Your efforts will be well rewarded soon. The first three +parts don't have a deep look at the architecture of the framework. As it makes +Symfony stand apart from the framework crowd, let's dive into it now. + +.. index:: + single: Directory Structure + +The Directory Structure +----------------------- + +The directory structure of a Symfony application is rather flexible but the +directory structure of a sandbox reflects the typical and recommended +structure of a Symfony application: + +* ``hello/``: This directory, named after your application, contains the + configuration files; + +* ``src/``: All the PHP code is stored under this directory; + +* ``web/``: This should be the web root directory. + +The Web Directory +~~~~~~~~~~~~~~~~~ + +The web root directory is the home of all public and static files like images, +stylesheets, and JavaScript files. It is also where the front controllers +live: + +.. code-block:: html+php + + # web/index.php + handle()->send(); + +Like any front controller, ``index.php`` uses a Kernel Class, ``HelloKernel``, to +bootstrap the application. + +.. index:: + single: Kernel + +The Application Directory +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``HelloKernel`` class is the main entry point of the application +configuration and as such, it is stored in the ``hello/`` directory. + +This class must implement five methods: + +* ``registerRootDir()``: Returns the configuration root directory; + +* ``registerBundles()``: Returns an array of all bundles needed to run the + application (notice the reference to + ``Application\HelloBundle\HelloBundle``); + +* ``registerBundleDirs()``: Returns an array associating namespaces and their + home directories; + +* ``registerContainerConfiguration()``: Returns the main configuration object + (more on this later); + +* ``registerRoutes()``: Returns the routing configuration. + +Have a look at the default implementation of these methods to better +understand the flexibility of the framework. At the beginning of this +tutorial, you opened the ``hello/config/routing.yml`` file. The path is +configured in the ``registerRoutes()``:: + + public function registerRoutes() + { + $loader = new RoutingLoader($this->getBundleDirs()); + + return $loader->load(__DIR__.'/config/routing.yml'); + } + +This is also where you can switch from using YAML configuration files to XML +ones or plain PHP code if that fits you better. + +To make things work together, the kernel requires one file from the ``src/`` +directory:: + + // hello/HelloKernel.php + require_once __DIR__.'/../src/autoload.php'; + +The Source Directory +~~~~~~~~~~~~~~~~~~~~ + +The ``src/autoload.php`` file is responsible for autoloading all the files +stored in the ``src/`` directory:: + + // src/autoload.php + require_once __DIR__.'/vendor/symfony/src/Symfony/Foundation/UniversalClassLoader.php'; + + use Symfony\Foundation\UniversalClassLoader; + + $loader = new UniversalClassLoader(); + $loader->registerNamespaces(array( + 'Symfony' => __DIR__.'/vendor/symfony/src', + 'Application' => __DIR__, + 'Bundle' => __DIR__, + 'Doctrine\\Common' => __DIR__.'/vendor/doctrine/lib/vendor/doctrine-common/lib', + 'Doctrine\\DBAL\\Migrations' => __DIR__.'/vendor/doctrine-migrations/lib', + 'Doctrine\\DBAL' => __DIR__.'/vendor/doctrine/lib/vendor/doctrine-dbal/lib', + 'Doctrine' => __DIR__.'/vendor/doctrine/lib', + 'Zend' => __DIR__.'/vendor/zend/library', + )); + $loader->registerPrefixes(array( + 'Swift_' => __DIR__.'/vendor/swiftmailer/lib/classes', + 'Twig_' => __DIR__.'/vendor/twig/lib', + )); + $loader->register(); + +The ``UniversalClassLoader`` from Symfony is used to autoload files that +respect either the technical interoperability `standards`_ for PHP 5.3 +namespaces or the PEAR naming `convention`_ for classes. As you can see +here, all dependencies are stored under the ``vendor/`` directory, but this is +just a convention. You can store them wherever you want, globally on your +server or locally in your projects. + +.. index:: + single: Bundles + +The Bundle System +----------------- + +This section starts to scratch the surface of one of the greatest and more +powerful features of Symfony, its bundle system. + +A bundle is kind of like a plugin in other software. But why is it called +bundle and not plugin then? Because everything is a bundle in Symfony, from +the core framework features to the code you write for your application. +Bundles are first-class citizens in Symfony. This gives you the flexibility to +use pre-built features packaged in third-party bundles or to distribute your +own bundles. It makes it so easy to pick and choose which features to enable +in your application and optimize them the way you want. + +An application is made up of bundles as defined in the ``registerBundles()`` +method of the ``HelloKernel`` class:: + + // hello/HelloKernel.php + + use Symfony\Foundation\Bundle\KernelBundle; + use Symfony\Framework\FoundationBundle\FoundationBundle; + use Symfony\Framework\DoctrineBundle\DoctrineBundle; + use Symfony\Framework\SwiftmailerBundle\SwiftmailerBundle; + use Symfony\Framework\ZendBundle\ZendBundle; + use Application\HelloBundle\HelloBundle; + + public function registerBundles() + { + return array( + new KernelBundle(), + new FoundationBundle(), + new DoctrineBundle(), + new SwiftmailerBundle(), + new ZendBundle(), + new HelloBundle(), + ); + } + +Along side the ``HelloBundle`` we have already talked about, notice that the +kernel also enables ``KernelBundle``, ``FoundationBundle``, ``DoctrineBundle``, +``SwiftmailerBundle``, and ``ZendBundle``. They are all part of the core +framework. + +Each bundle can be customized via configuration files written in YAML or XML. +Have a look at the default configuration: + +.. code-block:: yaml + + # hello/config/config.yml + kernel.config: ~ + web.config: ~ + web.templating: ~ + +Each entry like ``kernel.config`` defines the configuration of a bundle. Some +bundles can have several entries if they provide many features like +``FoundationBundle``, which has two entries: ``web.config`` and ``web.templating``. + +Each environment can override the default configuration by providing a +specific configuration file: + +.. code-block:: yaml + + # hello/config/config_dev.yml + imports: + - { resource: config.yml } + + web.config: + toolbar: true + + zend.logger: + priority: info + path: %kernel.root_dir%/logs/%kernel.environment%.log + +As we have seen in the previous part, an application is made of bundles as +defined in the ``registerBundles()`` method but how does Symfony know where to +look for bundles? Symfony is quite flexible in this regard. The +``registerBundleDirs()`` method must return an associative array that maps +namespaces to any valid directory (local or global ones):: + + public function registerBundleDirs() + { + return array( + 'Application' => __DIR__.'/../src/Application', + 'Bundle' => __DIR__.'/../src/Bundle', + 'Symfony\\Framework' => __DIR__.'/../src/vendor/symfony/src/Symfony/Framework', + ); + } + +So, when you reference the ``HelloBundle`` in a controller name or in a template +name, Symfony will look for it under the given directories. + +Do you understand now why Symfony is so flexible? Share your bundles between +applications, store them locally or globally, your choice. + +.. index:: + single: Vendors + +Vendors +------- + +Odds are your application will depend on third-party libraries. Those should +be stored in the ``src/vendor/`` directory. It already contains the Symfony +libraries, the SwiftMailer library, the Doctrine ORM, the Propel ORM, the Twig +templating system, and a selection of the Zend Framework classes. + +.. index:: + single: Cache + single: Logs + +Cache and Logs +-------------- + +Symfony is probably one of the fastest full-stack frameworks around. But how +can it be so fast if it parses and interprets tens of YAML and XML files for +each request? This is partly due to its cache system. The application +configuration is only parsed for the very first request and then compiled down +to plain PHP code stored in the ``cache/`` application directory. In the +development environment, Symfony is smart enough to flush the cache when you +change a file. But in the production one, it is your responsibility to clear +the cache when you update your code or change its configuration. + +When developing a web application, things can go wrong in many ways. The log +files in the ``logs/`` application directory tell you everything about the +requests and helps you fix the problem in no time. + +.. index:: + single: CLI + single: Command Line + +The Command Line Interface +-------------------------- + +Each application comes with a command line interface tool (``console``) that +helps you maintain your application. It provides commands that boost your +productivity by automating tedious and repetitive tasks. + +Run it without any arguments to learn more about its capabilities: + +.. code-block:: bash + + $ php hello/console + +The ``--help`` option helps you discover the usage of a command: + +.. code-block:: bash + + $ php hello/console router:debug --help + +Final Thoughts +-------------- + +Call me crazy, but after reading this part, you should be comfortable with +moving things around and making Symfony work for you. Everything is done in +Symfony to stand out of your way. So, feel free to rename and move directories +around as you see fit. + +And that's all for the quick tour. From testing to sending emails, you still +need to learn of lot to become a Symfony master. Ready to dig into these +topics now? Look no further, go to the official `guides`_ page and pick any +topic you want. + +.. _standards: http://groups.google.com/group/php-standards/web/psr-0-final-proposal +.. _convention: http://pear.php.net/ +.. _guides: http://www.symfony-reloaded.org/learn diff --git a/pt_BR/quick_tour/the_big_picture.rst b/pt_BR/quick_tour/the_big_picture.rst new file mode 100644 index 00000000000..5e5a926dc0c --- /dev/null +++ b/pt_BR/quick_tour/the_big_picture.rst @@ -0,0 +1,243 @@ +The Big Picture +=============== + +So, you want to try out Symfony but only have 10 minutes or so? This first +part of this tutorial has been written for you. It explains how to get started +fast with Symfony by showing you the structure of a simple ready-made project. + +If you have ever used a web framework before, you should feel right at home +with Symfony 2.0. + +.. index:: + pair: Sandbox; Download + +Download and Install +-------------------- + +First, check that you have at least PHP 5.3.2 installed and correctly +configured to work with a web server like Apache. + +Ready? Let's start by downloading Symfony. To get started even faster, we are +going to use the "Symfony sandbox". It is a Symfony project where all the +required libraries and some simple controllers are already included and where +the basic configuration is already done. The great advantage of the sandbox +over other types of installation is that you can start experimenting with +Symfony immediately. + +Download the `sandbox`_, and unpack it in your root web directory. You +should now have a ``sandbox/`` directory:: + + www/ <- your web root directory + sandbox/ <- the unpacked archive + hello/ + cache/ + config/ + logs/ + src/ + Application/ + HelloBundle/ + Controller/ + Resources/ + vendor/ + symfony/ + web/ + +.. index:: + single: Installation; Check + +Check the Configuration +----------------------- + +To avoid some headaches further down the line, check that your configuration +can run a Symfony project smoothly by requesting the following URL: + + http://localhost/sandbox/web/check.php + +Read the script output carefully and fix any problem that it finds. + +Now, request your first "real" Symfony webpage: + + http://localhost/sandbox/web/index_dev.php/ + +Symfony should congratulate you for your hard work so far! + +Your first Application +---------------------- + +The sandbox comes with a simple Hello World "application" and that's the +application we will use to learn more about Symfony. Go to the following URL +to be greeted by Symfony (replace Fabien with your first name): + + http://localhost/sandbox/web/index_dev.php/hello/Fabien + +What's going on here? Let's dissect the URL: + +.. index:: Font Controller + +* ``index_dev.php``: This is a "front controller". It is the unique entry + point of the hello application and it responds to all user requests; + +* ``/hello/Fabien``: This is the "virtual" path to the resource the user wants + to access. + +Your responsibility as a developer is to write the code that maps the user +request (``/hello/Fabien``) to the resource associated with it (``Hello +Fabien!``). + +.. index:: + single: Routing + pair: Configuration; Routing + +Routing +~~~~~~~ + +But how does Symfony route the request to your code? Simply by reading the +routing configuration file: + +.. code-block:: yaml + + # hello/config/routing.yml + homepage: + pattern: / + defaults: { _controller: FoundationBundle:Default:index } + + hello: + resource: HelloBundle/Resources/config/routing.yml + +The file is written in `YAML`, a simple format that makes the description of +configuration settings very easy. All the configuration files in Symfony can +be written in XML, YAML, or even in plain PHP code. This tutorial uses the +YAML format as it is more concise and easier to read for beginners. Of course, +"enterprise people" would probably have used XML everywhere. + +The first three lines of the routing configuration file define which code to +call when the user requests the "``/``" resource. More interesting is the last +line, which imports another routing configuration file that reads as follows: + +.. code-block:: yaml + + # src/Application/HelloBundle/Resources/config/routing.yml + hello: + pattern: /hello/:name + defaults: { _controller: HelloBundle:Hello:index } + +Here we go! As you can see, the "``/hello/:name``" resource pattern (a string +beginning with a colon like ``:name`` is a placeholder) is mapped to a +controller, referenced by the ``_controller`` value. + +.. index:: + single: Controller + single: MVC; Controller + +Controllers +~~~~~~~~~~~ + +The controller is responsible for returning a representation of the resource +(most of the time an HTML one) and it is defined as a PHP class: + +.. code-block:: php + :linenos: + + // src/Application/HelloBundle/Controller/HelloController.php + + namespace Application\HelloBundle\Controller; + + use Symfony\Framework\FoundationBundle\Controller; + + class HelloController extends Controller + { + public function indexAction($name) + { + return $this->render('HelloBundle:Hello:index', array('name' => $name)); + } + } + +The code is pretty straightforward but let's explain this code line by line: + +* *line 3*: Symfony takes advantage of new PHP 5.3 features and as such, all + controllers are properly namespaced (the namespace is the first part of the + ``_controler`` routing value: ``HelloBundle``). + +* *line 7*: The controller name is the concatenation of the second part of the + ``_controller`` routing value (``Hello``) and ``Controller``. It extends the + built-in ``Controller`` class, which provides useful shortcuts (as we will + see later in this tutorial). + +* *line 9*: Each controller is made of several actions. As per the + configuration, the hello page is handled by the ``index`` action (the third + part of the ``_controller`` routing value). This method receives the + resource placeholder values as arguments (``$name`` in our case). + +* *line 11*: The ``render()`` method loads and renders a template + (``HelloBundle:Hello:index``) with the variables passed as a second + argument. + +But what is a bundle? All the code you write in a Symfony project is organized +in bundles. In Symfony speak, a bundle is a structured set of files (PHP +files, stylesheets, JavaScripts, images, ...) that implements a single feature +(a blog, a forum, ...) and which can be easily shared with other developers. +In our example, we only have one bundle, ``HelloBundle``. + +Templates +~~~~~~~~~ + +So, the controller renders the ``HelloBundle:Hello:index`` template. But what's +in a template name? ``HelloBundle`` is the bundle name, ``Hello`` is the +controller, and ``index`` the template file name. The template itself is made +of HTML and simple PHP expressions: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/Hello/index.php + extend('HelloBundle::layout') ?> + + Hello ! + +Congratulations! You have looked at your first Symfony piece of code. That was +not so hard, was it? Symfony makes it really easy to implement web sites +better and faster. + +.. index:: + single: Environment + single: Configuration; Environment + +Environments +------------ + +Now that you have a better understanding on how Symfony works, have a closer +look at the bottom of the page; you will notice a small bar with the Symfony +and PHP logos. It is called the "Web Debug Toolbar" and it is the developer's +best friend. Of course, such a tool must not be displayed when you deploy your +application to your production servers. That's why you will find another front +controller in the ``web/`` directory (``index.php``), optimized for the production +environment: + + http://localhost/sandbox/web/index.php/hello/Fabien + +And if you have ``mod_rewrite`` installed, you can even omit the ``index.php`` +part of the URL: + + http://localhost/sandbox/web/hello/Fabien + +Last but not least, on the production servers, you should point your web root +directory to the ``web/`` directory to secure your installation and have an even +better looking URL: + + http://localhost/hello/Fabien + +To make the production environment as fast as possible, Symfony maintains a +cache under the ``hello/cache/`` directory. When you make changes, you need to +manually remove the cached files. That's why you should always use the +development front controller (``index_dev.php``) when working on a project. + +Final Thoughts +-------------- + +The 10 minutes are over. By now, you should be able to create your own simple +routes, controllers, and templates. As an exercise, try to build something +more useful than the Hello application! But if you are eager to learn more +about Symfony, you can read the next part of this tutorial right away, where +we dive more into the templating system. + +.. _sandbox: http://symfony-reloaded.org/code#sandbox +.. _YAML: http://www.yaml.org/ diff --git a/pt_BR/quick_tour/the_controller.rst b/pt_BR/quick_tour/the_controller.rst new file mode 100644 index 00000000000..80a3d01ba89 --- /dev/null +++ b/pt_BR/quick_tour/the_controller.rst @@ -0,0 +1,222 @@ +.. index:: + single: Controller + single: MVC; Controller + +The Controller +============== + +Still with us after the first two parts? You are already becoming a Symfony2 +addict! Without further ado, let's discover what controllers can do for you. + +.. index:: + single: Formats + single: Controller; Formats + single: Routing; Formats + single: View; Formats + +Formats +------- + +Nowadays, a web application should be able to deliver more than just HTML +pages. From XML for RSS feeds or Web Services, to JSON for Ajax requests, +there are plenty of different formats to choose from. Supporting those formats +in Symfony is straightforward. Edit ``routing.yml`` and add a ``_format`` with a +value of ``xml``: + +.. code-block:: yaml + + # src/Application/HelloBundle/Resources/config/routing.yml + hello: + pattern: /hello/:name + defaults: { _controller: HelloBundle:Hello:index, _format: xml } + +Then, add an ``index.xml.php`` template along side ``index.php``: + +.. code-block:: xml+php + + # src/Application/HelloBundle/Resources/views/Hello/index.xml.php + + + + +That's all there is to it. No need to change the controller. For standard +formats, Symfony will also automatically choose the best ``Content-Type`` header +for the response. If you want to support different formats for a single +action, use the ``:_format`` placeholder in the pattern instead: + +.. code-block:: yaml + + # src/Application/HelloBundle/Resources/config/routing.yml + hello: + pattern: /hello/:name.:_format + defaults: { _controller: HelloBundle:Hello:index, _format: html } + requirements: { _format: (html|xml|json) } + +The controller will now be called for URLs like ``/hello/Fabien.xml`` or +``/hello/Fabien.json``. As the default value for ``_format`` is ``html``, the +``/hello/Fabien`` and ``/hello/Fabien.html`` will both match for the ``html`` +format. + +The ``requirements`` entry defines regular expressions that placeholders must +match. In this example, if you try to request the ``/hello/Fabien.js`` resource, +you will get a 404 HTTP error, as it does not match the ``_format`` requirement. + +.. index:: + single: Response + +The Response Object +------------------- + +Now, let's get back to the ``Hello`` controller:: + + public function indexAction($name) + { + return $this->render('HelloBundle:Hello:index', array('name' => $name)); + } + +The ``render()`` method renders a template and returns a ``Response`` object. The +response can be tweaked before it is sent to the browser, for instance to +change the default ``Content-Type``:: + + public function indexAction($name) + { + $response = $this->render('HelloBundle:Hello:index', array('name' => $name)); + $response->setHeader('Content-Type', 'text/plain'); + + return $response; + } + +For simple templates, you can even create a ``Response`` object by hand and save +some milliseconds:: + + public function indexAction($name) + { + return $this->createResponse('Hello '.$name); + } + +This is really useful when a controller needs to send back a JSON response for +an Ajax request. + +.. index:: + single: Exceptions + +Error Management +---------------- + +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:: + + use Symfony\Components\RequestHandler\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. Similarly, ``ForbiddenHttpException`` returns a 403 error and +``UnauthorizedHttpException`` a 401 one. For any other HTTP error code, you can +use the base ``HttpException`` and pass the HTTP error as the exception code:: + + throw new HttpException('Unauthorized access.', 401); + +.. index:: + single: Controller; Redirect + single: Controller; Forward + +Redirecting and Forwarding +-------------------------- + +If you want to redirect the user to another page, use the ``redirect()`` method:: + + $this->redirect($this->generateUrl('hello', array('name' => 'Lucas'))); + +The ``generateUrl()`` is the same method as the ``generate()`` method we used on +the ``router`` helper before. It takes the route name and an array of parameters +as arguments and returns the associated friendly URL. + +You can also easily forward the action to another one with the ``forward()`` +method. As for the ``$view->actions`` helper, it makes an internal sub-request, +but it returns the ``Response`` object to allow for further modification if the +need arises:: + + $response = $this->forward('HelloBundle:Hello:fancy', array('name' => $name, 'color' => 'green')); + + // do something with the response or return it directly + +.. index:: + single: Request + +The Request Object +------------------ + +Besides the values of the routing placeholders, the controller also has access +to the ``Request`` object:: + + $request = $this->getRequest(); + + $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 + +In a template, you can also access the request object via the ``request`` +helper: + +.. code-block:: html+php + + request->getParameter('page') ?> + +The User +-------- + +Even if the HTTP protocol is stateless, Symfony provides a nice user object +that represents the client (be it a real person using a browser, a bot, or a +web service). Between two requests, Symfony stores the attributes in a cookie +by using the native PHP sessions. + +This feature is provided by ``FoundationBundle`` and it can be enabled by adding the +following line to ``config.yml``: + +.. code-block:: yaml + + # hello/config/config.yml + web.user: ~ + +Storing and retrieving information from the user can be easily achieved from +any controller:: + + // store an attribute for reuse during a later user request + $this->getUser()->setAttribute('foo', 'bar'); + + // in another controller for another request + $foo = $this->getUser()->getAttribute('foo'); + + // get/set the user culture + $this->getUser()->setCulture('fr'); + +You can also store small messages that will only be available for the very +next request:: + + // store a message for the very next request + $this->getUser()->setFlash('notice', 'Congratulations, your action succeeded!'); + + // get the message back in the next request + $notice = $this->getUser()->getFlash('notice'); + +Final Thoughts +-------------- + +That's all there is to it, and I'm not even sure we have spent the allocated +10 minutes. In the previous part, we saw how to extend the templating system +with helpers. But everything can extended or replaced in Symfony2 with +bundles. That's the topic of the next part of this tutorial. diff --git a/pt_BR/quick_tour/the_view.rst b/pt_BR/quick_tour/the_view.rst new file mode 100644 index 00000000000..a248f963de0 --- /dev/null +++ b/pt_BR/quick_tour/the_view.rst @@ -0,0 +1,267 @@ +.. index:: + single: View + single: MVC; View + +The View +======== + +After reading the first part of this tutorial, you have decided that Symfony +was worth another 10 minutes. Good for you. In this second part, you will +learn more about the Symfony template system. As seen before, Symfony uses PHP +as its default template engine but adds some nice features on top of if to +make it more powerful. + +.. tip:: + Instead of PHP, you can also use :doc:`Twig ` as the default + template engine with Symfony2. If makes your templates more concise and + more web designer friendly. + +.. index:: + single: Templating; Layout + single: Layout + +Decorating Templates +-------------------- + +More often than not, templates in a project share common elements, like the +well-know header and footer. In Symfony, we like to think about this problem +differently: a template can be decorated by another one. + +The ``index`` template is decorated by ``layout.php``, thanks to the +``extend()`` call: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/Hello/index.php + extend('HelloBundle::layout') ?> + + Hello ! + +The ``HelloBundle::layout`` notation sounds familiar, doesn't it? It is the same +notation as for referencing a template. The ``::`` part simply means that the +controller element is empty, so the corresponding file is directly stored in +``views/``. + +Now, let's have a look at the ``layout.php`` file: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/layout.php + + + + + + + slots->output('_content') ?> + + + +The ``$view->slots->output('_content')`` expression is replaced by the content +of the child template, ``index.php`` (more on slots in the next section). + +As you can see, Symfony provides methods on a mysterious ``$view`` object. In a +template, the ``$view`` variable is always available and refers to a special +object that provides a bunch of methods and properties that make the template +engine tick. + +Symfony also supports multiple decoration levels: a layout can itself be +decorated by another one. This technique is really useful for large projects +and is made even more powerful when used in combination with slots. + +.. index:: + single: Templating; Slot + single: Slot + +Slots +----- + +A slot is a snippet of code, defined in a template, and reusable in any layout +decorating the template. In the index template, define a ``title`` slot: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/Hello/index.php + extend('HelloBundle::layout') ?> + + slots->set('title', 'Hello World app') ?> + + Hello ! + +And change the layout to output the title in the header: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/layout.php + + + Codestin Search App + + + + slots->output('_content') ?> + + + +The ``output()`` method inserts the content of a slot and optionally takes a +default value if the slot is not defined. And ``_content`` is just a special +slot that contains the rendered child template. + +For large slots, there is also an extended syntax: + +.. code-block:: html+php + + slots->start('title') ?> + Some large amount of HTML + slots->stop() ?> + +.. index:: + single: Templating; Include + +Include other Templates +----------------------- + +The best way to share a snippet of code between several distinct templates is +to define a template that can then be included into another one. + +Create a ``hello.php`` template: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/Hello/hello.php + Hello ! + +And change the ``index.php`` template to include it: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/Hello/index.php + extend('HelloBundle::layout') ?> + + render('HelloBundle:Hello:hello', array('name' => $name)) ?> + +The ``render()`` method evaluates and returns the content of another template +(this is the exact same method as the one used in the controller). + +.. index:: + single: Templating; Embedding Pages + +Embed other Actions +------------------- + +And what if you want to embed the result of another action in a template? +That's very useful when working with Ajax, or when the embedded template needs +some variable not available in the main template. + +If you create a ``fancy`` action, and want to include it into the ``index`` +template, simply use the following code: + +.. code-block:: html+php + + # src/Application/HelloBundle/Resources/views/Hello/index.php + actions->output('HelloBundle:Hello:fancy', array('name' => $name, 'color' => 'green')) ?> + +Here, the ``HelloBundle:Hello:fancy`` string refers to the ``fancy`` action of the +``Hello`` controller:: + + // src/Application/HelloBundle/Controller/HelloController.php + + class HelloController extends Controller + { + public function fancyAction($name, $color) + { + // create some object, based on the $color variable + $object = ...; + + return $this->render('HelloBundle:Hello:fancy', array('name' => $name, 'object' => $object)); + } + + // ... + } + +But where is the ``$view->actions`` property defined? Like ``$view->slots``, it's +called a template helper, and the next section tells you more about those. + +.. index:: + single: Templating; Helpers + +Template Helpers +---------------- + +The Symfony templating system can be easily extended via helpers. Helpers are +PHP objects that provide features useful in a template context. ``actions`` and +``slots`` are two of the built-in Symfony helpers. + +Links between Pages +~~~~~~~~~~~~~~~~~~~ + +Speaking of web applications, creating links between different pages is a +must. Instead of hardcoding URLs in templates, the ``router`` helper knows how +to generate URLs based on the routing configuration. That way, all your URLs +can be easily updated by changing the configuration: + +.. code-block:: html+php + + + Greet Thomas! + + +The ``generate()`` method takes the route name and an array of values as +arguments. The route name is the main key under which routes are referenced +and the values are the route pattern placeholder values: + +.. code-block:: yaml + + # src/Application/HelloBundle/Resources/config/routing.yml + hello: # The route name + pattern: /hello/:name + defaults: { _bundle: HelloBundle, _controller: Hello, _action: index } + +Using Assets: images, JavaScripts, and stylesheets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +What would the Internet be without images, JavaScripts, and stylesheets? +Symfony provides three helpers to deal with them easily: ``assets``, +``javascripts``, and ``stylesheets``: + +.. code-block:: html+php + + + + + +The ``assets`` helper's main purpose is to make your application more portable. +Thanks to this helper, you can move the application root directory anywhere under your +web root directory without changing anything in your templates' code. + +Similarly, you can manage your stylesheets and JavaScripts with the +``stylesheets`` and ``JavaScripts`` helpers: + +.. code-block:: html+php + + javascripts->add('js/product.js') ?> + stylesheets->add('css/product.css') ?> + +The ``add()`` method defines dependencies. To actually output these assets, you +need to also add the following code in your main layout: + +.. code-block:: html+php + + javascripts ?> + stylesheets ?> + +Final Thoughts +-------------- + +The Symfony templating system is simple yet powerful. Thanks to layouts, +slots, templating and action inclusions, it is very easy to organize your +templates in a logical and extensible way. + +You have only been working with Symfony for about 20 minutes, and you can +already do pretty amazing stuff with it. That's the power of Symfony. Learning +the basics is easy, and you will soon learn that this simplicity is hidden +under a very flexible architecture. + +But I get ahead of myself. First, you need to learn more about the controller +and that's exactly the topic of the next part of this tutorial. Ready for +another 10 minutes with Symfony?