From 2b4fc9531985d12e03c53d5c72430c1a5ed6857c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 25 Jun 2010 16:10:47 +0200 Subject: [PATCH 1/9] updated for PR3 --- guides/en/Testing/Client.markdown | 1 + guides/en/Testing/Recipes.markdown | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/guides/en/Testing/Client.markdown b/guides/en/Testing/Client.markdown index fa56d6cccb8..be8f7f9b9a8 100644 --- a/guides/en/Testing/Client.markdown +++ b/guides/en/Testing/Client.markdown @@ -98,6 +98,7 @@ 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`: diff --git a/guides/en/Testing/Recipes.markdown b/guides/en/Testing/Recipes.markdown index 58b8e3296fe..6780c181c51 100644 --- a/guides/en/Testing/Recipes.markdown +++ b/guides/en/Testing/Recipes.markdown @@ -93,8 +93,7 @@ But before writing assertions, always check that the profiler is indeed available (it is enabled by default in the `test` environment): [php] - $profiler = $this->getProfiler($client->getResponse()); - if ($profiler) { + if ($profiler = $client->getProfiler()) { // check the number of requests $this->assertTrue($profiler['db']->getQueryCount() < 10); From 5bb596a8fc83fbd3baad7ab5b2c68fd18b33089f Mon Sep 17 00:00:00 2001 From: "Jonathan H. Wage" Date: Fri, 23 Jul 2010 12:55:57 -0500 Subject: [PATCH 2/9] [DoctrineMongoDBBundle] Updating documentation for recent changes. --- guides/en/Doctrine/Configuration.markdown | 25 +-- guides/en/Doctrine/MongoDB.markdown | 240 ++++++++++++++++------ 2 files changed, 184 insertions(+), 81 deletions(-) diff --git a/guides/en/Doctrine/Configuration.markdown b/guides/en/Doctrine/Configuration.markdown index 388af3bb2cb..1f33ed2d713 100644 --- a/guides/en/Doctrine/Configuration.markdown +++ b/guides/en/Doctrine/Configuration.markdown @@ -4,8 +4,6 @@ Doctrine Configuration DBAL Configuration ------------------ - - [yml] # config/config.yml doctrine.dbal: @@ -61,14 +59,14 @@ but you must pass it an argument with the name of the connection you want to get ORM Configuration ----------------- -doctrine.orm: - default_entity_manager: default - cache_driver: apc # array, apc, memcache, xcache - entity_managers: - default: - connection: default - customer: - connection: customer + 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 @@ -107,11 +105,6 @@ you just need to run the following command: Now your database will be updated and the new column added to the database table. -MongoDB Configuration ---------------------- - - - Console Commands ---------------- @@ -151,4 +144,4 @@ or options: :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. - ... + ... \ No newline at end of file diff --git a/guides/en/Doctrine/MongoDB.markdown b/guides/en/Doctrine/MongoDB.markdown index fe3c102d605..9f1cfde0543 100644 --- a/guides/en/Doctrine/MongoDB.markdown +++ b/guides/en/Doctrine/MongoDB.markdown @@ -2,83 +2,202 @@ MongoDB ======= The [MongoDB][1] Object Document Mapper is much like the Doctrine2 ORM in the -way it works and architecture. The plain PHP5 objects are persisted -transparently. +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][2]. -To get started working with Doctrine and MongoDB you just need to configure it: +## Configuration + +To get started working with Doctrine and the MongoDB Object Document Mapper you just need +to enable it: + + # 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: + + # 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: - [yml] # config/config.yml doctrine_odm.mongodb: - default_document_manager: default - cache_driver: array - document_managers: - default: - connection: mongodb - connections: - mongodb: - server: localhost - default_database: jwage - -Working with documents and MongoDB is very similar to how you work with -entities in the ORM. You are only dealing with plain PHP objects that are -mapped to MongoDB: - - [php] - namespace Application\HelloBundle\Documents; - - /** - * @Document - */ + 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: + + 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: + + + + + + + + Doctrine\Common\Cache\MemcacheCache + localhost + 11211 + Memcache + + + true + + + + +Multiple Connections: + + + + + + + + + + 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 { - /** - * @Id - */ protected $id; - - /** - * @String - */ protected $name; - /** - * Get id - * - * @return integer $id - */ public function getId() { return $this->id; } - /** - * Set name - * - * @param string $name - */ public function setName($name) { $this->name = $name; } - /** - * Get name - * - * @return string $name - */ public function getName() { return $this->name; } } -Now that you have a document created and mapped properly you can begin -managing its persistent state with Doctrine: +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 { @@ -93,29 +212,20 @@ managing its persistent state with Doctrine: // ... } + } - public function editAction($id) - { - $dm = $this->container->getService('doctrine.odm.mongodb.document_manager'); - $user = $dm->createQuery('HelloBundle:User') - ->where('id', $id) - ->getSingleResult(); - $user->setBody('new body'); - $dm->flush(); - } +Later you can retrieve the persisted document by its id: - public function deleteAction($id) + class UserController extends Controller + { + public function editAction($id) { $dm = $this->container->getService('doctrine.odm.mongodb.document_manager'); - $user = $dm->createQuery('HelloBundle:User') - ->where('id', $id) - ->getSingleResult(); - $dm->remove($user); - $dm->flush(); + $user = $dm->find('HelloBundle:User', $id); - // ... + // ... } } [1]: http://www.mongodb.org/ -[2]: http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/en +[2]: http://www.doctrine-project.org/projects/mongodb_odm/1.0/docs/en \ No newline at end of file From bfeb5d9f6ceec9d429e663e06cb0b9680f4b0522 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 28 Jul 2010 08:49:49 +0200 Subject: [PATCH 3/9] removed old file --- guides/en/Caching.markdown | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 guides/en/Caching.markdown diff --git a/guides/en/Caching.markdown b/guides/en/Caching.markdown deleted file mode 100644 index 7ea2552f3dc..00000000000 --- a/guides/en/Caching.markdown +++ /dev/null @@ -1,6 +0,0 @@ -Caching -======= - -"There are only two hard things in Computer Science: cache invalidation and -naming things." --Phil Karlton - From ef47cfd1fcc4f535c793dee0d53a579a7f435375 Mon Sep 17 00:00:00 2001 From: Adell Date: Wed, 4 Aug 2010 21:49:03 -0300 Subject: [PATCH 4/9] =?UTF-8?q?Adicionado=20a=20tradu=C3=A7=C3=A3o=20para?= =?UTF-8?q?=20o=20quick=20tour?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quick_tour/pt_BR/index.rst | 15 ++ quick_tour/pt_BR/the_architecture.rst | 293 ++++++++++++++++++++++++++ quick_tour/pt_BR/the_big_picture.rst | 243 +++++++++++++++++++++ quick_tour/pt_BR/the_controller.rst | 222 +++++++++++++++++++ quick_tour/pt_BR/the_view.rst | 267 +++++++++++++++++++++++ 5 files changed, 1040 insertions(+) create mode 100644 quick_tour/pt_BR/index.rst create mode 100644 quick_tour/pt_BR/the_architecture.rst create mode 100644 quick_tour/pt_BR/the_big_picture.rst create mode 100644 quick_tour/pt_BR/the_controller.rst create mode 100644 quick_tour/pt_BR/the_view.rst diff --git a/quick_tour/pt_BR/index.rst b/quick_tour/pt_BR/index.rst new file mode 100644 index 00000000000..d1592deffc1 --- /dev/null +++ b/quick_tour/pt_BR/index.rst @@ -0,0 +1,15 @@ +Tour Rápido +=========== + +Comece rapidamente com o Tour rápido do Symfony2: + +.. toctree:: + :maxdepth: 2 + :glob: + :numbered: + + the_big_picture + the_view + the_controller + the_architecture + diff --git a/quick_tour/pt_BR/the_architecture.rst b/quick_tour/pt_BR/the_architecture.rst new file mode 100644 index 00000000000..ccce32c9b8f --- /dev/null +++ b/quick_tour/pt_BR/the_architecture.rst @@ -0,0 +1,293 @@ +A Arquitetura +============= + +Você é meu heroi! Quem teria pensado que você ainda estaria aqui após as +três primeiras partes? Seu esforço será bem recompensado em breve. As três +primeiras partes não olharam profundamente a arquitetura do framework. +Como isto faz o Symfony um framework distante da multidão, vamos mergulhar agora. + +.. index:: + single: Directory Structure + +A estrutura de Diretorios +------------------------- + +A estrutura de diretorios de uma aplicação do Symfony é bastante flexisivel +mas a estrutura de uma sandbox reflete uma tipica e recomendada estrutura +de uma aplicação do Symfony: + +* ``hello/``: Este diretorio, nomeado após sua aplicação, contém os + arquivos de configuração; + +* ``src/``: Todo o código PHP está neste diretorio; + +* ``web/``: Este deve ser o diretorio raiz da web. + +O Diretorio Web +~~~~~~~~~~~~~~~ + +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/quick_tour/pt_BR/the_big_picture.rst b/quick_tour/pt_BR/the_big_picture.rst new file mode 100644 index 00000000000..5e5a926dc0c --- /dev/null +++ b/quick_tour/pt_BR/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/quick_tour/pt_BR/the_controller.rst b/quick_tour/pt_BR/the_controller.rst new file mode 100644 index 00000000000..80a3d01ba89 --- /dev/null +++ b/quick_tour/pt_BR/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/quick_tour/pt_BR/the_view.rst b/quick_tour/pt_BR/the_view.rst new file mode 100644 index 00000000000..a248f963de0 --- /dev/null +++ b/quick_tour/pt_BR/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 + + + <?php $view->slots->output('title', 'Default Title') ?> + + + + 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? From 69d22793695232ef8e6965b5ab878ecc75d8e2ae Mon Sep 17 00:00:00 2001 From: Adell Date: Wed, 4 Aug 2010 22:21:37 -0300 Subject: [PATCH 5/9] Traduzindo o the_architecture.rst --- quick_tour/pt_BR/the_architecture.rst | 36 +++++++++++++-------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/quick_tour/pt_BR/the_architecture.rst b/quick_tour/pt_BR/the_architecture.rst index ccce32c9b8f..441310f26ac 100644 --- a/quick_tour/pt_BR/the_architecture.rst +++ b/quick_tour/pt_BR/the_architecture.rst @@ -26,9 +26,8 @@ de uma aplicação do Symfony: O Diretorio Web ~~~~~~~~~~~~~~~ -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: +O diretorio web é a casa de todos os arquivos publicos e estaticos como imagens, +folha de estilo, e arquivos JavaScript. É onde os front controllers vivem: .. code-block:: html+php @@ -40,33 +39,32 @@ live: $kernel = new HelloKernel('prod', false); $kernel->handle()->send(); -Like any front controller, ``index.php`` uses a Kernel Class, ``HelloKernel``, to -bootstrap the application. +Como qualquer front controllers, ``index.php`` usa a ``HelloKernel``, que é uma classe Kernel +para inicializar a aplicação. .. index:: single: Kernel -The Application Directory -~~~~~~~~~~~~~~~~~~~~~~~~~ +O Diretorio Aplicação +~~~~~~~~~~~~~~~~~~~~~ -The ``HelloKernel`` class is the main entry point of the application -configuration and as such, it is stored in the ``hello/`` directory. +A classe ``HelloKernel`` é o ponto de entrada principal de configuraçãp +da aplicação e como tal, é armazenada no diretorio ``hello/``. -This class must implement five methods: +Esta classe deve implementar cinco metodos: -* ``registerRootDir()``: Returns the configuration root directory; +* ``registerRootDir()``: Retorna o diretorio raiz de configurações; -* ``registerBundles()``: Returns an array of all bundles needed to run the - application (notice the reference to - ``Application\HelloBundle\HelloBundle``); +* ``registerBundles()``: Retorna um array de todos os pacotes necessários para executar o + aplicação (observe a referencia a ``Application\HelloBundle\HelloBundle``); -* ``registerBundleDirs()``: Returns an array associating namespaces and their - home directories; +* ``registerBundleDirs()``: Retorna uma matriz que associa namespaces e seus + diretórios; -* ``registerContainerConfiguration()``: Returns the main configuration object - (more on this later); +* ``registerContainerConfiguration()``: Retorna o objeto principal de configuração + (Mais sobre isso depois); -* ``registerRoutes()``: Returns the routing configuration. +* ``registerRoutes()``: Retorna a configuração de roteamento. Have a look at the default implementation of these methods to better understand the flexibility of the framework. At the beginning of this From 686213f19d093238bf546623666ed36b62bd42fb Mon Sep 17 00:00:00 2001 From: skipp Date: Thu, 5 Aug 2010 03:40:16 -0700 Subject: [PATCH 6/9] first commit --- quick_tour/the_big_picture.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/quick_tour/the_big_picture.rst b/quick_tour/the_big_picture.rst index 5e5a926dc0c..c2512f938e5 100644 --- a/quick_tour/the_big_picture.rst +++ b/quick_tour/the_big_picture.rst @@ -1,9 +1,7 @@ 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. +Итак, вы хотите попробовать Symfony, но у вас только 10 минут или того меньше? Эта первая часть туториала была написана для Вас. 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. From 7d9e98e1b8b0daa76f3a4869468198d44733b049 Mon Sep 17 00:00:00 2001 From: Adell Date: Thu, 5 Aug 2010 19:25:17 -0300 Subject: [PATCH 7/9] =?UTF-8?q?Seguindo=20a=20tradu=C3=A7=C3=A3o=20do=20ar?= =?UTF-8?q?quivo=20the=5Farchitecture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- quick_tour/pt_BR/the_architecture.rst | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/quick_tour/pt_BR/the_architecture.rst b/quick_tour/pt_BR/the_architecture.rst index 441310f26ac..3872b147618 100644 --- a/quick_tour/pt_BR/the_architecture.rst +++ b/quick_tour/pt_BR/the_architecture.rst @@ -66,10 +66,9 @@ Esta classe deve implementar cinco metodos: * ``registerRoutes()``: Retorna a configuração de roteamento. -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()``:: +De uma olhada na implememtação padrão destes metodos para entender melhor a +flexibilidade do framework. No começo deste tutprial, você abriu o arquivo +``hello/config/routing.yml``. O caminho é configurado em ``registerRoutes()``:: public function registerRoutes() { @@ -78,20 +77,19 @@ configured in the ``registerRoutes()``:: 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. +Aqui é também onde você pode alternar entre usar arquivos de configuração YAML para XML +ou código PHP normal, no que você se encaixa melhor. -To make things work together, the kernel requires one file from the ``src/`` -directory:: +Para fazer as coisas trabalharem juntas, o kernel requer um arquivo do diretorio ``scr/``:: // hello/HelloKernel.php require_once __DIR__.'/../src/autoload.php'; -The Source Directory -~~~~~~~~~~~~~~~~~~~~ +O Diretorio Source +~~~~~~~~~~~~~~~~~~ -The ``src/autoload.php`` file is responsible for autoloading all the files -stored in the ``src/`` directory:: +O arquivo ``src/autoload.php`` é responsavél por autocarregar todos os arquivos internos +do diretorio ``scr/``:: // src/autoload.php require_once __DIR__.'/vendor/symfony/src/Symfony/Foundation/UniversalClassLoader.php'; From 6184344c79e96d6ac968da1a6c338912e4e1a18e Mon Sep 17 00:00:00 2001 From: Adell Date: Mon, 30 Aug 2010 17:27:43 -0300 Subject: [PATCH 8/9] =?UTF-8?q?adicionados=20novos=20arquivos=20e=20atuali?= =?UTF-8?q?zado=20a=20tradu=C3=A7=C3=A3o=20do=20arquivo=20the=5Farchitetur?= =?UTF-8?q?e.rst?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- guides/pt_BR/Twig.rst | 140 ++++++++ guides/pt_BR/bundles/best_practices.rst | 175 ++++++++++ guides/pt_BR/bundles/configuration.rst | 114 +++++++ guides/pt_BR/bundles/index.rst | 8 + guides/pt_BR/doctrine/MongoDB.rst | 253 ++++++++++++++ guides/pt_BR/doctrine/configuration.rst | 168 ++++++++++ guides/pt_BR/doctrine/index.rst | 9 + guides/pt_BR/doctrine/migrations.rst | 107 ++++++ guides/pt_BR/doctrine/overview.rst | 179 ++++++++++ guides/pt_BR/emails.rst | 37 ++ guides/pt_BR/event/index.rst | 8 + guides/pt_BR/event/overview.rst | 207 ++++++++++++ guides/pt_BR/event/recipes.rst | 175 ++++++++++ guides/pt_BR/forms.rst | 353 ++++++++++++++++++++ guides/pt_BR/index.rst | 19 ++ guides/pt_BR/map.rst.inc | 33 ++ guides/pt_BR/testing/client.rst | 101 ++++++ guides/pt_BR/testing/configuration.rst | 99 ++++++ guides/pt_BR/testing/crawler.rst | 198 +++++++++++ guides/pt_BR/testing/index.rst | 11 + guides/pt_BR/testing/overview.rst | 181 ++++++++++ guides/pt_BR/testing/recipes.rst | 163 +++++++++ guides/pt_BR/tools/YAML.rst | 375 +++++++++++++++++++++ guides/pt_BR/tools/autoloader.rst | 81 +++++ guides/pt_BR/tools/finder.rst | 197 +++++++++++ guides/pt_BR/tools/index.rst | 9 + guides/pt_BR/validator.rst | 427 ++++++++++++++++++++++++ quick_tour/pt_BR/the_architecture.rst | 41 +-- 28 files changed, 3848 insertions(+), 20 deletions(-) create mode 100644 guides/pt_BR/Twig.rst create mode 100644 guides/pt_BR/bundles/best_practices.rst create mode 100644 guides/pt_BR/bundles/configuration.rst create mode 100644 guides/pt_BR/bundles/index.rst create mode 100644 guides/pt_BR/doctrine/MongoDB.rst create mode 100644 guides/pt_BR/doctrine/configuration.rst create mode 100644 guides/pt_BR/doctrine/index.rst create mode 100644 guides/pt_BR/doctrine/migrations.rst create mode 100644 guides/pt_BR/doctrine/overview.rst create mode 100644 guides/pt_BR/emails.rst create mode 100644 guides/pt_BR/event/index.rst create mode 100644 guides/pt_BR/event/overview.rst create mode 100644 guides/pt_BR/event/recipes.rst create mode 100644 guides/pt_BR/forms.rst create mode 100644 guides/pt_BR/index.rst create mode 100644 guides/pt_BR/map.rst.inc create mode 100644 guides/pt_BR/testing/client.rst create mode 100644 guides/pt_BR/testing/configuration.rst create mode 100644 guides/pt_BR/testing/crawler.rst create mode 100644 guides/pt_BR/testing/index.rst create mode 100644 guides/pt_BR/testing/overview.rst create mode 100644 guides/pt_BR/testing/recipes.rst create mode 100644 guides/pt_BR/tools/YAML.rst create mode 100644 guides/pt_BR/tools/autoloader.rst create mode 100644 guides/pt_BR/tools/finder.rst create mode 100644 guides/pt_BR/tools/index.rst create mode 100644 guides/pt_BR/validator.rst diff --git a/guides/pt_BR/Twig.rst b/guides/pt_BR/Twig.rst new file mode 100644 index 00000000000..dfb1d39f3ef --- /dev/null +++ b/guides/pt_BR/Twig.rst @@ -0,0 +1,140 @@ +.. index:: + single: Twig + single: View; Twig + +Twig & Symfony2 +=============== + +`Twig`_ is a flexible, fast, and secure template language for PHP. Symfony2 +has native support for Twig through ``TwigBundle``. + +.. index:: + single: Twig; Installation + single: Twig; Configuration + +Installation & Configuration +---------------------------- + +Enable the ``TwigBundle`` in your kernel:: + + public function registerBundles() + { + $bundles = array( + // ... + new Symfony\Framework\TwigBundle\Bundle(), + ); + + // ... + } + +Then, configure it: + +.. code-block:: yaml + + # config/config.yml + twig.config: ~ + + # config/config_dev.yml + twig.config: + auto_reload: true + +.. tip:: + The configuration options are the same as the ones you pass to the + ``Twig_Environment`` `constructor`_. + +Usage +----- + +To render a Twig template instead of a PHP one, add the ``:twig`` suffix at the +end of the template name. The controller below renders the ``index.twig`` +template:: + + public function indexAction($name) + { + return $this->render('HelloBundle:Hello:index:twig', array('name' => $name)); + } + +The ``:twig`` suffix is only needed when there is no context, like in a +controller. But when you extend or include a template from a Twig template, +Symfony2 automatically switches the default engine to 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 %} + +To embed a PHP template in a Twig one, add the ``:php`` suffix to the template +name: + +.. code-block:: jinja + + {# index.twig #} + + {% render 'HelloBundle:Hello:sidebar:php' %} + +And the opposite is also true:: + + {# index.php #} + + render('HelloBundle:Hello:sidebar:twig') ?> + +.. index:: + single: Twig; Helpers + +Helpers +------- + +The default Symfony2 helpers are available within a Twig template via +specialized tags: + +.. 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:: + +Enabling Custom Extensions +-------------------------- + +To enable a Twig extension, add it as a regular service in one of your +configuration, and add a ``twig.extension`` annotation: + +.. code-block:: yaml + + services: + twig.extension.your_extension_name: + class: Fully\Qualified\Extension\Class\Name + annotation: { name: twig.extension } + +.. _Twig: http://www.twig-project.org/ +.. _constructor: http://www.twig-project.org/book/03-Twig-for-Developers diff --git a/guides/pt_BR/bundles/best_practices.rst b/guides/pt_BR/bundles/best_practices.rst new file mode 100644 index 00000000000..0898389b8d6 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/bundles/configuration.rst b/guides/pt_BR/bundles/configuration.rst new file mode 100644 index 00000000000..0b3ba90d734 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/bundles/index.rst b/guides/pt_BR/bundles/index.rst new file mode 100644 index 00000000000..6617561e724 --- /dev/null +++ b/guides/pt_BR/bundles/index.rst @@ -0,0 +1,8 @@ +Bundles +======= + +.. toctree:: + :maxdepth: 2 + + best_practices + configuration diff --git a/guides/pt_BR/doctrine/MongoDB.rst b/guides/pt_BR/doctrine/MongoDB.rst new file mode 100644 index 00000000000..6e0cb986533 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/doctrine/configuration.rst b/guides/pt_BR/doctrine/configuration.rst new file mode 100644 index 00000000000..c4e47851622 --- /dev/null +++ b/guides/pt_BR/doctrine/configuration.rst @@ -0,0 +1,168 @@ +Doctrine Configuration +====================== + +DBAL Configuration +------------------ + +<<<<<<< HEAD:guides/doctrine/configuration.rst +.. code-block:: yaml + +======= + [yml] +>>>>>>> origin/PR3:guides/en/Doctrine/Configuration.markdown + # 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 +----------------- + +<<<<<<< HEAD:guides/doctrine/configuration.rst +.. code-block:: yaml +======= + doctrine.orm: + default_entity_manager: default + cache_driver: apc # array, apc, memcache, xcache + entity_managers: + default: + connection: default + customer: + connection: customer +>>>>>>> origin/PR3:guides/en/Doctrine/Configuration.markdown + + 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. + + ... \ No newline at end of file diff --git a/guides/pt_BR/doctrine/index.rst b/guides/pt_BR/doctrine/index.rst new file mode 100644 index 00000000000..bfcd552931a --- /dev/null +++ b/guides/pt_BR/doctrine/index.rst @@ -0,0 +1,9 @@ +Doctrine +======== + +.. toctree:: + :maxdepth: 2 + + Overview + migrations + MongoDB diff --git a/guides/pt_BR/doctrine/migrations.rst b/guides/pt_BR/doctrine/migrations.rst new file mode 100644 index 00000000000..fb43fd7f02e --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/doctrine/overview.rst b/guides/pt_BR/doctrine/overview.rst new file mode 100644 index 00000000000..c4301f8bb24 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/emails.rst b/guides/pt_BR/emails.rst new file mode 100644 index 00000000000..c54a010c0dd --- /dev/null +++ b/guides/pt_BR/emails.rst @@ -0,0 +1,37 @@ +.. index:: + single: Emails + +Emails +====== + +Sending emails with Symfony is a snap. First, enable the ``SwiftmailerBundle`` +and configure how you want them to be sent: + +.. code-block:: yaml + + # hello/config/config.yml + swift.mailer: + transport: gmail # can be any of smtp, mail, sendmail, or gmail + username: your_gmail_username + password: your_gmail_password + +Then, use the mailer from any action:: + + public function indexAction($name) + { + // get the mailer first (mandatory to initialize Swift Mailer) + $mailer = $this->getMailer(); + + $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(...); + } + +The email body is stored in a template, rendered with the ``renderView()`` +method. diff --git a/guides/pt_BR/event/index.rst b/guides/pt_BR/event/index.rst new file mode 100644 index 00000000000..da97d639e16 --- /dev/null +++ b/guides/pt_BR/event/index.rst @@ -0,0 +1,8 @@ +Event System +============ + +.. toctree:: + :maxdepth: 2 + + Overview + recipes diff --git a/guides/pt_BR/event/overview.rst b/guides/pt_BR/event/overview.rst new file mode 100644 index 00000000000..ac240506b3d --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/event/recipes.rst b/guides/pt_BR/event/recipes.rst new file mode 100644 index 00000000000..139d7213a82 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/forms.rst b/guides/pt_BR/forms.rst new file mode 100644 index 00000000000..787d0e981d3 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/index.rst b/guides/pt_BR/index.rst new file mode 100644 index 00000000000..81fb57efad3 --- /dev/null +++ b/guides/pt_BR/index.rst @@ -0,0 +1,19 @@ +Guides +====== + +Dive into Symfony2 with the topical guides: + +.. toctree:: + :hidden: + + testing/index + doctrine/index + emails + forms + validator + Twig + event/index + tools/index + bundles/index + +.. include:: map.rst.inc diff --git a/guides/pt_BR/map.rst.inc b/guides/pt_BR/map.rst.inc new file mode 100644 index 00000000000..2e09f000728 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/testing/client.rst b/guides/pt_BR/testing/client.rst new file mode 100644 index 00000000000..8d702a5f33c --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/testing/configuration.rst b/guides/pt_BR/testing/configuration.rst new file mode 100644 index 00000000000..8d8ce0b6024 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/testing/crawler.rst b/guides/pt_BR/testing/crawler.rst new file mode 100644 index 00000000000..e2a87c64ecc --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/testing/index.rst b/guides/pt_BR/testing/index.rst new file mode 100644 index 00000000000..76e665dc2fb --- /dev/null +++ b/guides/pt_BR/testing/index.rst @@ -0,0 +1,11 @@ +Testing +======= + +.. toctree:: + :maxdepth: 2 + + Overview + configuration + crawler + client + recipes diff --git a/guides/pt_BR/testing/overview.rst b/guides/pt_BR/testing/overview.rst new file mode 100644 index 00000000000..62fcd53c777 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/testing/recipes.rst b/guides/pt_BR/testing/recipes.rst new file mode 100644 index 00000000000..5e43ffc1b8b --- /dev/null +++ b/guides/pt_BR/testing/recipes.rst @@ -0,0 +1,163 @@ +.. 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):: + +<<<<<<< HEAD:guides/testing/recipes.rst +======= + [php] +>>>>>>> origin/PR3:guides/en/Testing/Recipes.markdown + 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/guides/pt_BR/tools/YAML.rst b/guides/pt_BR/tools/YAML.rst new file mode 100644 index 00000000000..8abe3d8bbab --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/tools/autoloader.rst b/guides/pt_BR/tools/autoloader.rst new file mode 100644 index 00000000000..a1c40acaea0 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/tools/finder.rst b/guides/pt_BR/tools/finder.rst new file mode 100644 index 00000000000..7d8c4b2d820 --- /dev/null +++ b/guides/pt_BR/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/guides/pt_BR/tools/index.rst b/guides/pt_BR/tools/index.rst new file mode 100644 index 00000000000..3988c5e9dd9 --- /dev/null +++ b/guides/pt_BR/tools/index.rst @@ -0,0 +1,9 @@ +Tools +===== + +.. toctree:: + :maxdepth: 2 + + autoloader + finder + YAML diff --git a/guides/pt_BR/validator.rst b/guides/pt_BR/validator.rst new file mode 100644 index 00000000000..5ce63091802 --- /dev/null +++ b/guides/pt_BR/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/quick_tour/pt_BR/the_architecture.rst b/quick_tour/pt_BR/the_architecture.rst index 3872b147618..10def2b76ce 100644 --- a/quick_tour/pt_BR/the_architecture.rst +++ b/quick_tour/pt_BR/the_architecture.rst @@ -113,32 +113,33 @@ do diretorio ``scr/``:: )); $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. +O ``UniversalClassLoader`` é usado no Symfony para carregar automaticamente os +arquivos que seguem o `padrão` de interoperabilidade técnica _para namespace +para o PHP 5.3 ou para nomeações PEAR_ para as classes. Como você pode ver aqui, +todas as dependencias são armazenadas no diretorio ``vendor/``, mas isto é somente +uma convenção. Você pode armazenar em qualquer lugar que você quiser, globalmente +em seu servidor ou localmente em seu projeto. .. 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. +O Sistema de empacotamento (Bundle) +----------------------------------- -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. +Esta seção começa a arranhar a superfície de um dos maiores e mais poderosos +recursos do Symfony, o sistema de empacotamento. -An application is made up of bundles as defined in the ``registerBundles()`` -method of the ``HelloKernel`` class:: +Um pacote é como um plugin em outros softwares. Mas por que é chamado +pacote e não plugin, então? Porque tudo é um pacote no Symfony, das features do +core do framework até seus códigos escritos para a sua aplicação. Pacotes são +cidadãos de primeira classe em Symfony. Isso lhe dá a flexibilidade para usar os +recursos pré-construído e embalados em pacotes de terceiros ou para distribuir +seus próprios pacotes. Isso torna muito fácil escolher quais as funcionalidades +que permitam a sua aplicação e otimizá-los da maneira que quiser. + +Uma aplicação é composta por pacotes definidos no método ``registerBundles()`` +da classe:: ``HelloKernel`` // hello/HelloKernel.php @@ -161,7 +162,7 @@ method of the ``HelloKernel`` class:: ); } -Along side the ``HelloBundle`` we have already talked about, notice that the +Ao lado do ``HelloBundle`` que nos já falamos sobre 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. From 0bfdda0061b74ffcf1d98812dd967b500cf1d1f5 Mon Sep 17 00:00:00 2001 From: Adell Date: Tue, 31 Aug 2010 16:23:41 -0300 Subject: [PATCH 9/9] Terminada a pagina the_architecture.rst --- quick_tour/pt_BR/the_architecture.rst | 117 +++++++++++++------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/quick_tour/pt_BR/the_architecture.rst b/quick_tour/pt_BR/the_architecture.rst index 10def2b76ce..a72948faa2d 100644 --- a/quick_tour/pt_BR/the_architecture.rst +++ b/quick_tour/pt_BR/the_architecture.rst @@ -113,11 +113,11 @@ do diretorio ``scr/``:: )); $loader->register(); -O ``UniversalClassLoader`` é usado no Symfony para carregar automaticamente os -arquivos que seguem o `padrão` de interoperabilidade técnica _para namespace -para o PHP 5.3 ou para nomeações PEAR_ para as classes. Como você pode ver aqui, -todas as dependencias são armazenadas no diretorio ``vendor/``, mas isto é somente -uma convenção. Você pode armazenar em qualquer lugar que você quiser, globalmente +O ``UniversalClassLoader`` do Symfony é usado para carregar automaticamente os +arquivos que respeita nem a técnica de interoperabilidade `standards`_ para PHP 5.3 namespaces +ou o PEAR nomeação de `convention`_ classes. Como você pode ver aqui, todas as dependencias +são armazenadas no diretorio ``vendor/``, mas isto é somente uma convenção. +Você pode armazenar em qualquer lugar que você quiser, globalmente em seu servidor ou localmente em seu projeto. .. index:: @@ -131,7 +131,7 @@ Esta seção começa a arranhar a superfície de um dos maiores e mais poderosos recursos do Symfony, o sistema de empacotamento. Um pacote é como um plugin em outros softwares. Mas por que é chamado -pacote e não plugin, então? Porque tudo é um pacote no Symfony, das features do +pacote e não plugin então? Porque tudo é um pacote no Symfony, das features do core do framework até seus códigos escritos para a sua aplicação. Pacotes são cidadãos de primeira classe em Symfony. Isso lhe dá a flexibilidade para usar os recursos pré-construído e embalados em pacotes de terceiros ou para distribuir @@ -162,13 +162,12 @@ da classe:: ``HelloKernel`` ); } -Ao lado do ``HelloBundle`` que nos já falamos sobre 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. +Juntamente com o ``HelloBundle`` que nos já comentamos, note que o kernel também +permite ``KernelBundle``, ``FoundationBundle``, ``DoctrineBundle``, +``SwiftmailerBundle``, e ``ZendBundle``. Todos fazem parte do núcleo do framework. -Each bundle can be customized via configuration files written in YAML or XML. -Have a look at the default configuration: +Cada pacote pode ser customizado via configuração, escrevendo arquivos YAML ou XML. +Veja as configurações padrão: .. code-block:: yaml @@ -177,12 +176,12 @@ Have a look at the default configuration: 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``. +Cada entrada, como por exemplo ``kernel.config`` define a configuração do pacote. +Alguns pacotes podem ter varias entradas caso ofereçam muitas funcionalidades +``FoundationBundle``, que tem duas entradas: ``web.config`` e ``web.templating``. -Each environment can override the default configuration by providing a -specific configuration file: +Cada ambiente pode sobescrever a configuração padrão fornecendo um arquivo especifico +de configuração: .. code-block:: yaml @@ -197,11 +196,11 @@ specific configuration file: 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):: +Como vimos na parte anterior, uma aplicação é feita de pacotes definidos no método +``registerBundles()``, mas como o Symfony sabe onde procurar um pacote? Symfony é +muito flexível neste aspecto. O método ``registerBundleDirs()`` deve retornar um +array associativo que mapeia namespaces para qualquer diretório válido (locais ou +globais):: public function registerBundleDirs() { @@ -212,11 +211,11 @@ namespaces to any valid directory (local or global ones):: ); } -So, when you reference the ``HelloBundle`` in a controller name or in a template -name, Symfony will look for it under the given directories. +Então quando você referencia o ``HelloBundle`` em um controller name ou em um +template name, o Symfony procura dentro destes diretorios. -Do you understand now why Symfony is so flexible? Share your bundles between -applications, store them locally or globally, your choice. +Agora você entende porque o Symfony é tão flexivél? Compartilhe seus pacotes +entre aplicações, armazene localmente o globalmente, você escolhe. .. index:: single: Vendors @@ -224,66 +223,64 @@ applications, store them locally or globally, your choice. 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. +Provavelmente sua aplicação dependerá de biblioteca de terceiros. Estas devem ser +armazenadas no diretorio ``src/vendor``. Ele já contém as bibliotecas do symfony, +SwiftMailer, o ORM Doctrine, o ORM Prople, o sistema de templates Twig, e uma +seleção de classes do Zend Framework. .. index:: single: Cache single: Logs -Cache and Logs --------------- +Cache e 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. +Symfony é provavelmente um dos mais rápidos frameworks full-stack. Mas como pode +ser tão rapido se analisa dezenas de arquivos YAML e XML a cada solicitação? Isto +se deve em parte ao sistema de cache. A configuração da aplicação é analisada no +primeiro pedido, depois é compilada em codigo PHP e armazenada no diretorio +``cache/``. No ambiente de desenvolvimento, o Symfony é esperto o suficiente para +limpar o chache quando você altera um arquivo ou muda sua configuração. -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. +Quando desenvolvemos uma aplicação, as coisas podem dar errado em muitos aspectos. +Os arquivos log do diretorio ``logs/`` dizem a você tudo sobre os pedidos e te +ajudam a corrigir o problema rapidamente. .. index:: single: CLI single: Command Line -The Command Line Interface --------------------------- +A interface de Linha de Comando +------------------------------- -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. +Cada aplicação vem com uma ferramenta de linha de comando (``console``), ela te +ajuda a manter sua aplicação. Ele fornece comandos que aumentar a sua +produtividade ao automatizar tarefas tediosas e repetitivas. -Run it without any arguments to learn more about its capabilities: +Chame-a sem argumentos para aprender mais sobre suas capacidades: .. code-block:: bash $ php hello/console -The ``--help`` option helps you discover the usage of a command: +A opção ``--help`` te ajuda a descobrir o uso de um comando: .. code-block:: bash $ php hello/console router:debug --help -Final Thoughts --------------- +Considerações Finais +-------------------- -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. +Me chame de louco, mas após ler esta parte, você deve estar confortável com a +coisas que o circulam e fazem o Symfony trabalhar por você. Tudo é feito no +Symfony para estar fora do teu caminho. Então, sinta-se livre para renomear e +mover os diretorios como achar necessario. -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. +E isto é tudo para um tour rápido. Entre os teste de envio de e-mail, você ainda +necessidade de aprender muito para se tornar um mestre Symfony. Pronto para +cavar esses temas agora? Não procure mais, vá para a `guides`_ pagina oficial e +ecolha qualquer tópico que quiser. .. _standards: http://groups.google.com/group/php-standards/web/psr-0-final-proposal .. _convention: http://pear.php.net/