From b7fb6e7c74d8b312a5d0c62d632baa5c8d82529a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:59:29 +0000 Subject: [PATCH 01/53] Bump actions/stale from 7 to 8 Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index b40eff1a3f..2ca96f675b 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - uses: actions/stale@v8 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue is stale because it has been open for 120 days with no activity. Remove the `stale` label or comment or this will be closed in 15 days' From 945b0550f88b7cd47807c4e44ab6df8f5aad4a87 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Fri, 14 Apr 2023 09:43:06 -0300 Subject: [PATCH 02/53] controllers.rst spanish translate until 'Request Flow' --- es/controllers.rst | 85 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/es/controllers.rst b/es/controllers.rst index 03a972a518..226da385e3 100644 --- a/es/controllers.rst +++ b/es/controllers.rst @@ -5,17 +5,86 @@ Controllers .. php:class:: Controller -.. note:: - La documentación no es compatible actualmente con el idioma español en esta página. +Los controladores son la 'C' en MVC. Después de aplicar el enrutamiento y +que el controlador +ha sido encontrado, la acción de tu controlador es llamado. Tu controlador +debe manejar la interpretación de los datos de la solicitud, +asegurándose de que se llamen +a los modelos correctos y se muestre la respuesta o vista correcta. +Los controladores se pueden +considerar como una capa intermedia entre el Modelo y la Vista. Quieres mantener +tus controladores delgados, y tus modelos gruesos. +Esto te ayudará a reutilizar tu código +y más fácil de probar. - Por favor, siéntase libre de enviarnos un pull request en - `Github `_ o utilizar el botón **Improve this Doc** para proponer directamente los cambios. +Comúnmente, un controlador se usa para administrar la lógica en torno +a un solo modelo. Por +ejemplo, si estuvieras construyendo un sitio online para una panadería, +podrías tener un +RecetasController que gestiona tus recetas y un IngredientesController +que gestiona tus +ingredientes. Sin embargo, es posible hacer que los controladores trabajen +con más de +un modelo. En CakePHP, un controlador es nombrado a raíz del modelo que maneja. + +Los controladores de tu aplicación extienden de la clase ``AppController``, +que a su vez extiende de la clase principal :php:class:`Controller`. +La clase ``AppController`` puede ser definida en **src/Controller/AppController.php** +y debería contener los métodos que se comparten entre todos los controladores +de tu aplicación. + +Los controladores proveen una serie de métodos que manejan las peticiones. Estos +son llamadas *acciones*. Por defecto, cada método público en un controlador es +una acción, y es accesible mediante una URL. Una acción es responsable de +interpretar la petición y crear la respuesta. Por lo general, las respuestas +son de la forma de una vista renderizada, pero también, hay otras maneras de crear +respuestas. + +.. _app-controller: + +The App Controller +================== + +Como se indicó en la introducción, la clase ``AppController`` es clase padre de +todos los controladores de tu aplicación. ``AppController`` extiende de la clase +:php:class:`Cake\\Controller\\Controller` que está incluida en CakePHP. +``AppController`` se define en **src/Controller/AppController.php** como se +muestra a continuación:: + + namespace App\Controller; + + use Cake\Controller\Controller; + + class AppController extends Controller + { + } + +Los atributos y métodos del controlador creados en tu ``AppController`` van a +estar disponibles en todos los controladores que extiendan de este. Los +componentes (que aprenderás más adelante) son mejor usados para código que se +encuentra en muchos (pero no necesariamente en todos) los componentes. + +Puedes usar tu ``AppController`` para cargar componentes que van a ser utilizados +en cada controlador de tu aplicación. CakePHP proporciona un método ``initialize()`` +que es llamado al final del constructor de un controlador para este tipo de uso:: + + namespace App\Controller; + + use Cake\Controller\Controller; + + class AppController extends Controller + { + public function initialize(): void + { + // Always enable the CSRF component. + $this->loadComponent('Csrf'); + } + } + +Request Flow +============ - Usted puede hacer referencia a la versión en Inglés en el menú de selección superior - para obtener información sobre el tema de esta página. -More on Controllers -=================== .. toctree:: :maxdepth: 1 From c0cd8812ef2c848f4a7a2db544dd0c7ae8f07749 Mon Sep 17 00:00:00 2001 From: naidim Date: Mon, 17 Apr 2023 10:33:49 -0400 Subject: [PATCH 03/53] Updated composer command authentication 2.0 won't install with PHP 8/8.1/8.2 because zendframework/zend-diactros requires PHP ^7.1, and is also an abandoned package --- en/tutorials-and-examples/cms/authentication.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/tutorials-and-examples/cms/authentication.rst b/en/tutorials-and-examples/cms/authentication.rst index aa11152f3f..6df7acb93b 100644 --- a/en/tutorials-and-examples/cms/authentication.rst +++ b/en/tutorials-and-examples/cms/authentication.rst @@ -14,7 +14,7 @@ Use composer to install the Authentication Plugin: .. code-block:: console - composer require "cakephp/authentication:^2.0" + composer require "cakephp/authentication:^2.4" Adding Password Hashing From c91f5db14fd97838eadee8f8efd37c32dcaabaf3 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Mon, 17 Apr 2023 17:15:18 -0300 Subject: [PATCH 04/53] translated until Controller Callback Methods --- es/controllers.rst | 428 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 425 insertions(+), 3 deletions(-) diff --git a/es/controllers.rst b/es/controllers.rst index 226da385e3..95f83df284 100644 --- a/es/controllers.rst +++ b/es/controllers.rst @@ -21,7 +21,7 @@ Comúnmente, un controlador se usa para administrar la lógica en torno a un solo modelo. Por ejemplo, si estuvieras construyendo un sitio online para una panadería, podrías tener un -RecetasController que gestiona tus recetas y un IngredientesController +RecipesController que gestiona tus recetas y un IngredientsController que gestiona tus ingredientes. Sin embargo, es posible hacer que los controladores trabajen con más de @@ -81,10 +81,432 @@ que es llamado al final del constructor de un controlador para este tipo de uso: } } -Request Flow -============ +Flujo de solicitud +================== + +Cuando se realiza una solicitud a una aplicación CakePHP, las clases CakePHP +:php:class:`Cake\\Routing\\Router` y :php:class:`Cake\\Routing\\Dispatcher` +usan :ref:`routes-configuration` para encontrar y crear la instancia correcta +del controlador. Los datos de la solicitud son encapsulados en un objeto de +solicitud. CakePHP pone toda la información importante de la solicitud en la +propiedad ``$this->request``. Consulta la sección sobre :ref:`cake-request` +para obtener más información sobre el objeto de solicitud de CakePHP. + +Acciones del controlador +======================== + +Las acciones del controlador son las responsables de convertir los parámetros +de la solicitud en una respuesta para el navegador/usuario que realiza la +petición. CakePHP usa convenciones para automatizar este proceso y eliminar +algunos códigos repetitivos que de otro modo se necesitaría escribir. + +Por convención, CakePHP renderiza una vista con una versión en infinitivo del nombre +de la acción. Volviendo a nuestro ejemplo de la panadería online, nuestro +RecipesController podría contener las acciones ``view()``, ``share()``, y +``search()``. El controlador sería encontrado en +**src/Controller/RecipesController.php** y contiene:: + + // src/Controller/RecipesController.php + + class RecipesController extends AppController + { + public function view($id) + { + // Action logic goes here. + } + + public function share($customerId, $recipeId) + { + // Action logic goes here. + } + + public function search($query) + { + // Action logic goes here. + } + } + +Las plantillas para estas acciones serían **templates/Recipes/view.php**, +**templates/Recipes/share.php**, y **templates/Recipes/search.php**. El nombre +convencional para un archivo de vista es con minúsculas y con el nombre de la +acción entre guiones bajos. + +Las acciones de los controladores por lo general usan ``Controller::set()`` para +crear un contexto que ``View`` usa para renderizar la capa de vista. Debido +a las convenciones que CakePHP usa, no necesitas crear y renderizar la vista +manualmente. En su lugar, una vez que se ha completado la acción del controlador, +CakePHP se encargará de renderizar y entregar la vista. + +Si por algún motivo deseas omitir el comportamiento predeterminado, puedes retornar +un objeto :php:class:`Cake\\Http\\Response` de la acción con la respuesta creada. + +Para que puedas usar un controlador de manera efectiva en tu aplicación, +cubriremos algunos de los atributos y métodos principales proporcionados por los +controladores de CakePHP. + +Interactuando con vistas +======================== + +Los controladores interactúan con las vistas de muchas maneras. Primero, los +controladores son capaces de pasar información a las vistas, usando ``Controller::set()``. +También puedes decidir que clase de vista usar, y que archivo de vista debería +ser renderizado desde el controlador. + +.. _setting-view_variables: + +Configuración de variables de vista +----------------------------------- + +.. php:method:: set(string $var, mixed $value) + +EL método ``Controller::set()`` es la manera principal de mandar información +desde el controlador a la vista. Una vez que hayas utilizado ``Controller::set()``, +la variable puede ser accedida en tu vista:: + + // Primero pasas las información desde el controlador: + + $this->set('color', 'rosa'); + + // Después, en la vista, puede utilizar la información: + ?> + + Has seleccionado cubierta para la tarta. + +El método ``Controller::set()`` también toma un array asociativo como su primer +parámetro. A menudo, esto puede ser una forma rápida de asignar un conjunto de +información a la vista:: + + $data = [ + 'color' => 'pink', + 'type' => 'sugar', + 'base_price' => 23.95 + ]; + + // Hace $color, $type, and $base_price + // disponible para la vista: + + $this->set($data); + +Ten en cuenta que las variables de la vista se comparten entre todas las partes +renderizadas por tu vista. Estarán disponibles en todas las partes de la vista: +la plantilla y todos los elementos dentro de estas dos. + +Configuración de las opciones de la vista +----------------------------------------- + +Si deseas personalizar la clase vista, las rutas de diseño/plantillas, ayudantes +o el tema que se usarán para renderiza la vista, puede usar el método ``viewBuilder()`` +para obtener un constructor. Este constructor se puede utilizar para definir +propiedades de la vista antes de crearlas:: + + $this->viewBuilder() + ->addHelper('MyCustom') + ->setTheme('Modern') + ->setClassName('Modern.Admin'); + +Lo anterior muestra cómo puedes cargar ayudantes personalizados, configurar el tema +y usar una clase vista personalizada. + +Renderizando una vista +---------------------- + +.. php:method:: render(string $view, string $layout) + +El método ``Controller::render()`` es llamado automáticamente al final de cada +solicitud de la acción del controlador. Este método realiza toda la lógica +de la vista (usando la información que has enviado usando el método ``Controller::set()``), +coloca la vista dentro de su ``View::$layout``, y lo devuelve al usuario final. + +El archivo de vista por defecto utilizado para el renderizado es definido por +convención. +Si la acción ``search()`` de RecipesController es solicitada, el archivo vista en +**templates/Recipes/search.php** será renderizado:: + + namespace App\Controller; + + class RecipesController extends AppController + { + // ... + public function search() + { + // Renderiza la vista en templates/Recipes/search.php + return $this->render(); + } + // ... + } + +Aunque CakePHP va a llamarlo automáticamente después de cada acción de lógica +(a menos que llames a ``$this->disableAutoRender()``), puedes usarlo para +especificar un archivo de vista alternativo especificando el nombre de este como +primer argumento del método ``Controller::render()``. + +Si ``$view`` empieza con '/', se asume que es una vista o un archivo relacionado +con la carpeta **templates**. Esto permite el renderizado directo de elementos, +muy útil en llamadas AJAX:: + + // Renderiza el elemento en templates/element/ajaxreturn.php + $this->render('/element/ajaxreturn'); + +El segundo parámetro ``$layout`` de ``Controller::render()`` te permita especificar +la estructura con la que la vista es renderizada. + +Renderizando una plantilla específica +------------------------------------- + +En tu controlador, puede que quieras renderizar una vista diferente a la que es +convencional. Puedes hacer esto llamando a ``Controller::render()`` directamente. +Una vez que hayas llamado a ``Controller::render()``, CakePHP no tratará de +re-renderizar la vista:: + + namespace App\Controller; + + class PostsController extends AppController + { + public function my_action() + { + $this->render('custom_file'); + } + } + +Esto renderizará **templates/Posts/custom_file.php** en vez de +**templates/Posts/my_action.php**. + +También puedes renderizar vistas dentro de plugins usando la siguiente sintaxis: +``$this->render('PluginName.PluginController/custom_file')``. Por ejemplo:: + + namespace App\Controller; + + class PostsController extends AppController + { + public function myAction() + { + $this->render('Users.UserDetails/custom_file'); + } + } + +Esto renderizará **plugins/Users/templates/UserDetails/custom_file.php** +.. _controller-viewclasses: + +Negociación del tipo de contenido +================================= + +.. php:method:: viewClasses() + +Los controladores pueden definir una lista de clases de vistas que soportan. +Después de que la acción del controlador este completa CakePHP usará la lista de +vista para realizar negociación del tipo de contenido. Esto permite a tu aplicación +rehusar la misma acción del controlador para renderizar una vista HTMl o +renderizar una respuesta JSON o XML. Para definir la lista de clases de vista que +soporta un controlador se utiliza el método ``viewClasses()``:: + + namespace App\Controller; + + use Cake\View\JsonView; + use Cake\View\XmlView; + + class PostsController extends AppController + { + public function viewClasses(): array + { + return [JsonView::class, XmlView::class]; + } + } + +La clase ``View`` de la aplicación se usa automáticamente como respaldo cuando +no se puede seleccionar otra vista en función del encabezado de la petición ``Accept`` +o de la extensión del enrutamiento. Si tu aplicación necesita realizar una lógica +diferente para diferente formatos de respuesta puedes usar ``$this->request->is()`` +para construir la lógica condicional requerida. + +.. note:: + Las clases de vista deben implementar el método estático ``contentType()`` + para participar en las negociaciones del tipo de contenido. + +Negociación de tipo de contenido alternativos +============================================= + +Si ninguna vista puede coincidir con las preferencias del tipo de contenido de la +petición, CakePHP usará la clase base ``View``. Si deseas solicitar una negociación +del tipo de contenido, puedes usar ``NegotiationRequiredView`` que setea un código +de estatus 406:: + + public function viewClasses(): array + { + // Requiere aceptar la negociación del encabezado o devuelve una respuesta 406. + return [JsonView::class, NegotiationRequiredView::class]; + } + +Puede usar el valor del tipo de contenido ``TYPE_MATCH_ALL`` para crear tu lógica +de vista alternativa:: + + namespace App\View; + + use Cake\View\View; + + class CustomFallbackView extends View + { + public static function contentType(): string + { + return static::TYPE_MATCH_ALL; + } + + } + +Es importante recordar que las vistas coincidentes se aplican sólo *después* de +intentar la negociación del tipo de contenido. + +.. versionadded:: 4.4.0 + Anterior a 4.4 debes usar :doc:`/controllers/components/request-handling` + en vez de ``viewClasses()``. + +Redirigiendo a otras páginas +============================ + +.. php:method:: redirect(string|array $url, integer $status) + +El método ``redirect()`` agrega un encabezado ``Location`` y establece un código +de estado de una respuesta y la devuelve. Deberías devolver la respuesta creada +por ``redirect()`` para que CakePHP envíe la redirección en vez de completar +la acción del controlador y renderizar la vista. + +Puedes rerigir usando los valores :term:`routing array`:: + + return $this->redirect([ + 'controller' => 'Orders', + 'action' => 'confirm', + $order->id, + '?' => [ + 'product' => 'pizza', + 'quantity' => 5 + ], + '#' => 'top' + ]); + +O usando una URL relativa o absoluta:: + + return $this->redirect('/orders/confirm'); + return $this->redirect('http://www.example.com'); + +O la referencia de la página:: + + return $this->redirect($this->referer()); + +Usando el segundo parámetro puede definir un código de estatus para tu redirección:: + + // Haz un 301 (movido permanentemente) + return $this->redirect('/order/confirm', 301); + + // Haz un 303 (Ver otro) + return $this->redirect('/order/confirm', 303); + +Mira la sección :ref:`redirect-component-events` para saber como redirigir fuera +del ciclo de vida del manejador. + +Reenviando a un acción en el mismo controlador +============================================== + +.. php:method:: setAction($action, $args...) + +Si necesitas reenviar la acción actual a una acción diferente en el *mismo* controlador, +puedes usar ``Controller::setAction()`` para actualizar el objeto de la solicitud, +modifica la plantilla de vista que será renderizada y reendía la ejecución a la +nombrada acción:: + + // Desde una acción de elimincación, puedes renderizar a lista de página + // actualizada. + $this->setAction('index'); + +Cargando modelos adicionales +============================ + +.. php:method:: fetchTable(string $alias, array $config = []) + +La función ``fetchTable()`` es útil cuando se necesita usar una tabla que no es +la predeterminada por el controlador:: + + // En un método del controlador. + $recentArticles = $this->fetchTable('Articles')->find('all', [ + 'limit' => 5, + 'order' => 'Articles.created DESC' + ]) + ->all(); + +.. versionadded:: 4.3.0 + ``Controller::fetchTable()`` fue añadido. Antes de 4.3 necesitas usar ``Controller::loadModel()``. + +Paginación de un modelo +======================= + +.. php:method:: paginate() + +Este método se utiliza para paginar los resultados obtenidos por tus modelos. +Puedes especificar tamaño de páginas, condiciones de búsqueda del modelo y más. +Ver la sección :doc:`pagination ` para más detalle de como +usar ``paginate()``. + +El atributo ``$paginate`` te da una manera de personalizar cómo ``paginate()`` +se comporta:: + + class ArticlesController extends AppController + { + public $paginate = [ + 'Articles' => [ + 'conditions' => ['published' => 1] + ] + ]; + } + +Configuración de componentes para cargar +======================================== + +.. php:method:: loadComponent($name, $config = []) + +En el método ``initialize()`` de tu controlador, puedes definir cualquier componente +que deseas cargar, y cualquier dato de configuración para ellos:: + + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Csrf'); + $this->loadComponent('Comments', Configure::read('Comments')); + } + +.. _controller-life-cycle: + +Devolución del ciclo de vida de la petición +=========================================== + +Los controladores de CakePHP activan varios eventos/callbacks que puedes usar +para insertar lógica alrededor del ciclo de vida de la solicitud. + +Lista de eventos +---------------- + +* ``Controller.initialize`` +* ``Controller.startup`` +* ``Controller.beforeRedirect`` +* ``Controller.beforeRender`` +* ``Controller.shutdown`` + +Métodos de devolución de llamada del controlador +================================================ + +Por defecto, los siguientes métodos de devolución de llamada están conectados a +eventos relacionados si los métodos son implementados por tus controladores. + +.. php:method:: beforeFilter(EventInterface $event) + Llamado durante el evento ``Controller.initialize`` que ocurre antes de cada + acción en el controlador. Es un lugar útil para comprobar si hay una sesión + activa o inspeccionar los permisos del usuario. + + .. note:: + El método beforeFilter() será llamado por acciones faltantes. + + Devolver una respuesta del método ``beforeFilter`` no evitará que otros oyentes + del mismo evento sean llamados. Debes explícitamente :ref:`stop the event `. +.. php:method:: beforeRender(EventInterface $event) .. toctree:: :maxdepth: 1 From 3aaa4a52083ed22336a5b7f85fc02d11b5566eac Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Tue, 18 Apr 2023 10:26:17 -0300 Subject: [PATCH 05/53] first version finished --- es/controllers.rst | 60 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/es/controllers.rst b/es/controllers.rst index 95f83df284..ac1403a76f 100644 --- a/es/controllers.rst +++ b/es/controllers.rst @@ -1,4 +1,4 @@ -Controllers +Controladores ########### .. php:namespace:: Cake\Controller @@ -508,6 +508,64 @@ eventos relacionados si los métodos son implementados por tus controladores. .. php:method:: beforeRender(EventInterface $event) + Llamado durante el evento ``Controller.beforeRender`` que ocurre después + de la lógica de acción del controlador, pero antes de que la vista sea renderizada. + Esta devolución de llamada no se usa con frecuencia, pero puede ser necesaria + si estas llamando :php:meth:`~Cake\\Controller\\Controller::render()` de forma + manual antes del final de una acción dada. + +.. php:method:: afterFilter(EventInterface $event) + + Llamado durante el evento ``Controller.shutdown`` que se desencadena después + de cada acción del controlador, y después de que se complete el renderizado. + ESte es el último método del controlador para ejecutar. + +Además de las devoluciones de llamada del ciclo de vida del controlador, +:doc:`/controllers/components` también proporciona un conjunto similar de devoluciones +de llamada. + +Recuerda llamar a las devoluciones de llamada de ``AppController`` dentro de las +devoluciones de llamada del controlador hijo para mejores resultados:: + + //use Cake\Event\EventInterface; + public function beforeFilter(EventInterface $event) + { + parent::beforeFilter($event); + } + +.. _controller-middleware: + +Middleware del controlador +========================== + +.. php:method:: middleware($middleware, array $options = []) + +:doc:`Middleware ` puede ser definido globalmente, en +un ámbito de enrutamiento o dentro de un controlador. Para definir el middleware +para un controlador en específico usa el método ``middleware()`` de tu método +``initialize()`` del controlador:: + + public function initialize(): void + { + parent::initialize(); + + $this->middleware(function ($request, $handler) { + // Haz la lógica del middleware. + + // Verifica que devuelves una respuesta o llamas a handle() + return $handler->handle($request); + }); + } + +El middleware definido por un controlador será llamado **antes** ``beforeFilter()`` +y se llamarán a los métodos de acción. + +.. versionadded:: 4.3.0 + ``Controller::middleware()`` fue agregado. + +Más sobre controladores +=================== + .. toctree:: :maxdepth: 1 From f6ee9c14df0fd058cdb528fdab68a649b818a8f6 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Tue, 18 Apr 2023 15:57:07 -0300 Subject: [PATCH 06/53] typos fixed --- es/controllers.rst | 56 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/es/controllers.rst b/es/controllers.rst index ac1403a76f..a0f24b8867 100644 --- a/es/controllers.rst +++ b/es/controllers.rst @@ -1,5 +1,5 @@ Controladores -########### +############# .. php:namespace:: Cake\Controller @@ -14,8 +14,7 @@ a los modelos correctos y se muestre la respuesta o vista correcta. Los controladores se pueden considerar como una capa intermedia entre el Modelo y la Vista. Quieres mantener tus controladores delgados, y tus modelos gruesos. -Esto te ayudará a reutilizar tu código -y más fácil de probar. +Esto te ayudará a reutilizar tu código y lo hará mas fácil de probar. Comúnmente, un controlador se usa para administrar la lógica en torno a un solo modelo. Por @@ -42,7 +41,7 @@ respuestas. .. _app-controller: -The App Controller +El App Controller ================== Como se indicó en la introducción, la clase ``AppController`` es clase padre de @@ -76,7 +75,7 @@ que es llamado al final del constructor de un controlador para este tipo de uso: { public function initialize(): void { - // Always enable the CSRF component. + // Siempre habilita el componente CSRF. $this->loadComponent('Csrf'); } } @@ -112,17 +111,17 @@ RecipesController podría contener las acciones ``view()``, ``share()``, y { public function view($id) { - // Action logic goes here. + // La lógica de la acción va aquí. } public function share($customerId, $recipeId) { - // Action logic goes here. + // La lógica de la acción va aquí. } public function search($query) { - // Action logic goes here. + // La lógica de la acción va aquí. } } @@ -149,7 +148,7 @@ Interactuando con vistas Los controladores interactúan con las vistas de muchas maneras. Primero, los controladores son capaces de pasar información a las vistas, usando ``Controller::set()``. -También puedes decidir que clase de vista usar, y que archivo de vista debería +También puedes decidir qué clase de vista usar, y qué archivo de vista debería ser renderizado desde el controlador. .. _setting-view_variables: @@ -159,7 +158,7 @@ Configuración de variables de vista .. php:method:: set(string $var, mixed $value) -EL método ``Controller::set()`` es la manera principal de mandar información +El método ``Controller::set()`` es la manera principal de mandar información desde el controlador a la vista. Una vez que hayas utilizado ``Controller::set()``, la variable puede ser accedida en tu vista:: @@ -182,7 +181,7 @@ información a la vista:: 'base_price' => 23.95 ]; - // Hace $color, $type, and $base_price + // Hace $color, $type, y $base_price // disponible para la vista: $this->set($data); @@ -195,7 +194,7 @@ Configuración de las opciones de la vista ----------------------------------------- Si deseas personalizar la clase vista, las rutas de diseño/plantillas, ayudantes -o el tema que se usarán para renderiza la vista, puede usar el método ``viewBuilder()`` +o el tema que se usarán para renderizar la vista, puede usar el método ``viewBuilder()`` para obtener un constructor. Este constructor se puede utilizar para definir propiedades de la vista antes de crearlas:: @@ -251,7 +250,7 @@ El segundo parámetro ``$layout`` de ``Controller::render()`` te permita especif la estructura con la que la vista es renderizada. Renderizando una plantilla específica -------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ En tu controlador, puede que quieras renderizar una vista diferente a la que es convencional. Puedes hacer esto llamando a ``Controller::render()`` directamente. @@ -294,9 +293,9 @@ Negociación del tipo de contenido .. php:method:: viewClasses() Los controladores pueden definir una lista de clases de vistas que soportan. -Después de que la acción del controlador este completa CakePHP usará la lista de +Después de que la acción del controlador este completa, CakePHP usará la lista de vista para realizar negociación del tipo de contenido. Esto permite a tu aplicación -rehusar la misma acción del controlador para renderizar una vista HTMl o +rehusar la misma acción del controlador para renderizar una vista HTML o renderizar una respuesta JSON o XML. Para definir la lista de clases de vista que soporta un controlador se utiliza el método ``viewClasses()``:: @@ -370,7 +369,7 @@ de estado de una respuesta y la devuelve. Deberías devolver la respuesta creada por ``redirect()`` para que CakePHP envíe la redirección en vez de completar la acción del controlador y renderizar la vista. -Puedes rerigir usando los valores :term:`routing array`:: +Puedes redigir usando los valores :term:`routing array`:: return $this->redirect([ 'controller' => 'Orders', @@ -404,16 +403,16 @@ Mira la sección :ref:`redirect-component-events` para saber como redirigir fuer del ciclo de vida del manejador. Reenviando a un acción en el mismo controlador -============================================== +---------------------------------------------- .. php:method:: setAction($action, $args...) Si necesitas reenviar la acción actual a una acción diferente en el *mismo* controlador, puedes usar ``Controller::setAction()`` para actualizar el objeto de la solicitud, -modifica la plantilla de vista que será renderizada y reendía la ejecución a la +modifica la plantilla de vista que será renderizada y reenvía la ejecución a la nombrada acción:: - // Desde una acción de elimincación, puedes renderizar a lista de página + // Desde una acción de eliminación, puedes renderizar a lista de página // actualizada. $this->setAction('index'); @@ -474,8 +473,8 @@ que deseas cargar, y cualquier dato de configuración para ellos:: .. _controller-life-cycle: -Devolución del ciclo de vida de la petición -=========================================== +Callbacks del ciclo de vida de la petición +======================================================= Los controladores de CakePHP activan varios eventos/callbacks que puedes usar para insertar lógica alrededor del ciclo de vida de la solicitud. @@ -489,13 +488,14 @@ Lista de eventos * ``Controller.beforeRender`` * ``Controller.shutdown`` -Métodos de devolución de llamada del controlador +Métodos de callback del controlador ================================================ -Por defecto, los siguientes métodos de devolución de llamada están conectados a +Por defecto, los siguientes métodos de callback están conectados a eventos relacionados si los métodos son implementados por tus controladores. .. php:method:: beforeFilter(EventInterface $event) + Llamado durante el evento ``Controller.initialize`` que ocurre antes de cada acción en el controlador. Es un lugar útil para comprobar si hay una sesión activa o inspeccionar los permisos del usuario. @@ -504,13 +504,13 @@ eventos relacionados si los métodos son implementados por tus controladores. El método beforeFilter() será llamado por acciones faltantes. Devolver una respuesta del método ``beforeFilter`` no evitará que otros oyentes - del mismo evento sean llamados. Debes explícitamente :ref:`stop the event `. + del mismo evento sean llamados. Debes explícitamente :ref:`parar el evento `. .. php:method:: beforeRender(EventInterface $event) Llamado durante el evento ``Controller.beforeRender`` que ocurre después de la lógica de acción del controlador, pero antes de que la vista sea renderizada. - Esta devolución de llamada no se usa con frecuencia, pero puede ser necesaria + Este callback no se usa con frecuencia, pero puede ser necesaria si estas llamando :php:meth:`~Cake\\Controller\\Controller::render()` de forma manual antes del final de una acción dada. @@ -518,14 +518,14 @@ eventos relacionados si los métodos son implementados por tus controladores. Llamado durante el evento ``Controller.shutdown`` que se desencadena después de cada acción del controlador, y después de que se complete el renderizado. - ESte es el último método del controlador para ejecutar. + Este es el último método del controlador para ejecutar. Además de las devoluciones de llamada del ciclo de vida del controlador, :doc:`/controllers/components` también proporciona un conjunto similar de devoluciones de llamada. -Recuerda llamar a las devoluciones de llamada de ``AppController`` dentro de las -devoluciones de llamada del controlador hijo para mejores resultados:: +Recuerda llamar a los callbacks de ``AppController`` dentro de los callbacks +del controlador hijo para mejores resultados:: //use Cake\Event\EventInterface; public function beforeFilter(EventInterface $event) From 497aa1359ab8126d07cd73657e6a8b0598a07928 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Tue, 18 Apr 2023 16:09:09 -0300 Subject: [PATCH 07/53] fixing warnings --- es/controllers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/es/controllers.rst b/es/controllers.rst index a0f24b8867..3a5d2474be 100644 --- a/es/controllers.rst +++ b/es/controllers.rst @@ -564,7 +564,7 @@ y se llamarán a los métodos de acción. ``Controller::middleware()`` fue agregado. Más sobre controladores -=================== +======================= .. toctree:: :maxdepth: 1 From 2c50d4d49261d83a7656526511f0e44c1d3ce4b8 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Tue, 18 Apr 2023 16:24:50 -0300 Subject: [PATCH 08/53] fixing warning --- es/controllers.rst | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/es/controllers.rst b/es/controllers.rst index 3a5d2474be..0e993037f2 100644 --- a/es/controllers.rst +++ b/es/controllers.rst @@ -369,7 +369,7 @@ de estado de una respuesta y la devuelve. Deberías devolver la respuesta creada por ``redirect()`` para que CakePHP envíe la redirección en vez de completar la acción del controlador y renderizar la vista. -Puedes redigir usando los valores :term:`routing array`:: +Puedes redigir usando los valores de un array ordenado:: return $this->redirect([ 'controller' => 'Orders', @@ -399,9 +399,6 @@ Usando el segundo parámetro puede definir un código de estatus para tu redirec // Haz un 303 (Ver otro) return $this->redirect('/order/confirm', 303); -Mira la sección :ref:`redirect-component-events` para saber como redirigir fuera -del ciclo de vida del manejador. - Reenviando a un acción en el mismo controlador ---------------------------------------------- @@ -441,8 +438,6 @@ Paginación de un modelo Este método se utiliza para paginar los resultados obtenidos por tus modelos. Puedes especificar tamaño de páginas, condiciones de búsqueda del modelo y más. -Ver la sección :doc:`pagination ` para más detalle de como -usar ``paginate()``. El atributo ``$paginate`` te da una manera de personalizar cómo ``paginate()`` se comporta:: @@ -504,7 +499,7 @@ eventos relacionados si los métodos son implementados por tus controladores. El método beforeFilter() será llamado por acciones faltantes. Devolver una respuesta del método ``beforeFilter`` no evitará que otros oyentes - del mismo evento sean llamados. Debes explícitamente :ref:`parar el evento `. + del mismo evento sean llamados. Debes explícitamente parar el evento. .. php:method:: beforeRender(EventInterface $event) From 4ceb2bc9ca1c7dabba5b83317454978d478be313 Mon Sep 17 00:00:00 2001 From: Reinaldo Borin Date: Wed, 26 Apr 2023 08:26:33 -0300 Subject: [PATCH 09/53] Update saving-data.rst Misspelled. The correct one to converting word is "convertendo", not "conventendo". (Portuguese) --- pt/orm/saving-data.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pt/orm/saving-data.rst b/pt/orm/saving-data.rst index 7a12e19dcd..0ba286333c 100644 --- a/pt/orm/saving-data.rst +++ b/pt/orm/saving-data.rst @@ -361,7 +361,7 @@ Ao converter dados hasMany, você pode desativar a criação de nova entidade, u a opção ``onlyIds`. Quando ativada, esta opção restringe transformação de hasMany para apenas usar a chave ``_ids`` e ignorar todos os outros dados. -Conventendo Vários Registros +Convertendo Vários Registros ---------------------------- Ao criar formulários que cria/atualiza vários registros ao mesmo tempo, você pode usar From ef37608e50b737927e1cebc94bdc9040c935ec9e Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 28 Apr 2023 00:08:09 -0400 Subject: [PATCH 10/53] Trailing newline to trigger build. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 633602db13..f536f8f251 100644 --- a/README.md +++ b/README.md @@ -146,3 +146,4 @@ Making Search Work Locally * Start elasticsearch with the default configuration. * Populate the search using tooling found in the [cakephp docs builder](https://github.com/cakephp/docs-builder) project. * You should now be able to search the docs using elasticsearch. + From 59dd98b5bab2e4fb130465e0012feed61ccace02 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sat, 6 May 2023 00:03:22 +0530 Subject: [PATCH 11/53] Improve cache fallback explanation. Update the description to clarify the the decision to switch to fallback is done when initializing an engine instance, not when writing to one. --- en/core-libraries/caching.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/en/core-libraries/caching.rst b/en/core-libraries/caching.rst index 74d5857a1a..a2bb023eb4 100644 --- a/en/core-libraries/caching.rst +++ b/en/core-libraries/caching.rst @@ -214,9 +214,9 @@ the ``fallback`` configuration key:: 'fallback' => 'default', ]); -If the Redis server unexpectedly failed, writing to the ``redis`` cache -configuration would fall back to writing to the ``default`` cache configuration. -If writing to the ``default`` cache configuration *also* failed in this scenario, the +If initializing the ``RedisEngine`` instance fails, the ``redis`` cache configuration +would fall back to using the ``default`` cache configuration. If initializing the +engine for the ``default`` cache configuration *also* fails, in this scenario the engine would fall back once again to the ``NullEngine`` and prevent the application from throwing an uncaught exception. From a1cc0055b7084d47a5361628967ddbb818f94acd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zo=C3=AB=20Blade?= Date: Wed, 17 May 2023 10:05:12 +0100 Subject: [PATCH 12/53] Fix syntax --- en/views/themes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/views/themes.rst b/en/views/themes.rst index cade3aaa1f..75fcec0925 100644 --- a/en/views/themes.rst +++ b/en/views/themes.rst @@ -3,7 +3,7 @@ Themes Themes in CakePHP are simply plugins that focus on providing template files. See the section on :ref:`plugin-create-your-own`. -You can take advantage of themes, making allowing you to switch the look and feel of +You can take advantage of themes, allowing you to switch the look and feel of your page quickly. In addition to template files, they can also provide helpers and cells if your theming requires that. When using cells and helpers from your theme, you will need to continue using the :term:`plugin syntax`. From abf14c1d612e322d73296b958fb25cb8dac6708a Mon Sep 17 00:00:00 2001 From: Gerhard Lechner Date: Thu, 18 May 2023 11:43:58 +0200 Subject: [PATCH 13/53] Change `strtouppercase()` to `strtoupper()` --- en/orm/entities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/orm/entities.rst b/en/orm/entities.rst index d0479cb892..b1a9870f6f 100644 --- a/en/orm/entities.rst +++ b/en/orm/entities.rst @@ -221,7 +221,7 @@ looping mutator methods. For example:: { $this->slug = Text::slug($title); - return strtouppercase($title); + return strtoupper($title); } } From 4667d322642fddc3e5db50b0ff20d1fdae0cfca9 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Mon, 22 May 2023 19:44:18 -0300 Subject: [PATCH 14/53] translated to 'Using Other Components in your Component' --- es/controllers/components.rst | 261 +++++++++++++++++++++++++++++++++- 1 file changed, 254 insertions(+), 7 deletions(-) diff --git a/es/controllers/components.rst b/es/controllers/components.rst index 486504b6c5..5ceea153cf 100644 --- a/es/controllers/components.rst +++ b/es/controllers/components.rst @@ -1,14 +1,261 @@ -Components -########## +Componentes +########### + +Los componentes son paquetes de lógica que se comparten entre los controladores. +CakePHP viene un con fantástico conjunto de componentes básicos que puedes usar +para ayudar en varias tareas comunes. También puedes crear tus propios componentes. +Si te encuentras queriendo copiar y pegar cosas entre componentes, deberías considerar +crear tu propio componente que contenga la funcionalidad. Crear componentes mantiene +el código del controlador limpio y te permite rehusar código entre los diferentes +controladores. + +Para más información sobre componentes incluidos en CakePHP, consulte el capítulo +de cada componente: + +.. toctree:: + :maxdepth: 1 + + /controllers/components/authentication + /controllers/components/flash + /controllers/components/security + /controllers/components/pagination + /controllers/components/request-handling + /controllers/components/form-protection + /controllers/components/check-http-cache + +.. _configuring-components: + +Configurando componentes +======================== + +Muchos de los componentes principales requieren configuración. Algunos ejemplos +de componentes que requieren configuración son :doc:`/controllers/components/security` +y :doc:`/controllers/components/form-protection`. La configuración para estos +componentes, y para los componentes en general, es usualmente hecho a través ``loadComponent()`` +en el método ``initialize()`` del controlador o a través del array ``$components``:: + + class PostsController extends AppController + { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('FormProtection', [ + 'unlockedActions' => ['index'], + ]); + $this->loadComponent('Csrf'); + } + + } + +También puedes configurar los componentes en tiempo de ejecución usando el método +``setConfig()``. A veces, esto es hecho en el método ``beforeFilter()`` del controlador. +Lo anterior podría ser también expresado como:: + + public function beforeFilter(EventInterface $event) + { + $this->FormProtection->setConfig('unlockedActions', ['index']); + } + +Al igual que los helpers, componentes implementan los métodos ``getConfig()`` y +``setConfig()`` para leer y escribir los datos de configuración:: + + // Lee los datos de configuración. + $this->FormProtection->getConfig('unlockedActions'); + + // Escribe los datos de configuración + $this->Csrf->setConfig('cookieName', 'token'); + +Como los helpers, los componentes fusionarán automáticamente su propiedad ``$_defaultConfig`` +con la configuración del controlador para crear la propiedad ``$_config`` que es +accesible con ``getConfig()`` y ``setConfig()``. + +Componentes de alias +-------------------- + +Una configuración común para usar es la opción ``className``, que te permite +componentes de alias. Esta característica es útil cuando quieres reemplazar ``$this->Auth`` +u otra referencia común de componente con una implementación personalizada:: + + // src/Controller/PostsController.php + class PostsController extends AppController + { + public function initialize(): void + { + $this->loadComponent('Auth', [ + 'className' => 'MyAuth' + ]); + } + } + + // src/Controller/Component/MyAuthComponent.php + use Cake\Controller\Component\AuthComponent; + + class MyAuthComponent extends AuthComponent + { + // Agrega tu código para sobreescribir el AuthComponent principal + } + +Lo de arriba haría *alias* ``MyAuthComponent`` a ``$this->Auth`` en tus controladores. + +.. note:: + El alias de un componente reemplaza esa instancia en cualquier lugar donde se + use ese componente, incluso dentro de otros componentes. + +Carga de componentes sobre la marcha +------------------------------------ + +Es posible que no necesites todos tus componentes disponibles en cada acción del +controlador. En situaciones como estas, puedes cargar un componente en tiempo de +ejecución usando el método ``loadComponent()`` en tu controlador:: + + // En una acción del controlador + $this->loadComponent('OneTimer'); + $time = $this->OneTimer->getTime(); .. note:: - La documentación no es compatible actualmente con el idioma español en esta página. - Por favor, siéntase libre de enviarnos un pull request en - `Github `_ o utilizar el botón **Improve this Doc** para proponer directamente los cambios. + Ten en cuenta que los componentes cargados sobre la marcha no perderán devoluciones + de llamadas. Si te basas en que las devoluciones de llamada ``beforeFilter`` o + ``startup`` serán llamadas, necesitarás llamarlas manualmente dependiendo de + cuándo cargas tu componente. + +Uso de componentes +================== + +Una vez que hayas incluido algunos componentes a tu controlador, usarlos es bastante +simple. Cada componente que uses se exponen como una propiedad en tu controlador. +Si cargaste el :php:class:`Cake\\Controller\\Component\\FlashComponent` en tu controlador, +puedes acceder a él así:: + + class PostsController extends AppController + { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Flash'); + } + + public function delete() + { + if ($this->Post->delete($this->request->getData('Post.id')) { + $this->Flash->success('Post deleted.'); + return $this->redirect(['action' => 'index']); + } + } + } + +.. note:: + + Dado que tanto los modelos como los componentes se agregan a los controladores + como propiedades, comparten el mismo 'espacio de nombres'. Asegúrate de no + dar a un componente y un modelo el mismo nombre. + +.. _creating-a-component: + +Creando un componente +===================== + +Supongamos que nuestra aplicación necesita realizar una operación matemática compleja +en muchas partes diferentes de la aplicación. Podríamos crear un componente para +albergar esta lógica compartida para su uso en muchos controladores diferentes. + +El primer paso es crear un nuevo archivo de componente y clase. Crea el archivo en +**src/Controller/Component/MathComponent.php**. La estructura básica para el componente +debería verse algo como esto:: + + namespace App\Controller\Component; + + use Cake\Controller\Component; + + class MathComponent extends Component + { + public function doComplexOperation($amount1, $amount2) + { + return $amount1 + $amount2; + } + } + +.. note:: + + Todos los componentes deben extender de :php:class:`Cake\\Controller\\Component`. + De lo contrario, se disparará una excepción. + +Incluyendo tu componente en tus controladores +--------------------------------------------- + +Una vez que nuestro componente está terminado, podemos usarlo en los controladores +de la aplicación cargándolo durante el método ``initialize()`` del controlador. +Una vez cargado, el controlador recibirá un nuevo atributo con el nombre del +componente, a través del cual podemos acceder a una instancia del mismo:: + + // En un controlador + // Haz que el nuevo componente esté disponible en $this->Math, + // así como el estándar $this->Csrf + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Math'); + $this->loadComponent('Csrf'); + } + +Al incluir componentes en un controlador, también puedes declarar un conjunto de +parámetros que se pasarán al constructor del componente. Estos parámetros pueden +ser manejados por el componente:: + + // En tu controlador. + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Math', [ + 'precision' => 2, + 'randomGenerator' => 'srand' + ]); + $this->loadComponent('Csrf'); + } + +Lo anterior pasaría el array que contiene precision y randomGenerator a ``MathComponent::initialize()`` +en el parámetro ``$config``. + +Usando otros componentes en tu componente +----------------------------------------- + +A veces, uno de tus componentes necesita usar otro componente. Puedes cargar otros +componentes agregándolos a la propiedad `$components`:: + + // src/Controller/Component/CustomComponent.php + namespace App\Controller\Component; + + use Cake\Controller\Component; + + class CustomComponent extends Component + { + // The other component your component uses + protected $components = ['Existing']; + + // Execute any other additional setup for your component. + public function initialize(array $config): void + { + $this->Existing->foo(); + } + + public function bar() + { + // ... + } + } + + // src/Controller/Component/ExistingComponent.php + namespace App\Controller\Component; + + use Cake\Controller\Component; - Usted puede hacer referencia a la versión en Inglés en el menú de selección superior - para obtener información sobre el tema de esta página. + class ExistingComponent extends Component + { + public function foo() + { + // ... + } + } .. toctree:: :maxdepth: 1 From ad9994990fdbbb44e00c132779266980f6694a79 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Tue, 23 May 2023 11:14:57 -0300 Subject: [PATCH 15/53] first version finiched --- es/controllers/components.rst | 94 +++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/es/controllers/components.rst b/es/controllers/components.rst index 5ceea153cf..48d4503844 100644 --- a/es/controllers/components.rst +++ b/es/controllers/components.rst @@ -229,10 +229,10 @@ componentes agregándolos a la propiedad `$components`:: class CustomComponent extends Component { - // The other component your component uses + // El otro componente que tu componente usa protected $components = ['Existing']; - // Execute any other additional setup for your component. + // Ejecuta cualquier otra configuración adicional para tu componente. public function initialize(array $config): void { $this->Existing->foo(); @@ -257,17 +257,89 @@ componentes agregándolos a la propiedad `$components`:: } } -.. toctree:: - :maxdepth: 1 +.. note:: - /controllers/components/authentication - /controllers/components/cookie - /controllers/components/csrf - /controllers/components/flash - /controllers/components/security - /controllers/components/pagination - /controllers/components/request-handling + A diferencia de un componente incluido en un controlador, no se activarán + devoluciones de llamada en el componente de un componente. + +Accediendo al controlador de un componente +------------------------------------------ + +Desde dentro de un componente, puedes acceder al controlador actual a través del +registro:: + + $controller = $this->getController(); + +Devoluciones de llamadas de componentes +======================================= + +Los componentes también ofrecen algunas devoluciones de llamadas de ciclo de vida +de las solicitudes que les permiten aumentar el ciclo de solicitud. + +.. php:method:: beforeFilter(EventInterface $event) + + Es llamado antes que el método beforeFilter del controlador, pero *después* + del método initialize() del controlador. + +.. php:method:: startup(EventInterface $event) + + Es llamado después del método beforeFilter del controlador, pero antes de que + el controlador ejecute la acción actual del manejador. + +.. php:method:: beforeRender(EventInterface $event) + + Es llamado después de que el controlador ejecute la lógica de la acción + solicitada, pero antes de que el controlador renderize las vistas y el diseño. + +.. php:method:: shutdown(EventInterface $event) + + Es llamado antes de enviar la salida al navegador. + +.. php:method:: beforeRedirect(EventInterface $event, $url, Response $response) + + Es llamado cuando el método de redirección del controlador es llamado pero + antes de cualquier otra acción. Si este método devuelve ``false`` el controlador + no continuará en redirigir la petición. Los parámetros $url y $response permiten + modificar e inspeccionar la ubicación o cualquier otro encabezado en la respuesta. + +.. _redirect-component-events: + +Usando redireccionamiento en eventos de componentes +=================================================== + +Para redirigir desde dentro de un método de devolución de llamada de un componente, +puedes usar lo siguiente:: + + public function beforeFilter(EventInterface $event) + { + $event->stopPropagation(); + return $this->getController()->redirect('/'); + } + +Al detener el evento, le haces saber a CakePHP que no quieres ninguna otra devolución +de llamada de componente para ejecutar, y que el controlador no debe manejar la acción +más lejos. A partir de 4.1.0 puedes generar una ``RedirectException`` para señalar +una redirección:: + + use Cake\Http\Exception\RedirectException; + use Cake\Routing\Router; + + public function beforeFilter(EventInterface $event) + { + throw new RedirectException(Router::url('/')) + } + +Generar una excepción detendrá todos los demás detectores de eventos y creará +una nueva respuesta que no conserva ni hereda ninguno de los encabezados de la respuesta +actual. Al generar una ``RedirectException`` puedes incluir encabezados adicionales:: + + throw new RedirectException(Router::url('/'), 302, [ + 'Header-Key' => 'value', + ]); + +.. versionadded:: 4.1.0 .. meta:: :title lang=es: Components :keywords lang=es: array controller,core libraries,authentication request,array name,access control lists,public components,controller code,core components,cookiemonster,login cookie,configuration settings,functionality,logic,sessions,cakephp,doc + From 171cf14f704b15caa798e0b7877c52b79bbd9cde Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Sun, 28 May 2023 17:57:17 -0300 Subject: [PATCH 16/53] fixed errors --- es/controllers/components.rst | 8 ++++---- es/controllers/components/check-http-cache.rst | 11 +++++++++++ .../components/{cookie.rst => form-protection.rst} | 8 ++++---- 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 es/controllers/components/check-http-cache.rst rename es/controllers/components/{cookie.rst => form-protection.rst} (62%) diff --git a/es/controllers/components.rst b/es/controllers/components.rst index 48d4503844..6f3a53ada1 100644 --- a/es/controllers/components.rst +++ b/es/controllers/components.rst @@ -65,14 +65,14 @@ Al igual que los helpers, componentes implementan los métodos ``getConfig()`` y // Escribe los datos de configuración $this->Csrf->setConfig('cookieName', 'token'); -Como los helpers, los componentes fusionarán automáticamente su propiedad ``$_defaultConfig`` +Al igual que con los helpers, los componentes fusionarán automáticamente su propiedad ``$_defaultConfig`` con la configuración del controlador para crear la propiedad ``$_config`` que es accesible con ``getConfig()`` y ``setConfig()``. Componentes de alias -------------------- -Una configuración común para usar es la opción ``className``, que te permite +Una configuración común para usar es la opción ``className``, que te permite utilizar componentes de alias. Esta característica es útil cuando quieres reemplazar ``$this->Auth`` u otra referencia común de componente con una implementación personalizada:: @@ -125,7 +125,7 @@ Uso de componentes Una vez que hayas incluido algunos componentes a tu controlador, usarlos es bastante simple. Cada componente que uses se exponen como una propiedad en tu controlador. Si cargaste el :php:class:`Cake\\Controller\\Component\\FlashComponent` en tu controlador, -puedes acceder a él así:: +puedes acceder a él de esta forma:: class PostsController extends AppController { @@ -340,6 +340,6 @@ actual. Al generar una ``RedirectException`` puedes incluir encabezados adiciona .. versionadded:: 4.1.0 .. meta:: - :title lang=es: Components + :title lang=es: Componentes :keywords lang=es: array controller,core libraries,authentication request,array name,access control lists,public components,controller code,core components,cookiemonster,login cookie,configuration settings,functionality,logic,sessions,cakephp,doc diff --git a/es/controllers/components/check-http-cache.rst b/es/controllers/components/check-http-cache.rst new file mode 100644 index 0000000000..0324b1a250 --- /dev/null +++ b/es/controllers/components/check-http-cache.rst @@ -0,0 +1,11 @@ +Checking HTTP Cache +=================== + +.. note:: + La documentación no es compatible actualmente con el idioma español en esta página. + + Por favor, siéntase libre de enviarnos un pull request en + `Github `_ o utilizar el botón **Improve this Doc** para proponer directamente los cambios. + + Usted puede hacer referencia a la versión en Inglés en el menú de selección superior + para obtener información sobre el tema de esta página. \ No newline at end of file diff --git a/es/controllers/components/cookie.rst b/es/controllers/components/form-protection.rst similarity index 62% rename from es/controllers/components/cookie.rst rename to es/controllers/components/form-protection.rst index 288f615991..4ccf013abd 100644 --- a/es/controllers/components/cookie.rst +++ b/es/controllers/components/form-protection.rst @@ -1,5 +1,5 @@ -CookieComponent -############### +FormProtection +############## .. note:: La documentación no es compatible actualmente con el idioma español en esta página. @@ -11,5 +11,5 @@ CookieComponent para obtener información sobre el tema de esta página. .. meta:: - :title lang=es: Cookie - :keywords lang=es: array controller,php setcookie,cookie string,controller setup,string domain,default description,string name,session cookie,integers,variables,domain name,null + :title lang=en: FormProtection + :keywords lang=en: configurable parameters,form protection component,configuration parameters,protection features,tighter security,php class,meth,array,submission,security class,disable security,unlockActions \ No newline at end of file From f3d2bd3afba96ae0bd3099b90ad1a761c94413f5 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Sun, 28 May 2023 18:46:16 -0300 Subject: [PATCH 17/53] security.rst translated to spanish --- es/controllers/components/security.rst | 199 +++++++++++++++++++++++-- 1 file changed, 190 insertions(+), 9 deletions(-) diff --git a/es/controllers/components/security.rst b/es/controllers/components/security.rst index 9a0023d5f0..c6c5a1dfee 100644 --- a/es/controllers/components/security.rst +++ b/es/controllers/components/security.rst @@ -1,15 +1,196 @@ -Security -######## +Seguridad +######### + +.. php:class:: SecurityComponent(ComponentCollection $collection, array $config = []) + +El componente de seguridad crea una forma de integrar seguridad más estrechamente +a tu aplicación. Proporciona métodos para diversas tareas como: + +* Restringir qué métodos HTTP acepta tu aplicación. +* Protección contra manipulación de formularios. +* Requerir que se utiliza SSL. +* Limitación de la comunicación entre controladores. + +Como todos los componentes, se configura a través de varios parámetros configurables. +Todas estas propiedades se pueden establecer directamente o a través de métodos setter +del mismo nombre en ``beforeFilter()`` de tu controlador. + +Al usar el componente de seguridad, obtienes automáticamente protección contra la +manipulación de formularios. Los campos token ocultos se insertarán automáticamente +en los formularios y serán verificados por el componente de seguridad. + +Si estas utilizando las funciones de protección de formularios del componente de +seguridad y otros componentes que procesan datos de formularios en sus devoluciones +de llamada ``startup()``, asegúrate de colocar el componente de seguridad antes de +esos componentes en tu método ``initialize()``. .. note:: - La documentación no es compatible actualmente con el idioma español en esta página. - Por favor, siéntase libre de enviarnos un pull request en - `Github `_ o utilizar el botón **Improve this Doc** para proponer directamente los cambios. + Al usar el componente de seguridad, **debes** usar FormHelper para crear tus + formularios. Además, **no** debes reescribir ninguno de los "nombres" de los + campos. El componente de seguridad busca ciertos indicadores que son creados + y manejados por FormHelper (especialmente esos creados en + :php:meth:`~Cake\\View\\Helper\\FormHelper::create()` y + :php:meth:`~Cake\\View\\Helper\\FormHelper::end()`). Es probable que la modificación + dinámica de los campos que se envían en una solicitud POST, como deshabilitar, + borrar o crear nuevos campos a través de JavaScript, haga que la solicitud se + envíe a la devolución de llamada de blackhole. + + Siempre debes verificar el método HTTP que se utiliza antes de ejecutarlo para + evitar efectos secundarios. Debes :ref:`check the HTTP method ` + o usar :php:meth:`Cake\\Http\\ServerRequest::allowMethod()` para asegurarte + de que se utiliza el método HTTP correcto. + +Manejo de devoluciones de llamada blackhole +=========================================== + +.. php:method:: blackHole(Controller $controller, string $error = '', ?SecurityException $exception = null) + +Si una acción está restringida por el componente de seguridad, es 'black-holed' +como una solicitud no válida que dará como resultado un error 400 por defecto. +Puedes configurar este comportamiento seteando la opción de configuración +``blackHoleCallback`` para una función de devolución de llamada en el controlador. + +Al configurar un método de devolución de llamada, puedes personalizar como el +proceso blackhole funciona:: + + public function beforeFilter(EventInterface $event) + { + parent::beforeFilter($event); + + $this->Security->setConfig('blackHoleCallback', 'blackhole'); + } + + public function blackhole($type, SecurityException $exception) + { + if ($exception->getMessage() === 'Request is not SSL and the action is required to be secure') { + // Reword the exception message with a translatable string. + $exception->setMessage(__('Please access the requested page through HTTPS')); + } + + // Vuelve a lanzar la excepción reformulada condicionalmente. + throw $exception; + + // Alternativamente, maneja el error. Por ejemplo, configura un mensaje flash & + // redirige a la versión HTTPS de la página solicitada. + } + +El parámetro ``$type`` puede tener los siguientes valores: + +* 'auth' Indica un error de validación de formulario o un error de discrepancia +entre controlador y acción. +* 'secure' Indica un error de restricción del método SSL. + +Restringir acciones a SSL +========================= + +Esta funcionalidad fue eliminada en :ref:`https-enforcer-middleware`. + +Prevención de manipulación de formularios +========================================= + +Por defecto, ``SecurityComponent`` evita que los usuarios alteren lso formularios +de formas específicas. El ``SecurityComponent`` evitará las siguientes cosas: + +* Los campos desconocidos no podrán ser agregados al formulario. +* Los campos no pueden ser eliminados del formulario. +* Los valores en las entras ocultas no podrán ser modificadas. + +La prevención de este tipo de manipulación se logra trabajando con ``FormHelper`` +y rastreando qué campos hay en un formulario. También se realiza un seguimiento +de los valores de los campos ocultos. Todos estos datos se combinan y se convierten +en un hash. Cuando un formulario es enviado, ``SecurityComponent`` usará los datos +POST para construir la misma estructura y comparar el hash. + +.. note:: + + SecurityComponent **no** evitará que se agreguen/cambien opciones seleccionadas. + Tampoco impedirá que se agreguen/cambien opciones de radio. + +unlockedFields + Establecer en una lista de campos de formulario para excluir de la validación + POST. Los campos se pueden desbloquear en el componente o con :php:meth:`FormHelper::unlockField()`. + Los campos que han sido desbloqueados no están obligados a ser parte del POST + y los campos desbloqueados ocultos no tienen su valores verificados. + +validatePost + Establece en ``false`` para omitir por completo la validación de las solicitudes + POST, esencialmente desactivando las validaciones de los formularios. + +Uso +=== + +La configuración del componente de seguridad generalmente se realizar en las +devoluciones de llamada ``initialize`` o ``beforeFilter()`` del controlador:: + + namespace App\Controller; + + use App\Controller\AppController; + use Cake\Event\EventInterface; + + class WidgetsController extends AppController + { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Security'); + } + + public function beforeFilter(EventInterface $event) + { + parent::beforeFilter($event); + + if ($this->request->getParam('prefix') === 'Admin') { + $this->Security->setConfig('validatePost', false); + } + } + } + +El ejemplo anterior deshabilitaría la prevención de manipulación de formularios +para rutas con prefijo de administrador. + +.. _security-csrf: + +Protección CSRF +=============== + +CSRF o Cross Site Request Forgery es una vulnerabilidad común en las aplicaciones +web. Permite a un atacante capturar y reproducir una solicitud anterior, y a veces, +enviar solicitudes de datos utilizando etiquetas de imagen o recursos en otros +dominios. Para habilitar las funciones de protección CSRF, usa :ref:`csrf-middleware`. + +Deshabilitar la manipulación de formularios para acciones específicas +===================================================================== + +Hay muchos casos en los que querrías deshabilitar la prevención de manipulación +de formularios para una acción (por ejemplo, solicitudes AJAX). Puedes "desbloquear" +estas acciones enumerándolas en ``$this->Security->unlockedActions`` en tu +``beforeFilter()``:: + + namespace App\Controller; + + use App\Controller\AppController; + use Cake\Event\EventInterface; + + class WidgetController extends AppController + { + public function initialize(): void + { + parent::initialize(); + $this->loadComponent('Security'); + } + + public function beforeFilter(EventInterface $event) + { + parent::beforeFilter($event); + + $this->Security->setConfig('unlockedActions', ['edit']); + } + } - Usted puede hacer referencia a la versión en Inglés en el menú de selección superior - para obtener información sobre el tema de esta página. +Este ejemplo deshabilitaría todas las comprobaciones de seguridad para las acciones +de edición. .. meta:: - :title lang=es: Security - :keywords lang=es: configurable parameters,security component,configuration parameters,invalid request,protection features,tighter security,holing,php class,meth,404 error,period of inactivity,csrf,array,submission,security class,disable security,unlockActions + :title lang=es: Seguridad + :keywords lang=es: parámetros configurables, componente de seguridad, parámetros de configuración, solicitud no válida, funciones de protección, seguridad más estricta, holing, clase php, meth, error 404, período de inactividad, csrf, array, envío, clase de seguridad, deshabilitar seguridad, desbloquear acciones From f605b4bb0d678ce74bba76b0b3d06af75c37cde1 Mon Sep 17 00:00:00 2001 From: Sofia Juarez Date: Mon, 29 May 2023 11:54:21 -0300 Subject: [PATCH 18/53] security transltaed --- es/controllers/components/security.rst | 27 +++++++++++--------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/es/controllers/components/security.rst b/es/controllers/components/security.rst index c6c5a1dfee..261c8bd3d4 100644 --- a/es/controllers/components/security.rst +++ b/es/controllers/components/security.rst @@ -3,12 +3,12 @@ Seguridad .. php:class:: SecurityComponent(ComponentCollection $collection, array $config = []) -El componente de seguridad crea una forma de integrar seguridad más estrechamente -a tu aplicación. Proporciona métodos para diversas tareas como: +El componente de seguridad crea una forma de integrar seguridad de forma más estricta +en tu aplicación. Proporciona métodos para diversas tareas como: * Restringir qué métodos HTTP acepta tu aplicación. * Protección contra manipulación de formularios. -* Requerir que se utiliza SSL. +* Requerir que se utilice SSL. * Limitación de la comunicación entre controladores. Como todos los componentes, se configura a través de varios parámetros configurables. @@ -20,7 +20,7 @@ manipulación de formularios. Los campos token ocultos se insertarán automátic en los formularios y serán verificados por el componente de seguridad. Si estas utilizando las funciones de protección de formularios del componente de -seguridad y otros componentes que procesan datos de formularios en sus devoluciones +seguridad y otros componentes que procesan datos de formularios en tus devoluciones de llamada ``startup()``, asegúrate de colocar el componente de seguridad antes de esos componentes en tu método ``initialize()``. @@ -37,7 +37,7 @@ esos componentes en tu método ``initialize()``. envíe a la devolución de llamada de blackhole. Siempre debes verificar el método HTTP que se utiliza antes de ejecutarlo para - evitar efectos secundarios. Debes :ref:`check the HTTP method ` + evitar efectos secundarios. Debes verificar el método HTTP o usar :php:meth:`Cake\\Http\\ServerRequest::allowMethod()` para asegurarte de que se utiliza el método HTTP correcto. @@ -64,7 +64,7 @@ proceso blackhole funciona:: public function blackhole($type, SecurityException $exception) { if ($exception->getMessage() === 'Request is not SSL and the action is required to be secure') { - // Reword the exception message with a translatable string. + // Reformule el mensaje de excepción con un string traducible. $exception->setMessage(__('Please access the requested page through HTTPS')); } @@ -78,23 +78,18 @@ proceso blackhole funciona:: El parámetro ``$type`` puede tener los siguientes valores: * 'auth' Indica un error de validación de formulario o un error de discrepancia -entre controlador y acción. + entre controlador y acción. * 'secure' Indica un error de restricción del método SSL. -Restringir acciones a SSL -========================= - -Esta funcionalidad fue eliminada en :ref:`https-enforcer-middleware`. - Prevención de manipulación de formularios ========================================= -Por defecto, ``SecurityComponent`` evita que los usuarios alteren lso formularios +Por defecto, ``SecurityComponent`` evita que los usuarios alteren los formularios de formas específicas. El ``SecurityComponent`` evitará las siguientes cosas: * Los campos desconocidos no podrán ser agregados al formulario. * Los campos no pueden ser eliminados del formulario. -* Los valores en las entras ocultas no podrán ser modificadas. +* Los valores en las entradas ocultas no podrán ser modificadas. La prevención de este tipo de manipulación se logra trabajando con ``FormHelper`` y rastreando qué campos hay en un formulario. También se realiza un seguimiento @@ -120,7 +115,7 @@ validatePost Uso === -La configuración del componente de seguridad generalmente se realizar en las +La configuración del componente de seguridad generalmente se realiza en las devoluciones de llamada ``initialize`` o ``beforeFilter()`` del controlador:: namespace App\Controller; @@ -157,7 +152,7 @@ Protección CSRF CSRF o Cross Site Request Forgery es una vulnerabilidad común en las aplicaciones web. Permite a un atacante capturar y reproducir una solicitud anterior, y a veces, enviar solicitudes de datos utilizando etiquetas de imagen o recursos en otros -dominios. Para habilitar las funciones de protección CSRF, usa :ref:`csrf-middleware`. +dominios. Para habilitar las funciones de protección CSRF. Deshabilitar la manipulación de formularios para acciones específicas ===================================================================== From 01b41074f557286e9a97a912a78c2b1a26b93ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Thu, 8 Jun 2023 14:33:35 +0200 Subject: [PATCH 19/53] Add note about fetchTable not adding a controller property --- en/controllers.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/en/controllers.rst b/en/controllers.rst index a3b13d9bc0..e4098887e4 100644 --- a/en/controllers.rst +++ b/en/controllers.rst @@ -428,6 +428,11 @@ the controller's default one:: .. versionadded:: 4.3.0 ``Controller::fetchTable()`` was added. Prior to 4.3 you need to use ``Controller::loadModel()``. +.. note:: + + ``Controller::fetchTable()`` does not create a controller property with the name of the table alias, + e.g. ``$this->Articles``, as ``Controller::loadModel()`` does. + Paginating a Model ================== From d3e043e82c72d95a5d2ed4d601ec6b7ee29c3e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Thu, 8 Jun 2023 14:43:28 +0200 Subject: [PATCH 20/53] Add note about fetchTable not adding a controller property to migration guide --- en/appendices/4-3-migration-guide.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/en/appendices/4-3-migration-guide.rst b/en/appendices/4-3-migration-guide.rst index 0138ac40ec..5f7d864585 100644 --- a/en/appendices/4-3-migration-guide.rst +++ b/en/appendices/4-3-migration-guide.rst @@ -86,7 +86,9 @@ ORM - ``ModelAwareTrait::loadModel()`` is deprecated. Use the new ``LocatorAwareTrait::fetchTable()`` instead. For example, in controllers you can do ``$this->fetchTable()`` to get the default table instance or use ``$this->fetchTable('Foos')`` for a non-default table. You can set the ``LocatorAwareTrait::$defaultTable`` - property to specify the default table alias for ``fetchTable()``. + property to specify the default table alias for ``fetchTable()``. But be aware that + ``LocatorAwareTrait::fetchTable()`` does not create a property with the name of the table alias on the + calling object, e.g. ``$this->Articles``, as ``ModelAwareTrait::loadModel()`` does. - Query proxying all ``ResultSetInterface`` methods (including ```CollectionInterface```), which forces fetching results and calls the proxied method on the results, is now deprecated. An example of the deprecated usage is ``$query->combine('id', 'title');``. This should be From 18d9a30897d32d32ec317aa84a5bab750d2bcad9 Mon Sep 17 00:00:00 2001 From: Aamir Shahzad Date: Fri, 23 Jun 2023 05:18:20 +0500 Subject: [PATCH 21/53] Remove single quot because string also contains single quot There's already single quot inside the string "Something didn't work!". So single quot should not be used contain this string, or escape single quot. --- en/core-libraries/logging.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/core-libraries/logging.rst b/en/core-libraries/logging.rst index b4b9ff4d0e..4111274ebf 100644 --- a/en/core-libraries/logging.rst +++ b/en/core-libraries/logging.rst @@ -227,7 +227,7 @@ If a level is not supplied, :php:const:`LOG_ERR` is used which writes to the error log. The default log location is **logs/$level.log**:: // Executing this inside a CakePHP class - $this->log('Something didn't work!'); + $this->log("Something didn't work!"); // Results in this being appended to logs/error.log // 2007-11-02 10:22:02 Error: Something didn't work! From 5ac6039425524d5dd26cd50c3dca0f404d502929 Mon Sep 17 00:00:00 2001 From: celsowm Date: Sat, 24 Jun 2023 10:00:51 -0300 Subject: [PATCH 22/53] Update query-builder.rst same example added on cake3 docs yesterday :) --- en/orm/query-builder.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/en/orm/query-builder.rst b/en/orm/query-builder.rst index 93f3c298dd..86b9c95e96 100644 --- a/en/orm/query-builder.rst +++ b/en/orm/query-builder.rst @@ -1076,6 +1076,14 @@ use the ``identifier()`` method:: return $exp->gt('population', 100000); }); +You can use ``identifier()`` in comparisons to aggregations too:: + + $query = $this->Orders->find(); + $query->select(['Customers.customer_name', 'total_orders' => $query->func()->count('Orders.order_id')]) + ->contain('Customers') + ->group(['Customers.customer_name']) + ->having(['total_orders >=' => $query->identifier('Customers.minimum_order_count')]); + .. warning:: To prevent SQL injections, Identifier expressions should never have From 015ac977d76bfdfbe5e2dce01e991e585f041d73 Mon Sep 17 00:00:00 2001 From: celsowm Date: Sat, 24 Jun 2023 13:48:54 -0300 Subject: [PATCH 23/53] Update retrieving-data-and-resultsets.rst An example of how to specify conditions when using loadInto() --- en/orm/retrieving-data-and-resultsets.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/en/orm/retrieving-data-and-resultsets.rst b/en/orm/retrieving-data-and-resultsets.rst index b691a14af0..16abab7b70 100644 --- a/en/orm/retrieving-data-and-resultsets.rst +++ b/en/orm/retrieving-data-and-resultsets.rst @@ -1071,6 +1071,15 @@ can load additional associations using ``loadInto()``:: $articles = $this->Articles->find()->all(); $withMore = $this->Articles->loadInto($articles, ['Comments', 'Users']); +It is possible to restrict the data returned by the associations and filter them +by conditions. To specify conditions, pass an anonymous function that receives +as the first argument a query object, ``\Cake\ORM\Query``:: + + $user = $this->Users->get($id); + $withMore = $this->Users->loadInto($user, ['Posts' => function (Query $query) { + return $query->where(['Posts.status' => 'published']); + }]); + You can eager load additional data into a single entity, or a collection of entities. From 9c64cd46864eb72cff8e9c982fb61d63ad250ce4 Mon Sep 17 00:00:00 2001 From: celsowm Date: Sun, 25 Jun 2023 22:54:56 -0300 Subject: [PATCH 24/53] Update query-builder.rst An example of how to use $collation param --- en/orm/query-builder.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/en/orm/query-builder.rst b/en/orm/query-builder.rst index 86b9c95e96..79bf4a1cc9 100644 --- a/en/orm/query-builder.rst +++ b/en/orm/query-builder.rst @@ -1089,6 +1089,23 @@ You can use ``identifier()`` in comparisons to aggregations too:: To prevent SQL injections, Identifier expressions should never have untrusted data passed into them. +Collation +--------------------------------- + +In situations that you need to deal with accented characters, multilingual data +or case-sensitive comparisons, you can use the ``$collation`` parameter of ``IdentifierExpression`` +or ``StringExpression`` to apply a character expression to a certain collation:: + + use Cake\Database\Expression\IdentifierExpression; + + $collation = 'Latin1_general_CI_AI'; //sql server example + $query = $cities->find() + ->where(function (QueryExpression $exp, Query $q) use ($collation) { + return $exp->like(new IdentifierExpression('name', $collation), '%São José%'); + }); + # WHERE name COLLATE LIKE Latin1_general_CI_AI "%São José%" + + Automatically Creating IN Clauses --------------------------------- From 5033dbb8ea90d7d79de4f6a50cb34cf6d790b63f Mon Sep 17 00:00:00 2001 From: celsowm Date: Mon, 26 Jun 2023 21:15:28 -0300 Subject: [PATCH 25/53] Update query-builder.rst two examples of setConjunction() --- en/orm/query-builder.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/en/orm/query-builder.rst b/en/orm/query-builder.rst index 79bf4a1cc9..afb28aa9e2 100644 --- a/en/orm/query-builder.rst +++ b/en/orm/query-builder.rst @@ -1177,6 +1177,35 @@ expression objects to add snippets of SQL to your queries:: Using expression objects leaves you vulnerable to SQL injection. You should never use untrusted data into expressions. +Expression Conjuction +----------------------- + +It is possible to Changes for changing the conjunction used to join conditions in +a query expression using the method ``setConjunction``:: + + $query = $articles->find(); + $expr = $query->newExpr(['1','1'])->setConjunction('+'); + $query->select(['two' => $expr]); + +And can be used combined with aggregations too:: + + $query = $products->find(); + $query->select(function ($query) { + $stockQuantity = $query->func()->sum('Stocks.quantity'); + $totalStockValue = $query->func()->sum( + $query->newExpr(['Stocks.quantity', 'Products.unit_price']) + ->setConjunction('*') + ); + return [ + 'Products.name', + 'stock_quantity' => $stockQuantity, + 'Products.unit_price', + 'total_stock_value' => $totalStockValue + ]; + }) + ->innerJoinWith('Stocks') + ->groupBy(['Products.id', 'Products.name', 'Products.unit_price']); + Getting Results =============== From 6c2d92f328186df96e475f8c52c405c6cc055314 Mon Sep 17 00:00:00 2001 From: celsowm Date: Mon, 26 Jun 2023 21:25:22 -0300 Subject: [PATCH 26/53] Update query-builder.rst fix text --- en/orm/query-builder.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/en/orm/query-builder.rst b/en/orm/query-builder.rst index afb28aa9e2..28e3685229 100644 --- a/en/orm/query-builder.rst +++ b/en/orm/query-builder.rst @@ -1180,8 +1180,8 @@ expression objects to add snippets of SQL to your queries:: Expression Conjuction ----------------------- -It is possible to Changes for changing the conjunction used to join conditions in -a query expression using the method ``setConjunction``:: +It is possible to change the conjunction used to join conditions in a query +expression using the method ``setConjunction``:: $query = $articles->find(); $expr = $query->newExpr(['1','1'])->setConjunction('+'); From 09165a6054fe01adebc2335273ab3f8d9689e338 Mon Sep 17 00:00:00 2001 From: celsowm Date: Sun, 2 Jul 2023 10:35:29 -0300 Subject: [PATCH 27/53] Update query-builder.rst cast() on SQL Functions list --- en/orm/query-builder.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/en/orm/query-builder.rst b/en/orm/query-builder.rst index 28e3685229..440df99acc 100644 --- a/en/orm/query-builder.rst +++ b/en/orm/query-builder.rst @@ -317,7 +317,9 @@ You can access existing wrappers for several SQL functions through ``Query::func ``max()`` Calculate the max of a column. `Assumes arguments are literal values.` ``count()`` - Calculate the count. `Assumes arguments are literal values.` + Calculate the count. `Assumes arguments are literal values.`\ +``cast()`` + Convert a field or expression from one data type to another. ``concat()`` Concatenate two values together. `Assumes arguments are bound parameters.` ``coalesce()`` From 4e575562b697c883b0921270dc27d56f473d9a9a Mon Sep 17 00:00:00 2001 From: celsowm Date: Mon, 3 Jul 2023 15:54:35 -0300 Subject: [PATCH 28/53] Update query-builder.rst removing \ --- en/orm/query-builder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/orm/query-builder.rst b/en/orm/query-builder.rst index 440df99acc..156ffda186 100644 --- a/en/orm/query-builder.rst +++ b/en/orm/query-builder.rst @@ -317,7 +317,7 @@ You can access existing wrappers for several SQL functions through ``Query::func ``max()`` Calculate the max of a column. `Assumes arguments are literal values.` ``count()`` - Calculate the count. `Assumes arguments are literal values.`\ + Calculate the count. `Assumes arguments are literal values.` ``cast()`` Convert a field or expression from one data type to another. ``concat()`` From dc76ad258052d0e52bd6bd58665609093e4ac376 Mon Sep 17 00:00:00 2001 From: rrd Date: Wed, 5 Jul 2023 18:45:54 +0200 Subject: [PATCH 29/53] fix typo --- en/appendices/fixture-upgrade.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/appendices/fixture-upgrade.rst b/en/appendices/fixture-upgrade.rst index 989e3c1b0d..6e9dca7ba3 100644 --- a/en/appendices/fixture-upgrade.rst +++ b/en/appendices/fixture-upgrade.rst @@ -18,7 +18,7 @@ To upgrade to the new fixture system, you need to make a few updates: This removes schema management from the test fixture manager. Instead your application needs to create/update schema at the beginning of each test run. -#. Next, update ``tests/boostrap.php`` to create schema. There are a few +#. Next, update ``tests/bootstrap.php`` to create schema. There are a few different ways to create schema. Refer to :ref:`creating-test-database-schema` for the methods provided by CakePHP. #. Then, remove all the ``$fields`` and ``$import`` properties from your fixtures. From bac48ebc82a513203abf3bf467fdc36be331c1d3 Mon Sep 17 00:00:00 2001 From: Marc Wilhelm Date: Thu, 6 Jul 2023 15:42:32 +0200 Subject: [PATCH 30/53] Fix \Cake\Filesystem\Folder::copy() documentation Fix \Cake\Filesystem\Folder::copy() parameter documentation. https://github.com/cakephp/docs/issues/7643 --- en/core-libraries/file-folder.rst | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/en/core-libraries/file-folder.rst b/en/core-libraries/file-folder.rst index c268e96f27..5378f97cd2 100644 --- a/en/core-libraries/file-folder.rst +++ b/en/core-libraries/file-folder.rst @@ -94,24 +94,30 @@ Folder API $dir = new Folder(); $dir->chmod('/path/to/folder', 0755, true, ['skip_me.php']); -.. php:method:: copy(array|string $options = []) +.. php:method:: copy(string $to, array $options = []) - Recursively copy a directory. The only parameter $options can either - be a path into copy to or an array of options:: + Recursively copy a directory. The parameter $to is the location to copy to. The $options an array of options:: $folder1 = new Folder('/path/to/folder1'); $folder1->copy('/path/to/folder2'); // Will put folder1 and all its contents into folder2 $folder = new Folder('/path/to/folder'); - $folder->copy([ - 'to' => '/path/to/new/folder', + $folder->copy('/path/to/new/folder', [ 'from' => '/path/to/copy/from', // Will cause a cd() to occur 'mode' => 0755, 'skip' => ['skip-me.php', '.git'], 'scheme' => Folder::SKIP // Skip directories/files that already exist. ]); + Available options: + + * ``from`` The directory to copy from, this will cause a cd() to occur, changing the results of pwd(). + * ``mode`` The mode to copy the files/directories with as integer, e.g. 0775. + * ``skip`` Files/directories to skip. + * ``scheme`` Folder::MERGE, Folder::OVERWRITE, Folder::SKIP + * ``recursive`` Whether to copy recursively or not (default: true - recursive) + There are 3 supported schemes: * ``Folder::SKIP`` skip copying/moving files & directories that exist in the From 8640d32b5095ebd372926eccbd6f4fc437764c4b Mon Sep 17 00:00:00 2001 From: othercorey Date: Fri, 7 Jul 2023 00:09:36 -0500 Subject: [PATCH 31/53] Update supported php version --- config/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/conf.py b/config/conf.py index 0f68f4acf2..92922b87fd 100644 --- a/config/conf.py +++ b/config/conf.py @@ -112,6 +112,6 @@ epub_tocdepth = 2 rst_epilog = """ -.. |phpversion| replace:: **8.1** +.. |phpversion| replace:: **8.2** .. |minphpversion| replace:: 7.4 """ From 2381935a5e1935c10594764c2f1de3d463bbc277 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:04:54 +0000 Subject: [PATCH 32/53] Bump sphinxcontrib-phpdomain from 0.11.0 to 0.11.1 Bumps [sphinxcontrib-phpdomain](https://github.com/markstory/sphinxcontrib-phpdomain) from 0.11.0 to 0.11.1. - [Release notes](https://github.com/markstory/sphinxcontrib-phpdomain/releases) - [Changelog](https://github.com/markstory/sphinxcontrib-phpdomain/blob/master/CHANGES) - [Commits](https://github.com/markstory/sphinxcontrib-phpdomain/compare/0.11.0...0.11.1) --- updated-dependencies: - dependency-name: sphinxcontrib-phpdomain dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index a92deee0a2..9dbc679f1d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ docutils==0.17.1 sphinx==4.5.0 -sphinxcontrib-phpdomain==0.11.0 +sphinxcontrib-phpdomain==0.11.1 cakephpsphinx>=0.1.57,<1.0 From a22ae82e8d7735305fdaf5da42837c4b3b82e77f Mon Sep 17 00:00:00 2001 From: zachee54 Date: Fri, 6 Jan 2023 14:18:21 +0100 Subject: [PATCH 33/53] [fr] Typo error in email.rst --- fr/core-libraries/email.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fr/core-libraries/email.rst b/fr/core-libraries/email.rst index e990b4c379..7711a1cbb4 100644 --- a/fr/core-libraries/email.rst +++ b/fr/core-libraries/email.rst @@ -461,7 +461,7 @@ Vous pourriez par exemple ajouter ceci à votre ``UserMailer``:: L'objet mailer sera ainsi enregistré en tant qu'écouteur (*listener*) d'événement et la méthode ``onRegistration()`` sera appelée chaque fois que -l'événement ``Model.afterSave`` sera déclenché. +l'événement ``Model.afterSave`` sera déclenché:: // attache un gestionnaire d'événements sur Users $this->Users->getEventManager()->on($this->getMailer('User')); From 2f37874c165ca47092b469c7fb4220a4af13ef03 Mon Sep 17 00:00:00 2001 From: zachee54 Date: Tue, 28 Feb 2023 17:47:28 +0100 Subject: [PATCH 34/53] Fix BETWEEN expression instantiation example The indicated syntax didn't exist. --- en/orm/query-builder.rst | 2 +- fr/orm/query-builder.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/en/orm/query-builder.rst b/en/orm/query-builder.rst index 156ffda186..da2d2a1f56 100644 --- a/en/orm/query-builder.rst +++ b/en/orm/query-builder.rst @@ -530,7 +530,7 @@ following:: $sizing = $query->newExpr()->case() ->when(['population <' => 100000]) ->then('SMALL') - ->when($q->between('population', 100000, 999000)) + ->when($query->newExpr()->between('population', 100000, 999000)) ->then('MEDIUM') ->when(['population >=' => 999001]) ->then('LARGE'); diff --git a/fr/orm/query-builder.rst b/fr/orm/query-builder.rst index 86515ee034..4e44be3748 100644 --- a/fr/orm/query-builder.rst +++ b/fr/orm/query-builder.rst @@ -560,7 +560,7 @@ pourrions le faire ainsi:: $sizing = $query->newExpr()->case() ->when(['population <' => 100000]) ->then('PETITE') - ->when($q->between('population', 100000, 999000)) + ->when($query->newExpr()->between('population', 100000, 999000)) ->then('MOYENNE') ->when(['population >=' => 999001]) ->then('GRANDE'); From 1b51e1d73dfc0a398704854b1ec87bb188c14d87 Mon Sep 17 00:00:00 2001 From: zachee54 Date: Wed, 28 Jun 2023 22:10:10 +0200 Subject: [PATCH 35/53] [fr] Update saving-data.rst --- fr/orm/saving-data.rst | 1015 ++++++++++++++++++++-------------------- 1 file changed, 515 insertions(+), 500 deletions(-) diff --git a/fr/orm/saving-data.rst b/fr/orm/saving-data.rst index ba91caae8f..e06e52f782 100644 --- a/fr/orm/saving-data.rst +++ b/fr/orm/saving-data.rst @@ -9,13 +9,13 @@ Sauvegarder les Données Après avoir :doc:`chargé vos données` vous voudrez probablement mettre à jour et sauvegarder les changements. -Coup d'Oeil sur Enregistrement des Données -========================================== +Coup d'Oeil sur l'Enregistrement des Données +============================================ Les applications ont habituellement deux façons d'enregistrer les données. -La première est évidemment via des formulaires web et l'autre en générant ou -modifiant directement les données dans le code pour l'envoyer à la base de -données. +La première est évidemment d'utiliser des formulaires web et l'autre consiste à +générer ou modifier directement les données dans le code pour l'envoyer à la +base de données. Insérer des Données ------------------- @@ -24,13 +24,12 @@ Le moyen le plus simple d'insérer des données dans une base de données est de créer une nouvelle entity et de la passer à la méthode ``save()`` de la classe ``Table``:: - use Cake\ORM\TableRegistry; + use Cake\ORM\Locator\LocatorAwareTrait; - // Prior to 3.6 use TableRegistry::get('Articles') - $articlesTable = TableRegistry::getTableLocator()->get('Articles'); - $article = $articlesTable->newEntity(); + $articlesTable = $this->getTableLocator()->get('Articles'); + $article = $articlesTable->newEmptyEntity(); - $article->title = 'A New Article'; + $article->title = 'Un nouvel Article'; $article->body = 'Ceci est le contenu de cet article'; if ($articlesTable->save($article)) { @@ -43,31 +42,29 @@ Mettre à jour des Données La méthode ``save()`` sert également à la mise à jour des données:: - use Cake\ORM\TableRegistry; + use Cake\ORM\Locator\LocatorAwareTrait; - // Prior to 3.6 use TableRegistry::get('Articles') - $articlesTable = TableRegistry::getTableLocator()->get('Articles'); + $articlesTable = $this->getTableLocator()->get('Articles'); $article = $articlesTable->get(12); // Retourne l'article avec l'id 12 $article->title = 'Un nouveau titre pour cet article'; $articlesTable->save($article); -CakePHP saura s'il doit faire un ajout ou une mise à jour en se basant sur le +CakePHP saura s'il doit faire une insertion ou une mise à jour d'après le résultat de la méthode ``isNew()``. Les entities qui sont récupérées via -``get()`` ou ``find()`` renverrons toujours ``false`` lorsque la méthode -``isNew()`` est appelée sur eux. +``get()`` ou ``find()`` renverront toujours ``false`` lorsqu'on appelle leur +méthode ``isNew()``. -Enregistrements avec Associations +Enregistrer avec des Associations --------------------------------- -Par défaut, la méthode ``save()`` ne sauvegardera qu'un seul niveau +Par défaut, la méthode ``save()`` sauvegardera aussi un seul niveau d'association:: - // Prior to 3.6 use TableRegistry::get('Articles') - $articlesTable = TableRegistry::getTableLocator()->get('Articles'); + $articlesTable = $this->getTableLocator()->get('Articles'); $author = $articlesTable->Authors->findByUserName('mark')->first(); - $article = $articlesTable->newEntity(); + $article = $articlesTable->newEmptyEntity(); $article->title = 'Un article par mark'; $article->author = $author; @@ -79,14 +76,14 @@ d'association:: La méthode ``save()`` est également capable de créer de nouveaux enregistrements pour les associations:: - $firstComment = $articlesTable->Comments->newEntity(); + $firstComment = $articlesTable->Comments->newEmptyEntity(); $firstComment->body = 'Un super article'; - $secondComment = $articlesTable->Comments->newEntity(); + $secondComment = $articlesTable->Comments->newEmptyEntity(); $secondComment->body = 'J aime lire ceci!'; $tag1 = $articlesTable->Tags->findByName('cakephp')->first(); - $tag2 = $articlesTable->Tags->newEntity(); + $tag2 = $articlesTable->Tags->newEmptyEntity(); $tag2->name = 'Génial'; $article = $articlesTable->get(12); @@ -103,70 +100,29 @@ deux tags. Il y a un autre moyen de faire la même chose en utilisant la méthode ``link()`` dans l'association:: $tag1 = $articlesTable->Tags->findByName('cakephp')->first(); - $tag2 = $articlesTable->Tags->newEntity(); + $tag2 = $articlesTable->Tags->newEmptyEntity(); $tag2->name = 'Génial'; $articlesTable->Tags->link($article, [$tag1, $tag2]); -Sauvegarder des Données dans la Table de Jointure -------------------------------------------------- - -L'enregistrement de données dans la table de jointure est réalisé en utilisant -la propriété spéciale ``_joinData``. Cette propriété doit être une instance -d'``Entity`` de la table de jointure:: - - // Lie les enregistrements pour la première fois. - $tag1 = $articlesTable->Tags->findByName('cakephp')->first(); - $tag1->_joinData = $articlesTable->ArticlesTags->newEntity(); - $tag1->_joinData->tagComment = 'Je pense que cela est lié à CakePHP'; - - $articlesTable->Tags->link($article, [$tag1]); - - // Mise à jour d'une association existante. - $article = $articlesTable->get(1, ['contain' => ['Tags']]); - $article->tags[0]->_joinData->tagComment = 'Fresh comment.' - - // Nécessaire car nous changeons une propriété directement - $article->setDirty('tags', true); - - $articlesTable->save($article, ['associated' => ['Tags']]); - -Vous pouvez aussi créer/mettre à jour les informations de la table jointe quand -vous utilisez ``newEntity()`` ou ``patchEntity()``. Vos données POST devraient -ressembler à ceci:: - - $data = [ - 'title' => 'My great blog post', - 'body' => 'Some content that goes on for a bit.', - 'tags' => [ - [ - 'id' => 10, - '_joinData' => [ - 'tagComment' => 'Great article!', - ] - ], - ] - ]; - $articlesTable->newEntity($data, ['associated' => ['Tags']]); - -Délier les Enregistrements Many To Many ---------------------------------------- +Dissocier des Enregistrements Many To Many +------------------------------------------ -Délier des enregistrements Many to Many (plusieurs à plusieurs) est réalisable -via la méthode ``unlink()``:: +Pour dissocier des enregistrements many-to-many, utilisez la méthode +``unlink()``:: $tags = $articlesTable ->Tags ->find() ->where(['name IN' => ['cakephp', 'awesome']]) - ->toArray(); + ->toList(); $articlesTable->Tags->unlink($article, $tags); -Lors de la modification d'enregistrements en définissant ou modifiant -directement leurs propriétés il n'y aura pas de validation, ce qui est -problématique pour l'acceptation de données de formulaire. La section suivante -va vous expliquer comment convertir efficacement les données de formulaire +Lorsque vous modifiez des enregistrements en définissant ou modifiant +directement leurs propriétés, il n'y aura pas de validation, ce qui est +problématique s'il s'agit d'accepter les données d'un formulaire. La section +suivante explique comment convertir efficacement les données de formulaire en entities afin qu'elles puissent être validées et sauvegardées. .. _converting-request-data: @@ -174,52 +130,56 @@ en entities afin qu'elles puissent être validées et sauvegardées. Convertir les Données Requêtées en Entities =========================================== -Avant de modifier et sauvegarder à nouveau les données dans la base de données, -vous devrez convertir les données requêtées (qui se trouvent dans -$this->request->getData()) à partir du format de tableau -qui se trouvent dans la requête, et les entities que l'ORM utilise. La classe +Avant de modifier et de réenregistrer les données dans la base de données, +vous devrez convertir les données d'un format de tableau (figurant +dans la requête) en entities utilisées par l'ORM. La classe Table peut convertir efficacement une ou plusieurs entities à partir des -données requêtées. Vous pouvez convertir une entity unique en utilisant:: +données de la requête. Vous pouvez convertir une entity unique en utilisant:: // Dans un controller. - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); + // Valide et convertit en un objet Entity $entity = $articles->newEntity($this->request->getData()); -Les données requêtées doivent suivre la structure de vos entities. Par -exemple si vous avez un article qui appartient à un utilisateur, et si vous -avez plusieurs commentaires, vos données requêtées devraient ressembler -à ceci:: +.. note:: + + Si vous utilisez newEntity() et qu'il manque tout ou partie des nouvelles + données dans les entities créées, vérifiez que les colonnes que vous voulez + modifier sont listées dans la propriété ``$_accessible`` de votre entity. + Cf. :ref:`entities-mass-assignment`. + +Les données de la requête doivent suivre la structure de vos entities. Par +exemple si vous avez un article, que celui-ci appartient à un utilisateur, +(*belongs to*), et a plusieurs commentaires (*has many*), les données de votre +requête devraient ressembler à:: $data = [ - 'title' => 'My title', - 'body' => 'The text', + 'title' => 'Mon titre', + 'body' => 'Le texte', 'user_id' => 1, 'user' => [ 'username' => 'mark' ], 'comments' => [ - ['body' => 'First comment'], - ['body' => 'Second comment'], + ['body' => 'Premier commentaire'], + ['body' => 'Deuxième commentaire'], ] ]; Par défaut, la méthode ``newEntity()`` valide les données qui lui sont passées, comme expliqué dans la section :ref:`validating-request-data`. Si vous voulez -empêcher les données d'être validées, passez l'option ``'validate' => false``:: +empêcher la validation des données, passez l'option ``'validate' => false``:: $entity = $articles->newEntity($data, ['validate' => false]); Lors de la construction de formulaires qui sauvegardent des associations -imbriquées, vous devez définir quelles associations doivent être prises en -compte:: +imbriquées, vous devez définir quelles associations doivent être converties:: // Dans un controller - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); // Nouvelle entity avec des associations imbriquées $entity = $articles->newEntity($this->request->getData(), [ @@ -228,38 +188,36 @@ compte:: ] ]); -Ce qui est au-dessus indique que les 'Tags', 'Comments' et 'Users' pour les -Comments doivent être prises en compte. D'une autre façon, vous pouvez utiliser -la notation par point pour être plus bref:: +Ceci indique que les Tags, les commentaires et les utilisateurs associés aux +commentaires doivent être convertis. Au choix, vous pouvez aussi utiliser la +notation par points, qui est plus concise:: // Dans un controller - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); // Nouvelle entity avec des associations imbriquées en utilisant - // la notation par point + // la notation par points $entity = $articles->newEntity($this->request->getData(), [ 'associated' => ['Tags', 'Comments.Users'] ]); -Vous pouvez aussi désactiver le marshalling d'associations imbriquées comme +Vous pouvez aussi désactiver la conversion d'associations imbriquées comme ceci:: $entity = $articles->newEntity($data, ['associated' => []]); // ou... $entity = $articles->patchEntity($entity, $data, ['associated' => []]); -Les données associées sont également validées par défaut à moins que le -contraire ne lui soit spécifié. Vous pouvez également changer l'ensemble -de validation utilisé par association:: +Les données associées sont aussi validées par défaut, à moins de spécifier le +contraire. Vous pouvez également changer l'ensemble de validation utilisé pour +chaque association:: // Dans un controller - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); - // Ne fait pas la validation pour l'association Tags et + // Ne fait pas de validation pour l'association Tags et // appelle l'ensemble de validation 'signup' pour Comments.Users $entity = $articles->newEntity($this->request->getData(), [ 'associated' => [ @@ -268,82 +226,88 @@ de validation utilisé par association:: ] ]); -Le chapitre :ref:`using-different-validators-per-association` a plus -d'informations sur la façon d'utiliser les différents validateurs pour des -marshalling associés. +Le chapitre :ref:`using-different-validators-per-association` contient davantage +d'informations sur la façon d'utiliser les différents validateurs pour la +sauvegarde d'associations. -Le diagramme suivant donne un aperçu de ce qui se passe à l'intérieur de la -méthode ``newEntity()`` ou ``patchEntity()``: +Le diagramme suivant donne un aperçu de ce qui se passe dans la méthode +``newEntity()`` ou ``patchEntity()``: .. figure:: /_static/img/validation-cycle.png :align: left - :alt: Logigramme montrant le process de conversion en entity/validation. + :alt: Logigramme montrant le process de conversion/validation. -Vous récupérerez toujours une entity en retour de ``newEntity()``. Si la -validation échoue, votre entité contiendra des erreurs et tous les champs -invalides seront absents de l'entity créée. +La méthode ``newEmptyEntity()`` vous renverra toujours une entity. Si la +validation échoue, votre entité contiendra des erreurs et les champs invalides +ne seront pas remplis dans l'entity créée. Convertir des Données BelongsToMany ----------------------------------- -Si vous sauvegardez des associations belongsToMany, vous pouvez soit utiliser -une liste de données d'entity ou une liste d'ids. Quand vous utilisez une liste -de données d'entity, vos données requêtées devraient ressembler à ceci:: +Si vous sauvegardez des associations belongsToMany, vous pouvez utiliser soit +une liste de données d'entity, soit une liste d'ids. Quand vous utilisez une +liste de données d'entity, les données de votre requête devraient ressembler à +ceci:: $data = [ - 'title' => 'My title', - 'body' => 'The text', + 'title' => 'Mon titre', + 'body' => 'Le texte', 'user_id' => 1, 'tags' => [ ['name' => 'CakePHP'], ['name' => 'Internet'], - ] + ], ]; -Le code ci-dessus créera 2 nouveaux tags. Si vous voulez créer un lien d'un -article vers des tags existants, vous pouvez utiliser une lite des ids. -Vos données de requête doivent ressembler à ceci:: +Ce code créera 2 nouveaux tags. Si vous voulez créer un lien entre un article et +des tags existants, vous pouvez utiliser une liste d'ids. Les données de votre +requête doivent ressembler à ceci:: $data = [ - 'title' => 'My title', - 'body' => 'The text', + 'title' => 'Mon titre', + 'body' => 'Le texte', 'user_id' => 1, 'tags' => [ - '_ids' => [1, 2, 3, 4] - ] + '_ids' => [1, 2, 3, 4], + ], ]; Si vous souhaitez lier des entrées belongsToMany existantes et en créer de nouvelles en même temps, vous pouvez utiliser la forme étendue:: $data = [ - 'title' => 'My title', - 'body' => 'The text', + 'title' => 'Mon titre', + 'body' => 'Le texte', 'user_id' => 1, 'tags' => [ - ['name' => 'A new tag'], - ['name' => 'Another new tag'], + ['name' => 'Un nouveau tag'], + ['name' => 'Un autre nouveau tag'], ['id' => 5], - ['id' => 21] - ] + ['id' => 21], + ], ]; -Quand les données ci-dessus seront converties en entities, il y aura 4 tags. -Les deux premiers seront de nouveaux objets, et les deux seconds seront des +Quand ces données seront converties en entities, il y aura 4 tags. +Les deux premiers seront de nouveaux objets, et les deux autres seront des références à des tags existants. -Quand les données de belongsToMany sont converties, vous pouvez désactiver la -création d'une nouvelle entity, en utilisant l'option ``onlyIds``. Quand elle -est activée, cette option restreint la conversion des données de belongsToMany -pour utiliser uniquement la clé ``_ids`` et ignorer toutes les autres données. +Quand vous convertissez des données de belongsToMany, vous pouvez désactiver la +création d'une nouvelle entity en utilisant l'option ``onlyIds``:: + + $result = $articles->patchEntity($entity, $data, [ + 'associated' => ['Tags' => ['onlyIds' => true]], + ]); + +Quand elle est activée, cette option restreint la conversion des données de +belongsToMany pour utiliser uniquement la clé ``_ids``. Convertir des Données HasMany ----------------------------- -Si vous souhaitez mettre à jour les associations hasMany existantes et mettre à -jour leurs propriétés, vous devriez d'abord vous assurer que votre entity est -chargée avec l'association hasMany remplie. Vous pouvez ensuite utiliser les -données de la requête de la façon suivante:: +Si vous souhaitez mettre à jour des associations hasMany existantes et mettre à +jour leurs propriétés, vous devez d'abord vous assurer que votre entity est +chargée avec les données hasMany associées. Vous pouvez ensuite utiliser une +requête avec des données structurées de la façon suivante:: $data = [ 'title' => 'Mon titre', @@ -352,100 +316,95 @@ données de la requête de la façon suivante:: ['id' => 1, 'comment' => 'Mettre à jour le premier commentaire'], ['id' => 2, 'comment' => 'Mettre à jour le deuxième commentaire'], ['comment' => 'Créer un nouveau commentaire'], - ] + ], ]; -Si vous sauvegardez des associations hasMany et voulez lier des enregistrements -existants à un nouveau parent, vous pouvez utiliser le format ``_ids``:: +Si vous sauvegardez des associations hasMany et que voulez lier des +enregistrements existants à un nouveau parent, vous pouvez utiliser le format +``_ids``:: $data = [ - 'title' => 'My new article', - 'body' => 'The text', + 'title' => 'Mon nouvel article', + 'body' => 'Le texte', 'user_id' => 1, 'comments' => [ - '_ids' => [1, 2, 3, 4] - ] + '_ids' => [1, 2, 3, 4], + ], ]; -Quand les données de hasMany sont converties, vous pouvez désactiver la -création d'une nouvelle entity, en utilisant l'option ``onlyIds``. Quand elle +Quand vous convertissez des données de hasMany, vous pouvez désactiver la +création d'une nouvelle entity en utilisant l'option ``onlyIds``. Quand elle est activée, cette option restreint la conversion des données hasMany pour utiliser uniquement la clé ``_ids`` et ignorer toutes les autres données. Convertir des Enregistrements Multiples --------------------------------------- -Lorsque vous créez des formulaires de création/mise à jour d'enregistrements -multiples en une seule opération vous pouvez utiliser ``newEntities()``:: +Lorsque vous créez des formulaires de création/mise à jour de plusiseurs +enregistrements en une seule opération, vous pouvez utiliser ``newEntities()``:: // Dans un controller. - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $entities = $articles->newEntities($this->request->getData()); -Dans cette situation, les données de requête pour plusieurs articles doivent +Dans cette situation, les données de la requête pour plusieurs articles doivent ressembler à ceci:: $data = [ [ - 'title' => 'First post', - 'published' => 1 + 'title' => 'Premier post', + 'published' => 1, ], [ 'title' => 'Second post', - 'published' => 1 + 'published' => 1, ], ]; -Une fois que vous avez converti les données requêtées dans des entities, vous -pouvez leur faire un ``save()`` ou un ``delete()``:: +Une fois que vous avez converti les données de la requête en entities, vous +pouvez sauvegarder:: // Dans un controller. foreach ($entities as $entity) { - // Save entity + // Sauvegarder l'entity $articles->save($entity); - - // Supprime l'entity - $articles->delete($entity); } -Ce qui est au-dessus va lancer une transaction séparée pour chaque entity +Ce code va lancer séparément une transaction pour chaque entity sauvegardée. Si vous voulez traiter toutes les entities en transaction unique, -vous pouvez utiliser ``transactional()``:: +vous pouvez utiliser ``saveMany()`` ou ``saveManyOrFail()``:: - // Dans un controller. - $articles->getConnection()->transactional(function () use ($articles, $entities) { - foreach ($entities as $entity) { - $articles->save($entity, ['atomic' => false]); - } - }); + // Renvoie un booléen pour indiquer si l'opération a réussi + $articles->saveMany($entities); + + // Lève une PersistenceFailedException si l'un des enregistrements échoue + $articles->saveManyOrFail($entities); .. _changing-accessible-fields: Changer les Champs Accessibles ------------------------------ -Il est également possible de permettre à ``newEntity()`` d'écrire dans des +Il est également possible d'autoriser ``newEntity()`` à écrire dans des champs non accessibles. Par exemple, ``id`` est généralement absent de la -propriété ``_accessible``. Dans ce cas, vous pouvez utiliser l'option -``accessibleFields``. Cela est particulièrement intéressant pour conserver les -associations existantes entre certaines entities:: +propriété ``_accessible``. Dans un tel cas, vous pouvez utiliser l'option +``accessibleFields``. Il pourrait être utile de conserver les ids des entities +associées:: // Dans un controller. - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $entity = $articles->newEntity($this->request->getData(), [ 'associated' => [ 'Tags', 'Comments' => [ 'associated' => [ 'Users' => [ - 'accessibleFields' => ['id' => true] - ] - ] - ] - ] + 'accessibleFields' => ['id' => true], + ], + ], + ], + ], ]); Le code ci-dessus permet de conserver l'association entre Comments et Users pour @@ -453,25 +412,24 @@ l'entity concernée. .. note:: - Si vous utilisez newEntity() et qu'il manque quelques unes ou toutes les - données dans les entities résultantes, vérifiez deux fois que les colonnes + Si vous utilisez newEntity() et qu'il manque dans l'entity tout ou partie + des données transmises, vérifiez à deux fois que les colonnes que vous souhaitez définir sont listées dans la propriété ``$_accessible`` - de votre entity. + de votre entity. Cf. :ref:`entities-mass-assignment`. -Fusionner les Données Requêtées dans les Entities -------------------------------------------------- +Fusionner les Données de la Requête dans les Entities +----------------------------------------------------- -Afin de mettre à jour les entities, vous pouvez choisir d'appliquer les données -requêtées directement dans une entity existante. Ceci a l'avantage que seuls les -champs qui changent réellement seront sauvegardés, au lieu d'envoyer tous les -champs à la base de données, même ceux qui sont identiques. Vous pouvez +Pour mettre à jour des entities, vous pouvez choisir d'appliquer les données de +la requête directement sur une entity existante. Cela a l'avantage que seuls les +champs réellement modifiés seront sauvegardés, au lieu d'envoyer tous les +champs à la base de données, même ceux qui sont inchangés. Vous pouvez fusionner un tableau de données brutes dans une entity existante en utilisant la méthode ``patchEntity()``:: // Dans un controller. - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $article = $articles->get(1); $articles->patchEntity($article, $this->request->getData()); $articles->save($article); @@ -480,20 +438,18 @@ Validation et patchEntity ~~~~~~~~~~~~~~~~~~~~~~~~~ De la même façon que ``newEntity()``, la méthode ``patchEntity`` validera les -données avant qu'elles soient copiées dans l'entity. Ce mécanisme est expliqué +données avant de les copier dans l'entity. Ce mécanisme est expliqué dans la section :ref:`validating-request-data`. Si vous souhaitez désactiver la -validation lors du patch d'une entity, passez l'option ``validate`` comme -montré ci-dessous:: +validation lors du patch d'une entity, passez l'option ``validate`` comme ceci:: // Dans un controller. - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $article = $articles->get(1); $articles->patchEntity($article, $data, ['validate' => false]); Vous pouvez également changer l'ensemble de validation utilisé pour l'entity -ou n'importe qu'elle association:: +ou pour n'importe qu'elle association:: $articles->patchEntity($article, $this->request->getData(), [ 'validate' => 'custom', @@ -503,159 +459,149 @@ ou n'importe qu'elle association:: Patcher des HasMany et BelongsToMany ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Comme expliqué dans la section précédente, les données requêtées doivent suivre +Comme expliqué dans la section précédente, les données de la requête doivent suivre la structure de votre entity. La méthode ``patchEntity()`` est également capable -de fusionner les associations, par défaut seul les premiers niveaux +de fusionner les associations. Par défaut seul les premiers niveaux d'associations sont fusionnés mais si vous voulez contrôler la liste des -associations à fusionner ou fusionner des niveaux de plus en plus profonds, vous +associations à fusionner, ou fusionner des niveaux de plus en plus profonds, vous pouvez utiliser le troisième paramètre de la méthode:: // Dans un controller. $associated = ['Tags', 'Comments.Users']; $article = $articles->get(1, ['contain' => $associated]); $articles->patchEntity($article, $this->request->getData(), [ - 'associated' => $associated + 'associated' => $associated, ]); $articles->save($article); -Les associations sont fusionnées en faisant correspondre le champ de clé -primaire dans la source entities avec les champs correspondants dans le tableau -de données. Les associations vont construire de nouvelles entities si aucune -entity précédente n'est trouvé pour la propriété cible. +Les associations sont fusionnées en faisant correspondre la clé primaire des +entities source avec les champs correspondants dans le tableau de données +fourni. Si aucune entity cible n'est trouvée, les associations construiront de +nouvelles entities. -Pa exemple, prenons les données requêtées comme ce qui suit:: +Pa exemple, prenons une requête contenant les données suivantes:: $data = [ - 'title' => 'My title', + 'title' => 'Mon titre', 'user' => [ - 'username' => 'mark' - ] + 'username' => 'mark', + ], ]; -Essayer de faire un patch d'une entity sans entity dans la propriété user va -créer une nouvelle entity user:: +Si vous essayez de patcher une entity ne contenant pas d'entity associée dans la +propriété user, une nouvelle entity sera créée pour `user`:: // Dans un controller. $entity = $articles->patchEntity(new Article, $data); - echo $entity->user->username; // Echoes 'mark' + echo $entity->user->username; // Affiche 'mark' -La même chose peut être dite pour les associations hasMany et belongsToMany, -mais avec une mise en garde importante. +Cela fonctionne de la même manière pour les associations hasMany et +belongsToMany, avec cependant un point d'attention important: .. note:: Pour les associations belongsToMany, vérifiez que les entities associées - sont bien présentes dans la propriété ``$_accessible`` + ont bien une propriété accessible pour l'entité associée. Si Product belongsToMany Tag:: // Dans l'entity Product protected $_accessible = [ - // .. autre propriété + // .. autres propriétés 'tags' => true, ]; .. note:: Pour les associations hasMany et belongsToMany, s'il y avait des entities - qui ne pouvaient pas correspondre avec leur clé primaire à aucun - enregistrement dans le tableau de données, alors ces enregistrements - seraient annulés de l'entity résultante. + dont la clé primaire ne correspondait à aucun enregistrement dans le tableau + de données, alors ces enregistrements seraient écartés de l'entity + résultante. Rappelez-vous que l'utilisation de ``patchEntity()`` ou de - ``patchEntities()`` ne fait pas persister les données, il modifie juste - (ou créé) les entities données. Afin de sauvegarder l'entity, vous devrez - appeler la méthode ``save()`` de la table. + ``patchEntities()`` ne fait pas persister les données, elle ne fait que + modifier (ou créer) les entities données. Pour sauvegarder l'entity, vous + devrez appeler la méthode ``save()`` de la table. Par exemple, considérons le cas suivant:: $data = [ - 'title' => 'My title', - 'body' => 'The text', - 'comments' => [ - ['body' => 'First comment', 'id' => 1], - ['body' => 'Second comment', 'id' => 2], - ] - ]; - $article = $articles->newEntity($data); - $articles->save($article); - - $newData = [ + 'title' => 'Mon titre', + 'body' => 'Le text', 'comments' => [ - ['body' => 'Changed comment', 'id' => 1], - ['body' => 'A new comment'], - ] + ['body' => 'Premier commentaire', 'id' => 1], + ['body' => 'Second commentaire', 'id' => 2], + ], ]; $entity = $articles->newEntity($data); $articles->save($entity); $newData = [ 'comments' => [ - ['body' => 'Changed comment', 'id' => 1], - ['body' => 'A new comment'], - ] + ['body' => 'Commentaire modifié', 'id' => 1], + ['body' => 'Un nouveau commentaire'], + ], ]; $articles->patchEntity($entity, $newData); $articles->save($entity); -A la fin, si l'entity est à nouveau convertie en tableau, vous obtiendrez le +Au final, si l'entity est à nouveau convertie en tableau, vous obtiendrez le résultat suivant:: [ - 'title' => 'My title', - 'body' => 'The text', + 'title' => 'Mon titre', + 'body' => 'Le text', 'comments' => [ - ['body' => 'Changed comment', 'id' => 1], - ['body' => 'A new comment'], + ['body' => 'Commentaire modifié', 'id' => 1], + ['body' => 'Un nouveau commentaire'], ] ]; -Comme vous l'avez vu, le commentaire avec l'id 2 n'est plus ici, puisqu'il ne -correspondait à rien dans le tableau ``$newData``. Ceci arrive car CakePHP -reflète le nouvel état décrit dans les données requêtées. +Comme vous pouvez le constater, le commentaire avec l'id 2 a disparu, puisqu'il +ne correspondait à aucun élément du tableau ``$newData``. Cela se passe ainsi +parce CakePHP calque les données de l'entity sur le nouvel état que décrit par +les données de la requête. -Des avantages supplémentaires à cette approche sont qu'elle réduit le nombre -d'opérations à exécuter quand on fait persister l'entity à nouveau. +Un autre avantage à cette approche est qu'elle réduit le nombre d'opérations à +exécuter lorsque l'entity est à nouveau persistée. -Notez bien que ceci ne signifie pas que le commentaire avec l'id 2 a été -supprimé de la base de données, si vous souhaitez retirer les commentaires pour -cet article qui ne sont pas présents dans l'entity, vous pouvez collecter +Notez bien que cela ne veut pas dire que le commentaire avec l'id 2 a été +supprimé de la base de données. Si vous souhaitez supprimer les commentaires de +cet article qui ne sont pas présents dans l'entity, vous pouvez récupérer les clés primaires et exécuter une suppression batch pour celles qui ne sont pas dans la liste:: // Dans un controller. + use Cake\Collection\Collection; - // Prior to 3.6 use TableRegistry::get('Comments') - $comments = TableRegistry::getTableLocator()->get('Comments'); - $present = (new Collection($entity->comments))->extract('id')->filter()->toArray(); + $comments = $this->getTableLocator()->get('Comments'); + $present = (new Collection($entity->comments))->extract('id')->filter()->toList(); $comments->deleteAll([ 'article_id' => $article->id, - 'id NOT IN' => $present + 'id NOT IN' => $present, ]); -Comme vous pouvez le voir, ceci permet aussi de créer des solutions lorsqu'une +Comme vous voyez, cela permet aussi de créer des solutions dans lesquelles une association a besoin d'être implémentée comme un ensemble unique. -Vous pouvez aussi faire un patch de plusieurs entities en une fois. Les -considérations faîtes pour les associations hasMany et belongsToMany -s'appliquent pour le patch de plusieurs entities: Les correspondances sont -faites avec la valeur du champ de la clé primaire et les correspondances -manquantes dans le tableau original des entities seront retirées et non -présentes dans les résultats:: +Vous pouvez aussi faire un patch de plusieurs entities à la fois. Ce que nous +avons vu pour les associations hasMany et belongsToMany s'applique aussi pour +patcher plusieurs entities: les correspondances se font d'après la valeur de la +clé primaire et celles qui sont absentes dans le tableau des entities d'origine +seront retirées et absentes des résultats:: // Dans un controller. - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); - $list = $articles->find('popular')->toArray(); + $articles = $this->getTableLocator()->get('Articles'); + $list = $articles->find('popular')->toList(); $patched = $articles->patchEntities($list, $this->request->getData()); foreach ($patched as $entity) { $articles->save($entity); } -De la même façon que pour l'utilisation de ``patchEntity()``, vous pouvez -utiliser le troisième argument pour contrôler les associations qui seront -fusionnées dans chacune des entities du tableau:: +De la même façon qu'avec ``patchEntity()``, vous pouvez utiliser le troisième +argument pour contrôler les associations qui seront fusionnées dans chacune des +entities du tableau:: // Dans un controller. $patched = $articles->patchEntities( @@ -666,20 +612,20 @@ fusionnées dans chacune des entities du tableau:: .. _before-marshal: -Modifier les Données Requêtées Avant de Construire les Entities ---------------------------------------------------------------- +Modifier les Données de la Requête Avant de Construire les Entities +------------------------------------------------------------------- -Si vous devez modifier les données requêtées avant qu'elles ne soient -converties en entities, vous pouvez utiliser l'event ``Model.beforeMarshal``. -Cet event vous laisse manipuler les données requêtées juste avant que les -entities ne soient créées:: +Si vous devez modifier les données de la requête avant de les convertir en +entities, vous pouvez utiliser l'event ``Model.beforeMarshal``. Cet event vous +permet de manipuler les données de la requête juste avant la création des +entities:: - // Mettez des use en haut de votre fichier. - use Cake\Event\Event; + // Ajoutez les instructions use au début de votre fichier. + use Cake\Event\EventInterface; use ArrayObject; - // Dans une classe table ou behavior - public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options) + // Dans une classe de table ou un behavior + public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options) { if (isset($data['username'])) { $data['username'] = mb_strtolower($data['username']); @@ -687,27 +633,28 @@ entities ne soient créées:: } Le paramètre ``$data`` est une instance ``ArrayObject``, donc vous n'avez pas -à la retourner pour changer les données utilisées pour créer les entities. +besoin de la renvoyer pour changer les données qui seront utilisées pour créer +les entities. Le but principal de ``beforeMarshal`` est d'aider les utilisateurs à passer le process de validation lorsque des erreurs simples peuvent être résolues automatiquement, ou lorsque les données doivent être restructurées pour être -mises dans les bons champs. +placées dans les bons champs. L'event ``Model.beforeMarshal`` est lancé juste au début du process de validation. Une des raisons à cela est que ``beforeMarshal`` est autorisé à modifier les -règles de validation et les options d'enregistrement, telle que la whitelist -des champs. La validation est lancée juste après que cet événement soit -terminé. Un exemple commun de modification des données avant qu'elles soient -validées est la suppression des espaces superflus d'un champ avant -l'enregistrement:: - - // Mettez des use en haut de votre fichier. - use Cake\Event\Event; +règles de validation et les options d'enregistrement, telles que la liste +blanche des champs. La validation est lancée juste après la fin de l'exécution +de cet événement. Un exemple classique de modification des données avant leur +validation est la suppression des espaces superflus dans tous les champs avant +leur enregistrement:: + + // Ajoutez les instructions use au début de votre fichier. + use Cake\Event\EventInterface; use ArrayObject; // Dans une table ou un behavior - public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options) + public function beforeMarshal(EventInterface $event, ArrayObject $data, ArrayObject $options) { foreach ($data as $key => $value) { if (is_string($value)) { @@ -716,29 +663,63 @@ l'enregistrement:: } } -A cause de la manière dont le process de marshalling fonctionne, si un champ ne -passe pas la validation, il sera automatiquement supprimé du tableau de données -et ne sera pas copié dans l'entity. cela évite d'avoir des données incohérentes -dans l'objet entity. +Du fait du mode de fonctionnement du marshalling, si un champ ne passe pas la +validation il sera automatiquement supprimé du tableau de données et ne sera pas +copié dans l'entity. Cela évite d'avoir des données incohérentes dans l'objet +entity. + +De plus, les données fournies à la méthode ``beforeMarshal`` sont une copie des +données passées. La raison à cela est qu'il est important de préserver les +données saisies à l'origine par l'utilisateur, car elles sont susceptibles de +servir autre part. + +Modifier les Entités Après leur Mise À Jour À Partir de la Requête +------------------------------------------------------------------ + +L'événement ``Model.afterMarshal`` vous permet de modifier les entités après +qu'elles auront été créées ou modifiées à partir des données de la requête. Cela +peut vous servir à appliquer une logique de validation supplémentaire qui ne +peut pas être exprimée de manière simple à travers les méthodes du Validator:: + + // Ajoutez les instructions use au début de votre fichier. + use Cake\Event\EventInterface; + use Cake\ORM\EntityInterface; + use ArrayObject; + + // Dans une classe de table ou de behavior + public function afterMarshal( + EventInterface $event, + EntityInterface $entity, + ArrayObject $data, + ArrayObject $options + ) { + // Ne pas accepter les personnes dont le nom commence par J le 20 de + // chaque mois. + if (mb_substr($entity->name, 1) === 'J' && (int)date('d') === 20) { + $entity->setError('name', 'Pas de noms en J aujourd\'hui. Désolé.'); + } + } + +.. versionadded:: 4.1.0 Valider les Données Avant de Construire les Entities ---------------------------------------------------- -Le chapitre :doc:`/orm/validation` recèle plus d'information sur l'utilisation -des fonctionnalités de validation de CakePHP pour garantir que vos données -restent correctes et cohérentes. +Le chapitre :doc:`/orm/validation` vous fournira plus d'informations sur les +fonctionnalités de validation de CakePHP pour garantir l'exactitude et la +cohérence de vos données. -Eviter les Attaques d'Assignement en Masse de Propriétés +Éviter les Attaques d'Assignement en Masse de Propriétés -------------------------------------------------------- -Lors de la création ou la fusion des entities à partir de données requêtées, -vous devez faire attention à ce que vous autorisez à changer ou à ajouter -dans les entities à vos utilisateurs. Par exemple, en envoyant un tableau -dans la requête contenant ``user_id``, un pirate pourrait changer le -propriétaire d'un article, ce qui entraînerait des effets indésirables:: +Lors de la création ou la fusion des entities à partir de données de la requête, +vous devez être attentif aux ajouts ou modifications que vous permettez à vos +utilisateurs dans les entities. Par exemple, en envoyant dans la requpete un +tableau contenant ``user_id``, un pirate pourrait changer le propriétaire d'un +article, ce qui entraînerait des effets indésirables:: - // Contient ['user_id' => 100, 'title' => 'Hacked!']; - $data = $this->request->data; + // Contient ['user_id' => 100, 'title' => 'Piraté !']; + $data = $this->request->getData(); $entity = $this->patchEntity($entity, $data); $this->save($entity); @@ -747,35 +728,32 @@ définir les colonnes par défaut qui peuvent être définies en toute sécurit partir d'une requête en utilisant la fonctionnalité d':ref:`entities-mass-assignment` dans les entities. -La deuxième façon est d'utiliser l'option ``fieldList`` lors de la création ou +La deuxième façon est d'utiliser l'option ``fields`` lors de la création ou la fusion de données dans une entity:: - // Contient ['user_id' => 100, 'title' => 'Hacked!']; - $data = $this->request->data; + // Contient ['user_id' => 100, 'title' => 'Piraté !']; + $data = $this->request->getData(); // Permet seulement de changer le title $entity = $this->patchEntity($entity, $data, [ - 'fieldList' => ['title'] + 'fields' => ['title'] ]); $this->save($entity); Vous pouvez aussi contrôler les propriétés qui peuvent être assignées pour les associations:: - // Permet seulement le changement de title et de tags - // et le nom du tag est la seule colonne qui peut être définie + // Permet seulement de modifier le titre et les tags + // et le nom du tag est la seule colonne qui puisse être définie $entity = $this->patchEntity($entity, $data, [ - 'fieldList' => ['title', 'tags'], - 'associated' => ['Tags' => ['fieldList' => ['name']]] + 'fields' => ['title', 'tags'], + 'associated' => ['Tags' => ['fields' => ['name']]] ]); $this->save($entity); -Utiliser cette fonctionnalité est pratique quand vous avez différentes fonctions -auxquelles vos utilisateurs peuvent accéder et que vous voulez laisser vos -utilisateurs modifier différentes données basées sur leurs privilèges. - -L'option ``fieldList`` est aussi acceptée par les méthodes ``newEntity()``, -``newEntities()`` et ``patchEntities()``. +Cette fonctionnalité est pratique quand vos utilisateurs ont accès plusieurs +fonctions et que vous voulez leur permettre de modifier différentes données +en fonction de leurs privilèges. .. _saving-entities: @@ -784,60 +762,58 @@ Sauvegarder les Entities .. php:method:: save(Entity $entity, array $options = []) -Quand vous sauvegardez les données requêtées dans votre base de données, vous -devez d'abord hydrater une nouvelle entity en utilisant ``newEntity()`` pour -passer dans ``save()``. Pare exemple:: +Quand vous sauvegardez les données de la requête dans votre base de données, +vous devez d'abord hydrater une nouvelle entity en utilisant ``newEntity()``, +que vous pourrez ensuite passer à ``save()``. Par exemple:: // Dans un controller - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $article = $articles->newEntity($this->request->getData()); if ($articles->save($article)) { // ... } -L'ORM utilise la méthode ``isNew()`` sur une entity pour déterminer si oui ou -non une insertion ou une mise à jour doit être faite. Si la méthode -``isNew()`` retourne ``true`` et que l'entity a une valeur de clé primaire, -une requête 'exists' sera faîte. La requête 'exists' peut être supprimée en -passant ``'checkExisting' => false`` à l'argument ``$options``:: +L'ORM utilise la méthode ``isNew()`` sur une entity pour déterminer s'il faut +réaliser une insertion ou une mise à jour. Si la méthode ``isNew()`` renvoie +``true`` et que l'entity a une clé primaire, l'ORM va d'abord lancer une requête +'exists'. Cette requête 'exists' peut être supprimée en passant +``'checkExisting' => false`` dans l'argument ``$options``:: $articles->save($article, ['checkExisting' => false]); -Une fois que vous avez chargé quelques entities, vous voudrez probablement les -modifier et les mettre à jour dans votre base de données. C'est un exercice -simple dans CakePHP:: +Une fois que vous aurez chargé quelques entities, vous voudrez probablement les +modifier et mettre à jour la base de données. C'est une manipulation simple dans +CakePHP:: - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $article = $articles->find('all')->where(['id' => 2])->first(); - $article->title = 'My new title'; + $article->title = 'Mon nouveau titre'; $articles->save($article); Lors de la sauvegarde, CakePHP va -:ref:`appliquer vos règles de validation `, et -entourer l'opération de sauvegarde dans une transaction de base de données. -Cela va aussi seulement mettre à jour les propriétés qui ont changé. Le -``save()`` ci-dessus va générer le code SQL suivant: +:ref:`appliquer vos règles de validation `, et inclure +l'opération de sauvegarde dans une transaction de la base de données. +Cela mettra à jour uniquement les propriétés qui ont changé. L'appel à +``save()`` ci-dessus va générer un code SQL de ce type: .. code-block:: sql - UPDATE articles SET title = 'My new title' WHERE id = 2; + UPDATE articles SET title = 'Mon nouveau titre' WHERE id = 2; -Si vous avez une nouvelle entity, le code SQL suivant serait généré: +Si vous aviez une nouvelle entity, cela générerait le code SQL suivant: .. code-block:: sql - INSERT INTO articles (title) VALUES ('My new title'); + INSERT INTO articles (title) VALUES ('Mon nouveau titre'); Quand une entity est sauvegardée, voici ce qui se passe: 1. La vérification des règles commencera si elle n'est pas désactivée. 2. La vérification des règles va déclencher l'event ``Model.beforeRules``. Si l'event est stoppé, l'opération de - sauvegarde va connaitre un échec et retourner ``false``. + sauvegarde échouera et retournera ``false``. 3. Les règles seront vérifiées. Si l'entity est en train d'être créée, les règles ``create`` seront utilisées. Si l'entity est en train d'être mise à jour, les règles ``update`` seront utilisées. @@ -847,12 +823,12 @@ Quand une entity est sauvegardée, voici ce qui se passe: 6. Les associations parentes sont sauvegardées. Par exemple, toute association belongsTo listée sera sauvegardée. 7. Les champs modifiés sur l'entity seront sauvegardés. -8. Les associations Enfant sont sauvegardées. Par exemple, toute association +8. Les associations enfants sont sauvegardées. Par exemple, toute association hasMany, hasOne, ou belongsToMany listée sera sauvegardée. 9. L'event ``Model.afterSave`` sera dispatché. 10. L'event ``Model.afterSaveCommit`` sera dispatché. -Le diagramme suivant illustre le procédé ci-dessus: +Le diagramme suivant illustre ce procédé: .. figure:: /_static/img/save-cycle.png :align: left @@ -863,55 +839,41 @@ création et l'utilisation des règles. .. warning:: - Si aucun changement n'est fait à l'entity quand elle est sauvegardée, les - callbacks ne vont pas être déclenchés car aucune sauvegarde n'est faîte. + Si l'entity n'a subi aucun changement au moment de sa sauvegarde, les + callbacks ne vont pas être déclenchés car aucune opération de sauvegarde + n'est effectuée. La méthode ``save()`` va retourner l'entity modifiée en cas de succès, et ``false`` en cas d'échec. Vous pouvez désactiver les règles et/ou les -transactions en utilisant l'argument ``$options`` pendant la sauvegarde:: +transactions en utilisant l'argument ``$options`` lors de la sauvegarde:: // Dans un controller ou une méthode de table. - $articles->save($article, ['atomic' => false]); + $articles->save($article, ['checkRules' => false, 'atomic' => false]); Sauvegarder les Associations ---------------------------- -Quand vous sauvegardez une entity, vous pouvez aussi choisir d'avoir quelques -unes ou toutes les entities associées. Par défaut, toutes les entities de -premier niveau seront sauvegardées. Par exemple sauvegarder un Article, va -aussi automatiquement mettre à jour tout entity modifiée qui n'est pas -directement liée à la table articles. +Quand vous sauvegardez une entity, vous pouvez aussi choisir de sauvegarder tout +ou partie des entities associées. Par défaut, toutes les entities de premier +niveau seront sauvegardées. Par exemple, sauvegarder un Article va aussi +mettre à jour automatiquement toute entity modifiée directement liée à la table +des articles. -Vous pouvez régler finement les associations qui sont sauvegardées en -utilisant l'option ``associated``:: +Vous pouvez accéder à un réglage plus fin des associations qui sont sauvegardées +en utilisant l'option ``associated``:: // Dans un controller. // Sauvegarde seulement l'association avec les commentaires $articles->save($entity, ['associated' => ['Comments']]); -Vous pouvez définir une sauvegarde distante ou des associations imbriquées -profondément en utilisant la notation par point:: +Vous pouvez définir une sauvegarde d'associations imbriquées sur plusieurs +niveaux en utilisant la notation par point:: - // Sauvegarde la company, les employees et les addresses liées pour chacun d'eux. + // Sauvegarde la société, les employés et les adresses liées à chacun d'eux. $companies->save($entity, ['associated' => ['Employees.Addresses']]); -Si vous avez besoin de lancer un ensemble de règle de validation différente pour -une association, vous pouvez le spécifier dans un tableau d'options pour -l'association:: - - // Dans un controller. - - // Sauvegarde la company, les employees et les addresses liées pour chacun d'eux. - $companies->save($entity, [ - 'associated' => [ - 'Employees' => [ - 'associated' => ['Addresses'], - ] - ] - ]); - -En plus, vous pouvez combiner la notation par point pour les associations avec +De plus, vous pouvez combiner la notation par point pour les associations avec le tableau d'options:: $companies->save($entity, [ @@ -926,9 +888,9 @@ quand elles ont été chargées à partir de la base de données. Consultez la documentation du helper Form pour savoir comment :ref:`associated-form-inputs`. -Si vous construisez ou modifiez une donnée d'association après avoir construit +Si vous construisez ou modifiez des données associées après avoir construit vos entities, vous devrez marquer la propriété d'association comme étant -modifiée avec ``setDirty()``:: +modifiée en utilisant ``setDirty()``:: $company->author->name = 'Master Chef'; $company->setDirty('author', true); @@ -936,22 +898,21 @@ modifiée avec ``setDirty()``:: Sauvegarder les Associations BelongsTo -------------------------------------- -Lors de la sauvegarde des associations belongsTo, l'ORM s'attend à une entity +Lors de la sauvegarde des associations belongsTo, l'ORM attend une entity imbriquée unique avec le nom de l'association au singulier et -:ref:`en underscore `. +:ref:`des underscores `. Par exemple:: // Dans un controller. $data = [ - 'title' => 'First Post', + 'title' => 'Premier Post', 'user' => [ 'id' => 1, 'username' => 'mark' ] ]; - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $article = $articles->newEntity($data, [ 'associated' => ['Users'] ]); @@ -961,9 +922,9 @@ Par exemple:: Sauvegarder les Associations HasOne ----------------------------------- -Lors de la sauvegarde d'associations hasOne, l'ORM s'attend à une entity +Lors de la sauvegarde d'associations hasOne, l'ORM attend une entity imbriquée unique avec le nom de l'association au singulier et -:ref:`en underscore `. +:ref:`des underscores underscore `. Par exemple:: // Dans un controller. @@ -975,8 +936,7 @@ Par exemple:: ] ]; - // Prior to 3.6 use TableRegistry::get('Users') - $users = TableRegistry::getTableLocator()->get('Users'); + $users = $this->getTableLocator()->get('Users'); $user = $users->newEntity($data, [ 'associated' => ['Profiles'] ]); @@ -985,22 +945,21 @@ Par exemple:: Sauvegarder les Associations HasMany ------------------------------------ -Lors de la sauvegarde d'associations hasMany, l'ORM s'attend à une entity -imbriquée unique avec le nom de l'association au pluriel et -:ref:`en underscore `. +Lors de la sauvegarde d'associations hasMany, l'ORM attend un tableau d'entities +avec le nom de l'association au pluriel et +:ref:`des underscores `. Par exemple:: // Dans un controller. $data = [ - 'title' => 'First Post', + 'title' => 'Premier Post', 'comments' => [ - ['body' => 'Best post ever'], - ['body' => 'I really like this.'] + ['body' => 'Le meilleur post de ma vie'], + ['body' => 'Celui-là, je l\'aime vraiment bien.'] ] ]; - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $article = $articles->newEntity($data, [ 'associated' => ['Comments'] ]); @@ -1013,20 +972,20 @@ deux stratégies de sauvegarde: append Les enregistrements associés sont mis à jour dans la base de données - ou, si ils ne correspondent à aucun enregistrement existant, sont insérés. + ou, s'ils ne correspondent à aucun enregistrement existant, sont insérés. replace Tout enregistrement existant qui ne correspond pas aux enregistrements fournis sera supprimé de la base de données. Seuls les enregistrements fournis resteront (ou seront insérés). -Par défaut, la stratégie de sauvegarde ``append`` est utilisée. +Par défaut, l'ORM utilise la stratégie de sauvegarde ``append``. Consultez :ref:`has-many-associations` pour plus de détails sur la définition de ``saveStrategy``. -Peu importe le moment où vous ajoutez de nouveaux enregistrements dans une +Quel que soit le moment où vous ajoutez de nouveaux enregistrements dans une association existante, vous devez toujours marquer la propriété de l'association -comme 'setDirty'. Ceci dit à l'ORM que la propriété de l'association doit -persister:: +comme 'dirty'. Cela fait savoir à l'ORM que la propriété de cette association +doit être persistée:: $article->comments[] = $comment; $article->setDirty('comments', true); @@ -1034,66 +993,75 @@ persister:: Sans l'appel à ``setDirty()``, les commentaires mis à jour ne seront pas sauvegardés. +Si vous créez une entité et voulez y attacher des enregistrements existants dans +une association hasMany ou belongsToMany, vous devez d'abord initialiser la +propriété de l'association:: + + $article->comments = []; + +Sans l'initialisation, l'appel à ``$article->comments[] = $comment;`` sera sans +effet. + Sauvegarder les Associations BelongsToMany ------------------------------------------ -Lors de la sauvegarde d'associations hasMany, l'ORM s'attend à une entity -imbriquée unique avec le nom de l'association au pluriel et -:ref:`en underscore `. +Lors de la sauvegarde d'associations hasMany, l'ORM attend un tableau d'entities +avec le nom de l'association au pluriel et +:ref:`des underscores `. Par exemple:: // Dans un controller. $data = [ - 'title' => 'First Post', + 'title' => 'Premier Post', 'tags' => [ ['tag' => 'CakePHP'], ['tag' => 'Framework'] ] ]; - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $article = $articles->newEntity($data, [ 'associated' => ['Tags'] ]); $articles->save($article); -Quand vous convertissez les données requêtées en entities, les méthodes -``newEntity()`` et ``newEntities()`` vont gérer les deux tableaux de propriétés, -ainsi qu'une liste d'ids avec la clé ``_ids``. Utiliser la clé ``_ids`` facilite -la construction d'un box select ou d'un checkbox basé sur les contrôles pour les -associations belongs to many. Consultez la section -:ref:`converting-request-data` pour plus d'informations. +Quand vous convertissez les données de la requête en entities, les méthodes +``newEntity()`` et ``newEntities()`` traiteront les deux tableaux de propriétés, +ainsi qu'une liste d'ids sous la clé ``_ids``. L'utilisation de la clé ``_ids`` +permet de construire des contrôles de formulaire basés sur une liste déroulante +ou une liste de cases à cocher pour les associations belongsToMany. Consultez la +section :ref:`converting-request-data` pour plus d'informations. Lors de la sauvegarde des associations belongsToMany, vous avez le choix entre deux stratégies de sauvegarde: append Seuls les nouveaux liens seront créés de chaque côté de cette association. - Cette stratégie ne va pas détruire les liens existants même s'ils ne sont - pas présents dans le tableau d'entities à sauvegarder. + Cette stratégie détruira pas les liens existants même s'ils sont absents du + tableau d'entities à sauvegarder. replace - Lors de la sauvegarde, les liens existants seront retirés et les nouveaux + Lors de la sauvegarde, les liens existants seront supprimés et les nouveaux liens seront créés dans la table de jointure. S'il y a des liens existants - dans la base de données vers certaines entities que l'on souhaite - sauvegarder, ces liens seront mis à jour, non supprimés et re-sauvegardés. + dans la base de données vers certaines des entities que l'on souhaite + sauvegarder, ces liens seront mis à jour, et non supprimés et + re-sauvegardés. -Consultez :ref:`belongs-to-many-associations` pour plus de détails sur la -définition de ``saveStrategy``. +Consultez :ref:`belongs-to-many-associations` pour plus de détails sur la façon +de définir ``saveStrategy``. -Par défaut la stratégie ``replace`` est utilisée. Quand vous avez de nouveaux -enregistrements dans une association existante, vous devez toujours marquer -la propriété de l'association en 'dirty'. Ceci dit à l'ORM que la propriété -de l'association doit persister:: +Par défaut, l'ORM utilise la stratégie ``replace``. Si vous ajoutez à quelque +moment que ce soit de nouveaux enregistrements dans une association existante, +vous devez toujours marquer la propriété de l'association comme 'dirty'. Cela +fait savoir à l'ORM que la propriété de l'association doit être persistée:: $article->tags[] = $tag; $article->setDirty('tags', true); -Sans appel à ``setDirty()``, les tags mis à jour ne seront pas sauvegardés. +Sans appel à ``setDirty()``, les tags modifiés ne seront pas sauvegardés. -Vous vous voudrez probablement souvent créer une association entre deux entities -existantes, par exemple un utilisateur co-auteur d'un article. Cela est possible -en utilisant la méthode ``link()`` comme ceci:: +Vous vous retrouverez souvent à vouloir créer une association entre deux +entities existantes, par exemple un utilisateur co-auteur d'un article. Pour +cela, utilisez la méthode ``link()``:: $article = $this->Articles->get($articleId); $user = $this->Users->get($userId); @@ -1101,14 +1069,14 @@ en utilisant la méthode ``link()`` comme ceci:: $this->Articles->Users->link($article, [$user]); Lors de la sauvegarde d'associations belongsToMany, il peut être pertinent de -sauvegarder des données additionnelles dans la table de jointure. Dans -l'exemple précédent des tags, ça pourrait être le type de vote ``vote_type`` -de la personne qui a voté sur cet article. Le ``vote_type`` peut être ``upvote`` -ou ``downvote`` et est représenté par une chaîne de caractères. La relation est -entre Users et Articles. +sauvegarder des données supplémentaires dans la table de jointure. Dans +l'exemple précédent des tags, on pourrait imaginer le type de vote ``vote_type`` +de la personne qui a voté sur cet article. Le ``vote_type`` peut être soit +``upvote``, soit ``downvote``, et il est représenté par une chaîne de +caractères. La relation est entre Users et Articles. La sauvegarde de cette association et du ``vote_type`` est réalisée en ajoutant -tout d'abord des données à ``_joinData`` et ensuite en sauvegardant +tout d'abord des données à ``_joinData`` et en sauvegardant ensuite l'association avec ``link()``, par exemple:: $article = $this->Articles->get($articleId); @@ -1117,21 +1085,21 @@ l'association avec ``link()``, par exemple:: $user->_joinData = new Entity(['vote_type' => $voteType], ['markNew' => true]); $this->Articles->Users->link($article, [$user]); -Sauvegarder des Données Supplémentaires à la Table de Jointure --------------------------------------------------------------- +Sauvegarder des Données Supplémentaires dans la Table de Jointure +----------------------------------------------------------------- -Dans certaines situations, la table de jointure de l'association BelongsToMany, -aura des colonnes supplémentaires. CakePHP facilite la sauvegarde des -propriétés dans ces colonnes. Chaque entity dans une association belongsToMany -a une propriété ``_joinData`` qui contient les colonnes supplémentaires sur la +Dans certaines situations, vous aurez des colonnes supplémentaires dans la table +de jointure de l'association BelongsToMany. Avec CakePHP, il est facile d'y +sauvegarder des propriétés. Chaque entity d'une association belongsToMany a une +propriété ``_joinData`` qui contient les colonnes supplémentaires de la table de jointure. Ces données peuvent être soit un tableau, soit une instance -Entity. Par exemple si les Students BelongsToMany Courses, nous pourrions avoir +Entity. Par exemple, si les Students BelongsToMany Courses, nous pourrions avoir une table de jointure qui ressemble à ceci:: id | student_id | course_id | days_attended | grade Lors de la sauvegarde de données, vous pouvez remplir les colonnes -supplémentaires sur la table de jointure en définissant les données dans la +supplémentaires de la table de jointure en définissant les données dans la propriété ``_joinData``:: $student->courses[0]->_joinData->grade = 80.12; @@ -1140,9 +1108,9 @@ propriété ``_joinData``:: $studentsTable->save($student); La propriété ``_joinData`` peut être soit une entity, soit un tableau de données -si vous sauvegardez les entities construites à partir de données requêtées. -Lorsque vous sauvegardez des données de tables jointes depuis les données -requêtées, vos données POST doivent ressembler à ceci:: +si vous sauvegardez des entities construites à partir de données de la requête. +Lorsque vous sauvegardez des données de la table de jointure à partir de données +de la requête, vos données POST doivent ressembler à ceci:: $data = [ 'first_name' => 'Sally', @@ -1162,9 +1130,9 @@ requêtées, vos données POST doivent ressembler à ceci:: 'associated' => ['Courses._joinData'] ]); -Regardez le chapitre sur les :ref:`inputs pour les données associées -` pour savoir comment construire des inputs avec -le ``FormHelper`` correctement. +Consultez le chapitre sur les :ref:`inputs pour les données associées +` pour savoir comment construire correctement des inputs +avec le ``FormHelper``. .. _saving-complex-types: @@ -1172,72 +1140,67 @@ Sauvegarder les Types Complexes ------------------------------- Les tables peuvent stocker des données représentées dans des types basiques, -comme les chaînes, les integers, floats, booleans, etc... Mais elles peuvent -aussi être étendues pour accepter plus de types complexes comme les tableaux ou -les objets et sérialiser ces données en types plus simples qui peuvent être +comme des chaînes, integers, floats, booleans, etc... Mais elles peuvent +aussi être étendues pour accepter des types plus complexes comme des tableaux ou +des objets et sérialiser ces données en types plus simples qui peuvent être sauvegardés dans la base de données. -Cette fonctionnalité se fait en utilisant le système personnalisé de types. -Consulter la section :ref:`adding-custom-database-types` pour trouver comment -construire les Types de colonne personnalisés:: - - // Dans config/bootstrap.php +Pour cela, vous devez utiliser le système de types personnalisés. +Consulter la section :ref:`adding-custom-database-types` pour savoir comment +construire des Types de colonnes personnalisés:: use Cake\Database\TypeFactory; TypeFactory::map('json', 'Cake\Database\Type\JsonType'); // Dans src/Model/Table/UsersTable.php - use Cake\Database\Schema\TableSchema; class UsersTable extends Table { - protected function _initializeSchema(TableSchema $schema) + public function initialize(): void { - $schema->columnType('preferences', 'json'); - return $schema; + $this->getSchema()->setColumnType('preferences', 'json'); } } -Le code ci-dessus correspond à la colonne ``preferences`` pour le type -personnalisé ``json``. -Cela signifie que quand on récupère des données pour cette colonne, elles seront -désérialisées à partir d'une chaîne JSON dans la base de données et mises dans -une entity en tant que tableau. +Le code ci-dessus fait correspondre la colonne ``preferences`` au type +personnalisé ``json``. Cela signifie que lorsque vous récupérez des données de +cette colonne, les chaînes JSON de la base de données seront désérialisées et +insérées dans une entity sous forme de tableau. -Comme ceci, lors de la sauvegarde, le tableau sera transformé à nouveau en sa -représentation JSON:: +De même, lors de la sauvegarde, le tableau sera à nouveau transformé au format +JSON:: $user = new User([ 'preferences' => [ 'sports' => ['football', 'baseball'], - 'books' => ['Mastering PHP', 'Hamlet'] + 'books' => ['Maîtriser le PHP', 'Hamlet'] ] ]); $usersTable->save($user); -Lors de l'utilisation de types complexes, il est important de vérifier que les -données que vous recevez de l'utilisateur final sont valides. Ne pas gérer -correctement les données complexes va permettre à des utilisateurs mal -intentionnés d'être capable de stocker des données qu'ils ne pourraient pas -stocker normalement. +Quand vous utilisez des types complexes, il est important de vérifier que les +données que vous recevez de l'utilisateur final correspondent au bon type. +Sinon, en ne traitant pas correctement les données complexes, vous vous exposez +à ce que des utilisateurs malveillants puissent stocker des données qu'ils +n'auraient normalement pas le droit de stocker. Strict Saving ============= .. php:method:: saveOrFail($entity, $options = []) -Utiliser cette méthode lancera une :php:exc:`Cake\\ORM\\Exception\\PersistenceFailedException` -si: +L'appel à cette méthode lancera une +:php:exc:`Cake\\ORM\\Exception\\PersistenceFailedException` si: * les règles de validation ont échoué * l'entity contient des erreurs * la sauvegarde a été annulée par un _callback_. -Utiliser cette méthode peut être utile pour effectuer des opérations complexes -en base de données sans surveillance humaine comme lors de l'utilisation de +Cette méthode peut être utile pour effectuer des opérations complexes sur la +base de données sans surveillance humaine, comme lors de l'utilisation de script via des _tasks_ Shell. .. note:: @@ -1254,22 +1217,68 @@ utiliser la méthode :php:meth:`Cake\\ORM\Exception\\PersistenceFailedException: echo $e->getEntity(); } -Puisque cette méthode utilise la méthode :php:meth:`Cake\\ORM\\Table::save()`, -tous les événements de ``save`` seront déclenchés. +Dans la mesure où cette méthode utilise la méthode +:php:meth:`Cake\\ORM\\Table::save()`, tous les événements de ``save`` seront +déclenchés. + +Trouver Ou Créer une Entity +=========================== + +.. php:method:: findOrCreate($search, $callback = null, $options = []) + +Trouve un enregistrement d'après les critères de ``$search`` ou crée un nouvel +enregistrement en utilisant les propriétés de ``$search`` et en appelant la +méthode optionnelle ``$callback``. Cette méthode est idéale dans les scénarios +où vous avez besoin réduire les risque de doublons:: + + $record = $table->findOrCreate( + ['email' => 'bobbi@example.com'], + function ($entity) use ($autresDonnees) { + // Appelé seulement en cas de création d'un nouvel enregistrement + $entity->name = $autresDonnees['name']; + } + ); + +Si vos conditions pour ``find`` nécessitent un tri, des associations ou des +conditions personnalisés, alors le paramètre ``$search`` peut être un _callable_ +ou un objet ``Query``. Si vous utilisez un _callable_, il est censé prendre un +objet ``Query`` comme argument. + +L'entité renvoyée aura été sauvegardée s'il s'agit d'un nouvel enregistrement. +Cette méthode supporte les options suivantes: + +* ``atomic`` Si les opérations ``find`` et ``save`` sont censées être effectuées + à l'intérieur d'une transaction. +* ``defaults`` Défini à ``false`` pour ne pas définir les propriétés ``$search`` + dans l'entity créée. + +Créer Avec une Clé Primaire +=========================== + +Quand vous traitez des clés primaires UUID, vous avez souvent besoin de fournir +une valeur générée ailleurs, au lieu d'un identifiant autogénéré pour vous. Dans +ce cas, assurez-vous de ne pas passer la clé primaire au milieu des autres +données. Au lieu de cela, assignez la clé primaire puis patchez les autres +données dans l'entity:: + + $record = $table->newEmptyEntity(); + $record->id = $existingUuid; + $record = $table->patchEntity($record, $existingData); + $table->saveOrFail($record); Sauvegarder Plusieurs Entities ============================== .. php:method:: saveMany($entities, $options = []) -En utilisant cette méthode, vous pouvez sauvegarder plusieurs entities de façon -atomique. ``$entities`` peuvent être un tableau d'entities créé avec -``newEntities()`` / ``patchEntities()``. ``$options`` peut avoir les mêmes -options que celles acceptées par ``save()``:: +Cette méthode vous permet de sauvegarder plusieurs entities de façon atomique. +``$entities`` peut être un tableau d'entities créées avec ``newEntities()`` / +``patchEntities()``. ``$options`` peut avoir les mêmes options que celles +acceptées par ``save()``:: $data = [ [ - 'title' => 'First post', + 'title' => 'Premier post', 'published' => 1 ], [ @@ -1278,12 +1287,11 @@ options que celles acceptées par ``save()``:: ], ]; - // Prior to 3.6 use TableRegistry::get('Articles') - $articles = TableRegistry::getTableLocator()->get('Articles'); + $articles = $this->getTableLocator()->get('Articles'); $entities = $articles->newEntities($data); $result = $articles->saveMany($entities); -Le résultat sera la mise à jour des entities en cas de succès ou ``false`` en +La méthode renvoie les entities mises à jour en cas de succès, ou ``false`` en cas d'échec. Mises à Jour en Masse @@ -1291,16 +1299,23 @@ Mises à Jour en Masse .. php:method:: updateAll($fields, $conditions) -Il peut arriver que la mise à jour de lignes individuellement n'est pas efficace -ou pas nécessaire. Dans ces cas, il est plus efficace d'utiliser une mise à jour -en masse pour modifier plusieurs lignes en une fois:: +Il y a des cas où la mise à jour de lignes individuelles n'est pas efficace ni +nécessaire. Dans ce cas, il est préférable d'utiliser une mise à jour en masse +pour modifier plusieurs lignes en une fois, en assignant les nouvelles valeurs +des champs et les conditions de mise à jour:: // Publie tous les articles non publiés. function publishAllUnpublished() { $this->updateAll( - ['published' => true], // champs - ['published' => false]); // conditions + [ // champs + 'published' => true, + 'publish_date' => FrozenTime::now() + ], + [ // conditions + 'published' => false + ] + ); } Si vous devez faire des mises à jour en masse et utiliser des expressions SQL, @@ -1317,7 +1332,7 @@ requêtes préparées sous le capot:: $this->updateAll([$expression], ['published' => true]); } -Une mise à jour en masse sera considérée comme un succès si une ou plusieurs +Une mise à jour en masse sera considérée comme réussie si une ou plusieurs lignes sont mises à jour. .. warning:: @@ -1326,7 +1341,7 @@ lignes sont mises à jour. avez besoin de ceux-ci, chargez d'abord une collection d'enregistrements et mettez les à jour. -``updateAll()`` est uniquement une fonction de commodité. Vous pouvez également +``updateAll()`` est seulement une fonction de commodité. Vous pouvez également utiliser cette interface plus flexible:: // Publication de tous les articles non publiés. From 0df0d28878a3783d6e2c7d7fcb010cc3bac53588 Mon Sep 17 00:00:00 2001 From: zachee54 Date: Sat, 8 Jul 2023 15:47:45 +0200 Subject: [PATCH 36/53] [fr] First translation of console-commands.rst --- fr/console-commands.rst | 176 +++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 84 deletions(-) diff --git a/fr/console-commands.rst b/fr/console-commands.rst index f8ecb8d654..c5fd46fa62 100644 --- a/fr/console-commands.rst +++ b/fr/console-commands.rst @@ -1,27 +1,30 @@ -Console Commands -################ +Commandes sur la Console +######################## .. php:namespace:: Cake\Console -In addition to a web framework, CakePHP also provides a console framework for -creating command line tools & applications. Console applications are ideal for -handling a variety of background & maintenance tasks that leverage your existing -application configuratino, models, plugins and domain logic. +En plus d'un framework web, CakePHP fournit aussi un framework de console pour +créer des outils et applications en ligne de commande. Les applications sur +console sont idéales pour traiter diverses tâches en arrière-plan ou opérations +de maintenance qui influent sur la configuration existante de votre application, +vos modèles, plugin et logique de domaine. -CakePHP provides several console tools for interacting with CakePHP features -like i18n and routing that enable you to introspect your application and -generate related files. +CakePHP propose plusieurs outils de console pour interagir avec les +fonctionnalités de CakePHP telles que l'internationalisation et le routage, qui +vous permettent d'introspecter votre application et des générer des fichiers +correspondant. -The CakePHP Console -=================== +La Console CakePHP +================== -The CakePHP Console uses a dispatcher-type system to load a commands, parse -their arguments and invoke the correct command. While the examples below use -bash the CakePHP console is compatible with any \*nix shell and windows. +La console CakePHP utilise un système de type dispatcher pour charger des +commandes, parser leurs arguments et appeler la bonne commande. Les exemples +qui suivent utilisent bash ; cependant la console CakePHP est compatible avec +n'importe quel shell \*nix et Windows. -A CakePHP application contains **src/Command**, **src/Shell** and -**src/Shell/Task** directories that contain its shells and tasks. It also -comes with an executable in the **bin** directory: +Une application CakePHP contient les répertoires **src/Command**, **src/Shell** +et **src/Shell/Task**, qui contiennent ses shells et ses tâches. Elle est aussi +livrée avec un exécutable dans le répertoire **bin**: .. code-block:: console @@ -30,104 +33,108 @@ comes with an executable in the **bin** directory: .. note:: - For Windows, the command needs to be ``bin\cake`` (note the backslash). + Pour Windows, il faut taper la commande ``bin\cake`` (notez le backslash). -Running the Console with no arguments will list out available commands. You -could then run the any of the listed commands by using its name: +Si vous lancez la Console sans arguments, vous obtiendrez la liste des commandes +disponibles. Vous pouvez ensuite lancer une de ces commandes en tapant son nom: .. code-block:: console - # run server shell + # lancer le shell du serveur bin/cake server - # run migrations shell + # lancer le shell des migrations bin/cake migrations -h - # run bake (with plugin prefix) + # lancer bake (avec un préfixe de plugin) bin/cake bake.bake -h -Plugin commands can be invoked without a plugin prefix if the commands's name -does not overlap with an application or framework shell. In the case that two -plugins provide a command with the same name, the first loaded plugin will get -the short alias. You can always use the ``plugin.command`` format to -unambiguously reference a command. +Vous pouvez appeler des commandes de plugin sans le préfixe du plugin si le nom +de la commande n'entre pas en collision avec un shell de l'application ou du +framework. Dans le cas où deux plugins proposent une commande avec le même nom, +l'alias court correspondra au plugin chargé en premier. Vous pouvez toujours +utiliser le format ``plugin.command`` pour faire référence à une commande de +manière non ambigüe. -Console Applications -==================== +Applications sur Console +======================== -By default CakePHP will automatically discover all the commands in your -application and its plugins. You may want to reduce the number of exposed -commands, when building standalone console applications. You can use your -``Application``'s ``console()`` hook to limit which commands are exposed and -rename commands that are exposed:: +Par défaut, CakePHP cherchera automatiquement toutes les commandes dans votre +application et vos plugins. Quand vous créerez des applications autonoms sur +console, vous voudrez peut-être restreindre le nombre de commandes accessibles. +Vous pouvez utiliser le crochet ``console()`` de ``Application`` pour limiter et +renommer les commandes exposées:: - // in src/Application.php + // dans src/Application.php namespace App; - use App\Shell\UserShell; - use App\Shell\VersionShell; + use App\Command\UserCommand; + use App\Command\VersionCommand; + use Cake\Console\CommandCollection; use Cake\Http\BaseApplication; class Application extends BaseApplication { - public function console($commands) + public function console(CommandCollection $commands): CommandCollection { - // Add by classname + // Ajouter par nom de classe $commands->add('user', UserCommand::class); - // Add instance + // Ajouter une instance $commands->add('version', new VersionCommand()); return $commands; } } -In the above example, the only commands available would be ``help``, ``version`` -and ``user``. See the `plugin-commands` section for how to add commands in -your plugins. +Dans cet exemple, seules les commandes ``help``, ``version`` et ``user`` +seraient disponibles. Consultez la section :ref:`plugin-commands` pour savoir +comment ajouter des commandes dans vos plugins. .. note:: - When adding multiple commands that use the same Command class, the ``help`` - command will display the shortest option. + Quand vous ajoutez plusieurs commandes qui utilisent la même classe Command, + la commande ``help`` affichera l'option la plus courte. .. _renaming-commands: .. index:: nested commands, subcommands -Renaming Commands -================= +Renommer des Commandes +====================== -There are cases where you will want to rename commands, to create nested -commands or subcommands. While the default auto-discovery of commands will not -do this, you can register your commands to create any desired naming. +Dans certains cas, vous aurez besoin de renommer des commandes, ou de créer des +commandes imbriquées ou des sous-commandes. La découverte automatique des +commandes ne fera pas cela, cependant vous pouvez déclarer vos commandes pour +créer la dénomination désirée. -You can customize the command names by defining each command in your plugin:: +Vous pouvez personnaliser les noms de commandes en définissant chaque commande +dans votre plugin:: - public function console($commands) + public function console(CommandCollection $commands): CommandCollection { - // Add commands with nested naming + // Ajouter des commandes avec une dénomintaion imbriquée $commands->add('user dump', UserDumpCommand::class); $commands->add('user:show', UserShowCommand::class); - // Rename a command entirely + // Renommer entièrement une commande $commands->add('lazer', UserDeleteCommand::class); return $commands; } -When overriding the ``console()`` hook in your application, remember to -call ``$commands->autoDiscover()`` to add commands from CakePHP, your -application, and plugins. +Quand vous réécrivez le crochet ``console()`` de votre application, pensez à +appeler ``$commands->autoDiscover()`` pour ajouter des commandes de CakePHP, de +votre application, et des plugins. -If you need to rename/remove any attached commands, you can use the -``Console.buildCommands`` event on your application event manager to modify the -available commands. +Si vous avez besoin de renommer ou supprimer une commande attachée, vous pouvez +utiliser l'événement ``Console.buildCommands`` dans le gestionnaire d'événements +de votre application pour modifier les commandes disponibles. -Commands -======== +Commandes +========= -See the :doc:`/console-commands/commands` chapter on how to create your first -command. Then learn more about commands: +Rendez-vous au chapitre :doc:`/console-commands/commands` pour créer votre +première commande. Puis, pour en savoir plus sur les commandes: .. toctree:: :maxdepth: 1 @@ -137,8 +144,8 @@ command. Then learn more about commands: console-commands/option-parsers console-commands/cron-jobs -CakePHP Provided Commands -========================= +Commandes Fournies par CakePHP +============================== .. toctree:: :maxdepth: 1 @@ -148,36 +155,37 @@ CakePHP Provided Commands console-commands/i18n console-commands/plugin console-commands/schema-cache + console-commands/routes console-commands/server - console-commands/shells console-commands/repl - console-commands/routes + console-commands/shells -Routing in the Console Environment -================================== +Routage dans l'Environnement de la Console +========================================== -In command-line interface (CLI), specifically your shells and tasks, -``env('HTTP_HOST')`` and other webbrowser specific environment variables are not -set. +En ligne de commande (CLI), et spécifiquement dans vos shells et vos tâches, +``env('HTTP_HOST')`` et les autres variables d'environnement spécifiques au +serveur web ne sont pas définies. -If you generate reports or send emails that make use of ``Router::url()`` those -will contain the default host ``http://localhost/`` and thus resulting in -invalid URLs. In this case you need to specify the domain manually. -You can do that using the Configure value ``App.fullBaseUrl`` from your -bootstrap or config, for example. +Si vous générez des rapports ou si vous envoyez des mails qui utilisent00 +``Router::url()``, ils contiendront l'hôte par défaut ``http://localhost/``, et +donc ils produiront des URL invalides. Dans un tel cas, vous devez spécifier le +domaine manuellement. Vous pouvez utiliser pour cela la valeur +``App.fullBaseUrl`` de Configure depuis votre bootstrap ou votre configuration, +par exemple. -For sending emails, you should provide Email class with the host you want to -send the email with:: +Pour envoyer des mails, vous devrez fournir une classe Email avec l'hôte à +partir duquel vous voulez envoyer le mail:: use Cake\Mailer\Email; $email = new Email(); $email->setDomain('www.example.org'); -This asserts that the generated message IDs are valid and fit to the domain the -emails are sent from. +Cela suppose que les IDs du message généré soient valides et correspondent au +domaine à partir duquel les mails sont envoyés. .. meta:: - :title lang=en: Shells, Tasks & Console Tools + :title lang=fr: Shells, Tâches & Outils de Console :keywords lang=en: shell scripts,system shell,application classes,background tasks,line script,cron job,request response,system path,acl,new projects,shells,specifics,parameters,i18n,cakephp,directory,maintenance,ideal,applications,mvc From 91144ef2c48dcee1b19ba915c69d591e13886457 Mon Sep 17 00:00:00 2001 From: zachee54 Date: Sat, 8 Jul 2023 22:03:10 +0200 Subject: [PATCH 37/53] [fr] Update translation of commands.rst --- fr/console-commands/commands.rst | 283 +++++++++++++++++++------------ 1 file changed, 172 insertions(+), 111 deletions(-) diff --git a/fr/console-commands/commands.rst b/fr/console-commands/commands.rst index 034fb709c3..6a4f6bf5e4 100644 --- a/fr/console-commands/commands.rst +++ b/fr/console-commands/commands.rst @@ -1,5 +1,5 @@ -Commandes de la Console -####################### +Objets Command +############## .. php:namespace:: Cake\Console .. php:class:: Command @@ -13,8 +13,9 @@ Créer une Commande Créons maintenant notre première commande. Pour cet exemple, nous allons créer une commande Hello world toute simple. Dans le répertoire **src/Command** de votre application, créez -**HelloCommand.php**. Mettez dedans le code qui suit:: +**HelloCommand.php**. Mettez-y le code suivant:: + out('Hello world.'); + + return static::CODE_SUCCESS; } } Les classes Command doivent avoir une méthode ``execute()`` qui fait la plus grande partie du travail. -Cette méthode est appelée quand une commande est appelée. Appelons la première commande de notre +Cette méthode est appelée quand une commande est lancée. Appelons la première commande de notre application, exécutez: .. code-block:: console @@ -43,6 +46,7 @@ Vous devriez voir la sortie suivante:: Notre méthode ``execute()`` n'est pas très intéressente, ajoutons des entrées à partir de la ligne de commande:: + addArgument('name', [ - 'help' => 'What is your name' + 'help' => 'Quel est votre nom' ]); return $parser; } - public function execute(Arguments $args, ConsoleIo $io) + public function execute(Arguments $args, ConsoleIo $io): int { $name = $args->getArgument('name'); $io->out("Hello {$name}."); + + return static::CODE_SUCCESS; } } @@ -76,6 +82,21 @@ Après avoir sauvegardé ce fichier, vous devriez pouvoir exécuter la commande # Affiche Hello jillian + +Changer le Nom Par Défaut de la Commande +======================================== + +CakePHP va s'appuyer sur des conventions pour générer le nom que vos commandes +utilisent en ligne de commande. Si vous voulez remplacer le nom généré, +implémentez la méthode ``defaultName()`` dans votre commande:: + + public static function defaultName(): string + { + return 'oh_hi'; + } + +Ceci rendrait ``HelloCommand`` accessible par ``cake oh_hi`` au lieu de +``cake hello``. Définir les Arguments et les Options ==================================== @@ -85,27 +106,29 @@ pour définir des arguments. Nous pouvons aussi définir des options. Par exempl ``yell`` à notre ``HelloCommand``:: // ... - public function buildOptionParser(ConsoleOptionParser $parser) + protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { $parser ->addArgument('name', [ - 'help' => 'What is your name' + 'help' => 'Quel est votre nom' ]) ->addOption('yell', [ - 'help' => 'Shout the name', + 'help' => 'Crier le nom', 'boolean' => true ]); return $parser; } - public function execute(Arguments $args, ConsoleIo $io) + public function execute(Arguments $args, ConsoleIo $io): int { $name = $args->getArgument('name'); if ($args->getOption('yell')) { $name = mb_strtoupper($name); } $io->out("Hello {$name}."); + + return static::CODE_SUCCESS; } Consultez la section :doc:`/console-commands/option-parsers` pour plus d'information. @@ -113,17 +136,21 @@ Consultez la section :doc:`/console-commands/option-parsers` pour plus d'informa Créer une Sortie ================ -Les commands fournissent une instance ``ConsoleIo`` quand elles sont exécutées. Cet objet vous permet -d'intéragir avec ``stdout``, ``stderr`` et de créer des fichiers. Consultez la section -:doc:`/console-commands/input-output` pour plus d'information. +Les commands reçoivent une instance ``ConsoleIo`` quand elles sont exécutées. +Cet objet vous permet d'interagir avec ``stdout``, ``stderr`` et de créer des +fichiers. Consultez la section :doc:`/console-commands/input-output` pour plus +d'information. Utiliser les Models dans les Commands ===================================== -Vous aurez souvent besoin d'accéder à logique applicative dans les commandes console. Vous pouvez charger les models -dans les commandes, comme vous le feriez dans un controller en utilisant ``loadModel()``. Les models chargés sont définis en -propriétés attachés à vos commandes:: +Vous aurez souvent besoin d'accéder à logique métier de votre application depuis +les commandes console. Vous pouvez charger des modèles dans les commandes, +exactement comme vous le feriez dans un controller en utilisant +``$this->fetchTable()``, puisque les commandes utilisent ``LocatorAwareTrait``:: + loadModel('Users'); - } + // Définit la table par défaut. Cela vous permet d'utiliser `fetchTable()` sans argument. + protected $defaultTable = 'Users'; - public function buildOptionParser(ConsoleOptionParser $parser) + protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { $parser ->addArgument('name', [ - 'help' => 'What is your name' + 'help' => 'Quel est votre nom' ]); return $parser; } - public function execute(Arguments $args, ConsoleIo $io) + public function execute(Arguments $args, ConsoleIo $io): int { $name = $args->getArgument('name'); - $user = $this->Users->findByUsername($name)->first(); + $user = $this->fetchTable()->findByUsername($name)->first(); $io->out(print_r($user, true)); + + return static::CODE_SUCCESS; } } La commande ci-dessus va récupérer un utilisateur par son nom d'utilisateur et afficher les informations stockées dans la base de données. -Sortir du Code et Arrêter l'Execution -===================================== +Codes de Sortie et Arrêter l'Execution +====================================== Quand vos commandes rencontrent une erreur irrécupérable, vous pouvez utiliser la méthode ``abort()`` pour terminer l'exécution:: // ... - public function execute(Arguments $args, ConsoleIo $io) + public function execute(Arguments $args, ConsoleIo $io): int { $name = $args->getArgument('name'); if (strlen($name) < 5) { @@ -176,18 +202,36 @@ l'exécution:: $io->error('Name must be at least 4 characters long.'); $this->abort(); } + + return static::CODE_SUCCESS; } -Vous pouvez passer tout code de sortie souhaité dans ``abort()``. +Vous pouvez aussi utiliser ``abort()`` sur l'objet ``$io`` pour émettre un +message et un code:: + + public function execute(Arguments $args, ConsoleIo $io): int + { + $name = $args->getArgument('name'); + if (strlen($name) < 5) { + // Arrête l'exécution, affiche vers stderr, et définit le code de sortie à 99 + $io->abort('Le nom doit avoir au moins 4 caractères.', 99); + } + + return static::CODE_SUCCESS; + } + +Vous pouvez passer n'importe quel code de sortie dans ``abort()``. .. tip:: - Evitez les codes de sortie 64 - 78, car ils ont une signification particulière décrite par - ``sysexits.h``. Evitez les codes de sortie au-dessus de 127, car ils sont utilisés pour indiquer une - de processus par signal tel que SIGKILL ou SIGSEGV. + Évitez les codes de sortie 64 - 78, car ils ont une signification + particulière décrite par ``sysexits.h``. Évitez les codes de sortie + au-dessus de 127, car ils sont utilisés pour indiquer une sortie de + processus par signal tel que SIGKILL ou SIGSEGV. - Vous pouvez en apprendre plus sur les codes de sortie dans la page sysexit du manuel de la plupart des systèmes - Unix (``man sysexits``), ou la page d'aide sur les ``Codes de Sortie Système`` dans Windows. + Vous pouvez en savoir plus à propos des codes de sortie sur la manpage de + sysexit sur la plupart des systèmes Unix (``man sysexits``), ou la page + d'aide ``System Error Codes`` sous Windows. Appeler d'Autres Commandes ========================== @@ -204,15 +248,15 @@ Pour ce faire, utilisez ``executeCommand``:: .. note:: - QUand vous appelez ``executeCommand()`` dans une boucle, il est recommandé - de passer l'instance ``ConsoleIo`` en tant que 3ème argument optionnel dans - la commande parente pour éviter une potentielle limite de fichiers ouverts, - qui pourrait arriver dans certains environnements. + Quand vous appelez ``executeCommand()`` dans une boucle, il est recommandé + de passer l'instance ``ConsoleIo`` de la commande parente en 3ème argument + optionnel pour éviter une potentielle limite de fichiers ouverts, ce qui + pourrait arriver dans certains environnements. .. _console-command-description: -Définir une Description de Commande -=================================== +Définir la Description de la Commande +===================================== Vous pouvez définir une description de commande via:: @@ -224,7 +268,7 @@ Vous pouvez définir une description de commande via:: } } -Cela affichera votre description dans le CLI Cake: +Cela affichera votre description dans la CLI de Cake: .. code-block:: console @@ -244,20 +288,25 @@ Ainsi que dans la section *help* de votre commande: Usage: cake user [-h] [-q] [-v] - .. _console-integration-testing: Tester les Commandes ==================== -Pour faciliter les tests des applications de console, CakePHP fournit une classe -``ConsoleIntegrationTestCase`` qui peut être utilisée pour tester les applications console -et faire des assertions de résultats. +Pour faciliter les tests des applications de console, CakePHP fournit le trait +``ConsoleIntegrationTestTrait`` que vous pouvez utiliser pour tester les +applications console et faire des assertions sur leurs résultats. + +Pour commencer à tester votre application de console, créez un cas de test qui +utilise le trait ``Cake\TestSuite\ConsoleIntegrationTestTrait``. Ce trait +contient une méthode ``exec()`` qui est utilisée pour exécuter votre commande. +Vous pouvez y passer la même chaîne que celle que vous passeriez en ligne de +commande. + +.. note:: -Pour commencer à tester votre application console, créez un cas de test qui étend -``Cake\TestSuite\ConsoleIntegrationTestCase``. cette classe contient une méthode -``exec()`` qui est utilisée pour exécuter votre commande. Vous pouvez passer la même chaîne à cette méthode -que ce que vous passeriez dans le CLI. + Pour CakePHP 4.4 et au-delà, il faut utiliser le namespace de + ``Cake\Console\TestSuite\ConsoleIntegrationTestTrait`` Commençons avec une commande très simple qui se trouve dans **src/Command/UpdateTableCommand.php**:: @@ -271,26 +320,29 @@ Commençons avec une commande très simple qui se trouve dans class UpdateTableCommand extends Command { - public function buildOptionParser(ConsoleOptionParser $parser) + protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { - $parser->setDescription('My cool console app'); + $parser->setDescription('Mon application de console super cool'); return $parser; } } Pour écrire un test d'intégration pour ce shell, nous créons un cas de test dans -**tests/TestCase/Command/UpdateTableCommandTest.php** qui étend -``Cake\TestSuite\ConsoleIntegrationTestCase``. Ce shell ne fait pas grand chose pour le +**tests/TestCase/Command/UpdateTableTest.php** qui utilise le trait +``Cake\TestSuite\ConsoleIntegrationTestTrait``. Ce shell ne fait pas grand chose pour le moment, mais testons simplement si la description de notre shell description s'affiche dans ``stdout``:: namespace App\Test\TestCase\Command; - use Cake\TestSuite\ConsoleIntegrationTestCase; - - class UpdateTableCommandTest extends ConsoleIntegrationTestCase + use Cake\TestSuite\ConsoleIntegrationTestTrait; + use Cake\TestSuite\TestCase; + + class UpdateTableCommandTest extends TestCase { - public function setUp() + user ConsoleIntegrationTestTrait; + + public function setUp(): void { parent::setUp(); $this->useCommandRunner(); @@ -299,7 +351,7 @@ moment, mais testons simplement si la description de notre shell description s'a public function testDescriptionOutput() { $this->exec('update_table --help'); - $this->assertOutputContains('My cool console app'); + $this->assertOutputContains('Mon application de console super cool'); } } @@ -318,52 +370,55 @@ notre commande:: class UpdateTableCommand extends Command { - public function buildOptionParser(ConsoleOptionParser $parser) + protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { $parser - ->setDescription('My cool console app') + ->setDescription('Mon application de console super cool') ->addArgument('table', [ - 'help' => 'Table to update', + 'help' => 'Table à mettre à jour', 'required' => true ]); return $parser; } - public function execute(Arguments $args, ConsoleIo $io) + public function execute(Arguments $args, ConsoleIo $io): int { $table = $args->getArgument('table'); - $this->loadModel($table); - $this->{$table}->query() + $this->fetchTable($table)->query() ->update() ->set([ 'modified' => new FrozenTime() ]) ->execute(); + + return static::CODE_SUCCESS; } } -C'est un shell plus complet qui a des options obligatoires et de logique associée. -Modifions notre cas de test pour avoir le bout de code suivant:: +C'est un shell plus complet qui a des options obligatoires et une logique +associée. Modifions notre cas de test en y intégrant le code suivant:: namespace Cake\Test\TestCase\Command; use Cake\Command\Command; use Cake\I18n\FrozenTime; - use Cake\ORM\TableRegistry; - use Cake\TestSuite\ConsoleIntegrationTestCase; + use Cake\TestSuite\ConsoleIntegrationTestTrait; + use Cake\TestSuite\TestCase; - class UpdateTableCommandTest extends ConsoleIntegrationTestCase + class UpdateTableCommandTest extends TestCase { - public $fixtures = [ - // assumes you have a UsersFixture - 'app.users' + use ConsoleIntegrationTestTrait; + + protected $fixtures = [ + // assume que vous avez une UsersFixture + 'app.Users' ]; public function testDescriptionOutput() { $this->exec('update_table --help'); - $this->assertOutputContains('My cool console app'); + $this->assertOutputContains('Mon application de console super cool'); } public function testUpdateModified() @@ -376,17 +431,19 @@ Modifions notre cas de test pour avoir le bout de code suivant:: $this->exec('update_table Users'); $this->assertExitCode(Command::CODE_SUCCESS); - $user = TableRegistry::get('Users')->get(1); + $user = $this->getTableLocator()->get('Users')->get(1); $this->assertSame($user->modified->timestamp, $now->timestamp); FrozenTime::setTestNow(null); } } -Comme vous pouvez le voir dans la méthode ``testUpdateModified``, nous testons que notre commande -met à jour la table que nous passons en premier argument. Premièrement, nous faisons l'assertion que la commande -sort avec le bon code de sortie ``0``. Ensuite nous vérifions que notre commande a fait le travail, qui est de mettre -à jour la table que nous avons fourni et définit la colonne ``modified`` à la date actuelle. +Comme vous pouvez le voir dans la méthode ``testUpdateModified``, nous testons +que notre commande met à jour la table que nous passons en premier argument. +Premièrement, nous faisons l'assertion que la commande se termine avec le bon +code de sortie ``0``. Ensuite nous vérifions que notre commande a fait le +travail, qui est de mettre à jour la table que nous avons fournie et d'insérer +la date et l'heure actuelle dans la colonne ``modified``. Souvenez-vous que ``exec()`` va prendre la même chaîne que si vous tapiez dans le CLI, donc vous pouvez inclure des options et des arguments dans la chaîne de votre commande. @@ -394,12 +451,13 @@ et des arguments dans la chaîne de votre commande. Tester les Shells Interactifs ----------------------------- -Les consoles sont souvent interactives. Tester les shells intéractifs avec la classe -``Cake\TestSuite\ConsoleIntegrationTestCase`` nécessite seulement de passer les entrées en deuxième paramètre -de ``exec()``. Ils doivent être inclus en tableau dans l'ordre dans lequel vous les souhaitez. +Les consoles sont souvent interactives. Pour tester les shells interactifs avec +le trait ``Cake\TestSuite\ConsoleIntegrationTestTrait``, vous devez seulement +passer les entrées attendues en deuxième paramètre de ``exec()``. Ils doivent +être présentés dans un tableau dans l'ordre dans lequel vous voulez les passer. -Continuons notre exemple de commande, et ajoutons une confirmation intéractive. -Mettez à jour la classe command avec ce qui suit:: +Continuons notre exemple de commande, et ajoutons une confirmation interactive. +Mettez à jour la classe de commande de la façon suivante:: namespace App\Command; @@ -411,38 +469,41 @@ Mettez à jour la classe command avec ce qui suit:: class UpdateTableCommand extends Command { - public function buildOptionParser(ConsoleOptionParser $parser) + protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { $parser - ->setDescription('My cool console app') + ->setDescription('Mon application de console super cool') ->addArgument('table', [ - 'help' => 'Table to update', + 'help' => 'Table à mettre à jour', 'required' => true ]); return $parser; } - public function execute(Arguments $args, ConsoleIo $io) + public function execute(Arguments $args, ConsoleIo $io): int { $table = $args->getArgument('table'); $this->loadModel($table); - if ($io->ask('Are you sure?', 'n', ['y', 'n']) === 'n') { - $io->error('You need to be sure.'); + if ($io->ask('Êtes-vous sûr ?', 'n', ['o', 'n']) === 'n') { + $io->error('Vous devez être sûr.'); $this->abort(); } - $this->{$table}->query() + $this->fetchTable($table)->query() ->update() ->set([ 'modified' => new FrozenTime() ]) ->execute(); + + return static::CODE_SUCCESS; } } -Maintenant que nous avons une sous-commande intéractive, nous pouvons ajouter un cas de test qui vérifie -que nous recevons les bonnes réponses et un qui vérifie que nous recevons une réponse incorrecte. Retirez la -méthode ``testUpdateModified`` et ajoutez les méthodes qui suivent dans +Maintenant que nous avons une sous-commande interactive, nous pouvons ajouter un +cas de test qui vérifie que nous recevons une réponse positive et un qui vérifie +que nous recevons une réponse négative. Retirez la méthode +``testUpdateModified`` et ajoutez les méthodes qui suivent dans **tests/TestCase/Command/UpdateTableCommandTest.php**:: @@ -453,10 +514,10 @@ méthode ``testUpdateModified`` et ajoutez les méthodes qui suivent dans $this->loadFixtures('Users'); - $this->exec('update_table Users', ['y']); + $this->exec('update_table Users', ['o']); $this->assertExitCode(Command::CODE_SUCCESS); - $user = TableRegistry::get('Users')->get(1); + $user = $this->getTableLocator()->get('Users')->get(1); $this->assertSame($user->modified->timestamp, $now->timestamp); FrozenTime::setTestNow(null); @@ -464,47 +525,47 @@ méthode ``testUpdateModified`` et ajoutez les méthodes qui suivent dans public function testUpdateModifiedUnsure() { - $user = TableRegistry::get('Users')->get(1); + $user = $this->getTableLocator()->get('Users')->get(1); $original = $user->modified->timestamp; $this->exec('my_console best_framework', ['n']); $this->assertExitCode(Command::CODE_ERROR); $this->assertErrorContains('You need to be sure.'); - $user = TableRegistry::get('Users')->get(1); + $user = $this->getTableLocator()->get('Users')->get(1); $this->assertSame($original, $user->timestamp); } -Dans les premiers cas de test, nous confirmons la question, et les enregistrements sont mis à jour. Dans le deuxième test, nous +Dans le premier cas de test, nous confirmons la question, et les enregistrements sont mis à jour. Dans le deuxième test, nous ne confirmons pas et les enregistrements ne sont pas mis à jour, et nous pouvons vérifier que le message d'erreur a été écrit dans ``stderr``. -Tester CommandRunner --------------------- +Tester le CommandRunner +----------------------- -Pour tester les shells qui sont dispatchés en utilisant la classe ``CommandRunner``, activez la dans vos cas de test -avec la méthode suivante:: +Pour tester les shells qui sont dispatchés en utilisant la classe +``CommandRunner``, activez-la dans vos cas de test avec la méthode suivante:: $this->useCommandRunner(); Méthodes d'Assertion -------------------- -La classe ``Cake\TestSuite\ConsoleIntegrationTestCase`` fournit un certain -nombre de méthodes d'assertion qui aident à l'assertion de sorties de consoles:: +Le trait ``Cake\TestSuite\ConsoleIntegrationTestTrait`` fournit de nombreuses +méthodes d'assertion qui aident à vérifier la sortie de la console:: - // assert that the shell exited with the expected code + // vérifie que le shell s'est terminé avec le code attendu $this->assertExitCode($expected); - // assert that stdout contains a string + // vérifie que stdout contient une chaîne de caractères $this->assertOutputContains($expected); - // assert that stderr contains a string + // vérifie que stderr contient une chaîne de caractères $this->assertErrorContains($expected); - // assert that stdout matches a regular expression + // vérifie que stdout répond à une expression régulière $this->assertOutputRegExp($expected); - // assert that stderr matches a regular expression + // vérifie que stderr répond à une expression régulière $this->assertErrorRegExp($expected); From 19125baf9b954955fc74fc339091b7be043f8857 Mon Sep 17 00:00:00 2001 From: zachee54 Date: Sat, 8 Jul 2023 22:12:52 +0200 Subject: [PATCH 38/53] [fr] Update translation in cron-jobs.rst --- fr/console-commands/cron-jobs.rst | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/fr/console-commands/cron-jobs.rst b/fr/console-commands/cron-jobs.rst index f1103a4cdd..9541fb5b0b 100644 --- a/fr/console-commands/cron-jobs.rst +++ b/fr/console-commands/cron-jobs.rst @@ -2,19 +2,19 @@ Exécuter des Shells en Tâches Cron (Cron Jobs) ############################################## Une action habituelle à faire avec un shell est de l'exécuter par une tâche -cron pour nettoyer la base de données une fois de temps en temps ou pour -envoyer des newsletters:: +cron pour nettoyer la base de données de temps en temps ou pour envoyer des +newsletters. La configuration est un jeu d'enfant, par exemple:: - */5 * * * * cd /full/path/to/root && bin/cake myshell myparam - # * * * * * command to execute + */5 * * * * cd /chemin/complet/vers/la/racine && bin/cake monshell monparam + # * * * * * commande à exécuter # │ │ │ │ │ # │ │ │ │ │ - # │ │ │ │ \───── day of week (0 - 6) (0 to 6 are Sunday to Saturday, - # | | | | or use names) - # │ │ │ \────────── month (1 - 12) - # │ │ \─────────────── day of month (1 - 31) - # │ \──────────────────── hour (0 - 23) - # \───────────────────────── min (0 - 59) + # │ │ │ │ \───── jour de la semaine (0 - 6) (0 à 6 vont de dimanche à samedi), + # | | | | ou utilisez des noms) + # │ │ │ \────────── mois (1 - 12) + # │ │ \─────────────── jour du mois (1 - 31) + # │ \──────────────────── heures (0 - 23) + # \───────────────────────── minutes (0 - 59) Vous pouvez avoir plus d'infos ici: https://fr.wikipedia.org/wiki/Cron @@ -23,12 +23,13 @@ Vous pouvez avoir plus d'infos ici: https://fr.wikipedia.org/wiki/Cron Utilisez ``-q`` (or `--quiet`) pour ne pas afficher de sortie pour les cronjobs. -Tâches Cron sur des serveurs mutualisés +Tâches Cron sur des Serveurs Mutualisés --------------------------------------- -Sur certains serveurs mutualisés ``cd /full/path/to/root && bin/cake myshell myparam`` +Sur certains serveurs mutualisés +``cd /chemin/complet/vers/la/racine && bin/cake macommande monparam`` pourrait ne pas fonctionner. Vous pouvez à la place utiliser -``php /full/path/to/root/bin/cake.php myshell myparam``. +``php /chemin/complet/vers/la/racine/bin/cake.php macommande monparam``. .. note:: @@ -37,7 +38,7 @@ pourrait ne pas fonctionner. Vous pouvez à la place utiliser changer register_argc_argv de manière globale, vous pouvez préciser à la tâche cron d'utiliser votre propre configuration en la spécifiant via le paramètre ``-d register_argc_argv=1``. Exemple: - ``php -d register_argc_argv=1 /full/path/to/root/bin/cake.php myshell myparam``. + ``php -d register_argc_argv=1 /chemin/complet/vers/la/racine/bin/cake.php macommande monparam``. .. meta:: :title lang=fr: Lancer des Shells en tant que cronjobs From 98a42ad00b8f3a6aa9d191280f1b051a0a7e81d7 Mon Sep 17 00:00:00 2001 From: zachee54 Date: Sun, 9 Jul 2023 18:06:29 +0200 Subject: [PATCH 39/53] [fr] Update translation in input-output.rst --- fr/console-commands/input-output.rst | 198 +++++++++++++++------------ 1 file changed, 111 insertions(+), 87 deletions(-) diff --git a/fr/console-commands/input-output.rst b/fr/console-commands/input-output.rst index 1247de15ee..9207991d08 100644 --- a/fr/console-commands/input-output.rst +++ b/fr/console-commands/input-output.rst @@ -1,11 +1,14 @@ -Entrée/sortie de commande +Entrée/Sortie de Commande ========================= .. php:namespace:: Cake\Console .. php:class:: ConsoleIo CakePHP fournit l'objet ``ConsoleIo`` aux commandes afin qu'elles puissent -lire interactivement les informations d'entrée et de sortie de l'utilisateur. +lire interactivement les informations entrées par l'utilisateur et afficher +d'autres informations en sortie pour l'utilisateur. + +.. _command-helpers: Helpers (Assistants) de commande ================================ @@ -19,10 +22,10 @@ n'importe quelle commande, shell ou tâche:: // Récupère un helper depuis un plugin. $io->helper('Plugin.HelperName')->output($data); -Vous pouvez aussi récupérer les instances des Helpers et appeler n'importe +Vous pouvez aussi récupérer des instances de Helpers et appeler n'importe quelle méthode publique dessus:: - // Récupérer et utiliser le ProgressHelper. + // Récupérer et utiliser le helper Progress. $progress = $io->helper('Progress'); $progress->increment(10); $progress->draw(); @@ -30,11 +33,11 @@ quelle méthode publique dessus:: Créer des Helpers (Assistants) ============================== -Alors que CakePHP est fourni avec quelques helpers de commande, vous pouvez +CakePHP est fourni avec quelques helpers de commande, cependant vous pouvez en créer d'autres dans votre application ou vos plugins. À titre d'exemple, nous allons créer un helper simple pour générer des titres élégants. -Créez d'abord le fichier **src/Command/Helper/HeadingHelper.php** et mettez -ce qui suit dedans:: +Créez d'abord le fichier **src/Command/Helper/HeadingHelper.php** et insérez-y +ceci:: helper('Heading')->output(['It works!']); + $this->helper('Heading')->output(['Ça marche !']); // Avec ~~~~ de chaque coté - $this->helper('Heading')->output(['It works!', '~', 4]); + $this->helper('Heading')->output(['Ça marche !', '~', 4]); Les Helpers implémentent généralement la méthode ``output()`` qui prend un tableau de paramètres. Cependant, comme les Console Helper sont des classes @@ -73,11 +76,11 @@ quelle forme d'arguments. Les Helpers inclus ================== -L'Helper Table --------------- +Helper Table +------------ -Le TableHelper aide à faire des tableaux d'art ASCII bien formatés. -L'utiliser est assez simple:: +Le TableHelper aide à faire des tableaux ASCII bien formatés. L'utilisation est +assez simple:: $data = [ ['Header 1', 'Header', 'Long Header'], @@ -94,8 +97,27 @@ L'utiliser est assez simple:: | Longer thing | short | Longest Value | +--------------+---------------+---------------+ -L'Helper Progress ------------------ +Vousp ouvez utiliser la balise de formatage ```` dans les tables +pour en aligner son contenu à droite:: + + $data = [ + ['Nom 1', 'Prix Total'], + ['Cake Mix', '1.50'], + ]; + $io->helper('Table')->output($data); + + // Outputs + +----------+------------+ + | Nom 1 | Prix Total | + +----------+------------+ + | Cake Mix | 1.50 | + +----------+------------+ + +.. versionadded:: 4.2.0 + La balise de formatage ```` a été ajoutée dans 4.2. + +Helper Progress +--------------- Le ProgressHelper peut être utilisé de deux façons. Le mode simple vous permet de fournir un callback qui est appelé jusqu'à ce que l'avancement soit complet:: @@ -126,8 +148,8 @@ Voici un exemple de toutes les options utilisées:: } ]); -Le ProgressHelper peut aussi être utilisé manuellement pour incrementer et -réafficher la barre de progression quand nécessaire:: +Le ProgressHelper peut aussi être utilisé manuellement pour incrémenter et +réafficher la barre de progression selon les besoins:: $progress = $io->helper('Progress'); $progress->init([ @@ -144,31 +166,32 @@ Récupérer l'entrée utilisateur .. php:method:: ask($question, $choices = null, $default = null) -Lorsque vous créez des applications de console interactive, vous devez obtenir -les entrées de l'utilisateur. CakePHP fournit un moyen de le faire:: +Lorsque vous créez des applications de console interactives, vous aurez besoin +de récupérer des entrées de l'utilisateur. CakePHP fournit un moyen de le +faire:: - // Get arbitrary text from the user. - $color = $io->ask('What color do you like?'); + // Obtenir un texte quelconque de l'utilisateur. + $color = $io->ask('Quelle couleur aimez-vous ?'); - // Get a choice from the user. - $selection = $io->askChoice('Red or Green?', ['R', 'G'], 'R'); + // Obtenir un choix de l'utilisateur. + $selection = $io->askChoice('Rouge ou Vert ?', ['R', 'V'], 'R'); -Selection validation is case-insensitive. +La validation de la sélection est insensible à la casse. Créer des fichiers ================== .. php:method:: createFile($path, $contents) -Créer des fichiers est souvent une part importante de beaucoup de commandes -console qui permettent d'automatiser le développement et le déploiement. -la méthode ``createFile()`` donne une interface simple pour créer des fichiers, +Souvent, une partie importante des commandes de console consiste à créer des +fichiers, afin d'aider à automatiser le développement et le déploiement. La +méthode ``createFile()`` donne une interface simple pour créer des fichiers, avec une confirmation interactive:: - // Create a file with confirmation on overwrite + // Créer un fichier demandant de confirmer l'écrasement $io->createFile('bower.json', $stuff); - // Force overwriting without asking + // Forcer l'écrasement sans demander $io->createFile('bower.json', $stuff, true); Créer une sortie @@ -177,43 +200,45 @@ Créer une sortie .. php:method:out($message, $newlines, $level) .. php:method:err($message, $newlines) -Écrire dans ``stdout`` et ``stderr`` est une autre opération courante dans -CakePHP:: +Une autre opération courante dans CakePHP consiste à écrire dans ``stdout`` et +``stderr``:: // Écrire dans stdout - $io->out('Normal message'); + $io->out('Message normal'); // Écrire dans stderr - $io->err('Error message'); + $io->err('Message d\'erreur'); -En plus des méthodes de sortie vanilla, CakePHP fournit des méthodes +En plus des méthodes de sortie vanilla, CakePHP fournit des méthodes *wrappers* qui stylisent la sortie avec les couleurs ANSI appropriées:: // Texte vert dans stdout - $io->success('Success message'); + $io->success('Message de réussite'); // Texte cyan dans stdout - $io->info('Informational text'); + $io->info('Texte informatif'); // Texte bleu dans stdout - $io->comment('Additional context'); + $io->comment('Supplément de contexte'); // Texte rouge dans stderr - $io->error('Error text'); + $io->error('Texte d\'erreur'); // Texte jaune dans stderr - $io->warning('Warning text'); + $io->warning('Texte d\'avertissement'); -It also provides two convenience methods regarding the output level:: +Le formatage en couleur sera automatiquement désactivé si ``posix_isatty`` +renvoie true, ou si la variable d'environnement ``NO_COLOR`` est définie. + +``ConsoleIo`` fournit deux méthodes de confort à propos du niveau de sortie:: // N'apparaît que lorsque la sortie verbose est activée. (-v) - $io->verbose('Verbose message'); + $io->verbose('Message verbeux'); // Apparaîtrait à tous les niveaux. - $io->quiet('Quiet message'); + $io->quiet('Message succinct'); -Vous pouvez également créer des lignes vierges ou tracer -des lignes de tirets:: +Vous pouvez également créer des lignes vierges ou tracer des lignes de tirets:: // Affiche 2 ligne vides $io->out($this->nl(2)); @@ -221,10 +246,10 @@ des lignes de tirets:: // Dessiner une ligne horizontale $io->hr(); -Finalement, vous pouvez mettre à jour la ligne de texte actuelle +Pour finir, vous pouvez mettre à jour la ligne de texte actuelle à l'écran:: - $io->out('Counting down'); + $io->out('Compte à rebours'); $io->out('10', 0); for ($i = 9; $i > 0; $i--) { sleep(1); @@ -233,8 +258,8 @@ Finalement, vous pouvez mettre à jour la ligne de texte actuelle .. note:: - Il est important de se rappeler que vous ne pouvez pas ecraser le texte une - fois qu'une nouvelle ligne a été affichée. + Il est important de se rappeler que vous ne pouvez pas écraser le texte une + fois qu'un retour à la ligne a été affiché. .. _shell-output-level: @@ -249,25 +274,25 @@ peut alors décider du niveau de détail qui l'intéresse en sélectionnant le b indicateur lors de l'appel de la commande. Il y a 3 niveaux: * ``QUIET`` - Seulement les informations absolument importantes devraient être - marquées en sortie silencieuse. -* ``NORMAL`` -Le niveau par défaut, et l'utilisation normale. -* ``VERBOSE`` - Notez ainsi les messages qui peuvent être trop verbeux pour un - usage régulier, mais utile pour du débogage en ``VERBOSE``. + marquées en sortie *quiet*. +* ``NORMAL`` -Le niveau par défaut, pour un usage normal. +* ``VERBOSE`` - Marquez ``VERBOSE`` les messages qui peuvent être trop verbeux + pour un usage régulier, mais utiles pour du débogage . Vous pouvez marquer la sortie comme ceci:: - // Apparaitra à tous les niveaux. - $io->out('Quiet message', 1, ConsoleIo::QUIET); - $io->quiet('Quiet message'); + // Apparaîtra à tous les niveaux. + $io->out('Message succinct', 1, ConsoleIo::QUIET); + $io->quiet('Message succinct'); // N'apparaît pas lorsque la sortie silencieuse est activée. - $io->out('normal message', 1, ConsoleIo::NORMAL); - $io->out('loud message', 1, ConsoleIo::VERBOSE); - $io->verbose('Verbose output'); + $io->out('message normal', 1, ConsoleIo::NORMAL); + $io->out('message bavard', 1, ConsoleIo::VERBOSE); + $io->verbose('Sortie verbeuse'); // N'apparaît que lorsque la sortie verbose est activée. - $io->out('extra message', 1, ConsoleIo::VERBOSE); - $io->verbose('Verbose output'); + $io->out('message extra', 1, ConsoleIo::VERBOSE); + $io->verbose('Sortie verbeuse'); Vous pouvez contrôler le niveau de sortie des shells, en utilisant les options ``--quiet`` et ``--verbose``. Ces options sont ajoutées par défaut, et vous @@ -276,16 +301,16 @@ CakePHP. Les options ``--quiet`` et ``--verbose`` contrôlent aussi l'affichage des données de journalisation dans stdout/stderr. Normalement, les messages de journalisation -d'information et supérieurs sont affichés dans stdout/stderr. Quand ``--verbose`` -est utilisé, le journal de debogage sera affiché dans stdout. Quand ``--quiet`` -est utilisé, seulement les messages d'avertissement et supérieurs seront affichés +d'information et supérieurs sont affichés dans stdout/stderr. Avec +``--verbose``, le journal de débogage sera affiché dans stdout. Avec +``--quiet``, seuls les messages d'avertissement et supérieurs seront affichés dans stderr. Styliser la sortie ================== -Le style de sortie se fait en incluant des balises; tout comme le HTML, dans -votre sortie. Ces balises seront remplacées par la bonne séquence de code ANSI, +Vous pouvez donner un style à la sortie en incluant des balises dans votre sortie +- comme en HTML. Ces balises seront remplacées par la bonne séquence de code ANSI, ou supprimées si vous êtes sur une console qui ne supporte pas les codes ANSI. Il existe plusieurs styles intégrés, et vous pouvez en créer d'autres. Ceux qui sont intégrés sont: @@ -297,16 +322,15 @@ sont intégrés sont: * ``comment`` Texte additionnel. Texte bleu. * ``question`` Texte qui est une question, ajouté automatiquement par le shell. -Vous pouvez créer des styles supplémentaires en utilisant ``$io->styles()``. Pour -déclarer un nouveau style de sortie, vous pouvez faire:: +Vous pouvez créer des styles supplémentaires en utilisant ``$io->setStyle()``. +Pour déclarer un nouveau style de sortie, vous pouvez faire:: - $io->styles('flashy', ['text' => 'magenta', 'blink' => true]); + $io->setStyle('flashy', ['text' => 'magenta', 'blink' => true]); Cela vous permettrait alors d'utiliser une balise ```` dans votre sortie -shell, et si les couleurs ANSI sont activées, ce qui suit serait affiché comme -texte magenta clignotant -``$this->out('Whoooa Something went wrong');``. Lors de la -définition des styles, vous pouvez utiliser les couleurs suivantes pour les +shell, et si les couleurs ANSI sont activées, ce texte serait affiché en magenta +clignotant ``$this->out('Ouaaaah Il y a un problème');``. +En définissant des styles, vous pouvez utiliser les couleurs suivantes pour les attributs ``text`` et ``background``: * black @@ -319,37 +343,37 @@ attributs ``text`` et ``background``: * yellow Vous pouvez également utiliser les options suivantes en tant que commutateurs -booléens, leur attribuer une valeur considérée comme vraie les active. +booléens. Ils deviennent actifs quand vous leur attribuez une valeur évaluée à +``true``. * blink * bold * reverse * underline -L'ajout d'un style le rend également disponible sur toutes les instances de -ConsoleOutput, de sorte que vous n'avez pas à redéclarer les styles pour les -objets stdout et stdout. +Une fois ajouté, un style est disponible sur toutes les instances de +ConsoleOutput, de sorte que vous n'avez pas à redéclarer des styles à la fois +pour des objets stdout et stderr. -Désactiver la colorisation -========================== +Désactiver la Couleur +===================== Bien que la colorisation soit très jolie, il peut arriver que vous souhaitiez la désactiver, ou la forcer à s'activer:: $io->outputAs(ConsoleOutput::RAW); -Ce qui précède placera l'objet de sortie en mode de sortie brute. En mode de -sortie brute, aucun style n'est effectué. Il y a trois modes que vous pouvez -utiliser. +Cette instruction placera l'objet de sortie en mode de sortie brute. En mode de +sortie brute, il n'y a aucun style. Vous pouvez utiliser trois modes. * ``ConsoleOutput::COLOR`` - Sortie avec les codes d'échappement de couleur en place. * ``ConsoleOutput::PLAIN`` - Sortie en texte simple, les balises de style connues seront supprimées de la sortie. -* ``ConsoleOutput::RAW`` - La sortie brute, aucun style ou formatage ne sera fait. - C'est un bon mode à utiliser si vous affichez du XML ou si vous voulez déboguer - pourquoi votre style ne fonctionne pas. +* ``ConsoleOutput::RAW`` - Sortie brute sans style ni formatage. C'est un mode + approprié si vous générez du XML ou si vous voulez déboguer pour voir pourquoi + votre style ne fonctionne pas. -Par defaut sur les systèmes \*nix les objets ConsoleOutput sont initialisés en -mode sortie couleur. Sur les systèmes Windows, la sortie en texte simple est la -valeur par défaut à moins que la variable d'environment ``ANSICON`` est présente. +Par défaut sur les systèmes \*nix, les objets ConsoleOutput sont en mode sortie +couleur. Sur les systèmes Windows, la sortie est par défaut en texte simple sauf +si la variable d'environment ``ANSICON`` est présente. From 1993b1a00b193a93bbe23a72ccb34dfc2097b961 Mon Sep 17 00:00:00 2001 From: zachee54 Date: Tue, 11 Jul 2023 17:03:01 +0200 Subject: [PATCH 40/53] [fr] Update plugins.rst --- fr/plugins.rst | 637 ++++++++++++++++++++++++++++--------------------- 1 file changed, 366 insertions(+), 271 deletions(-) diff --git a/fr/plugins.rst b/fr/plugins.rst index 035ec0a408..47463e9e1e 100644 --- a/fr/plugins.rst +++ b/fr/plugins.rst @@ -34,188 +34,174 @@ Ceci installe la dernière version de DebugKit et met à jour vos fichiers **composer.json**, **composer.lock**, met à jour **vendor/cakephp-plugins.php** et met à jour votre autoloader. +Installer un Plugin Manuellement +================================ + Si le plugin que vous voulez installer n'est pas disponible sur packagist.org. Vous pouvez cloner ou copier le code du plugin dans votre répertoire -``plugins``. En supposant que vous voulez installer un plugin appelé -``ContactManager``, vous auriez un dossier dans ``plugins`` appelé -``ContactManager``. Dans ce répertoire se trouvent les View, Model, Controller, -webroot, et tous les autres répertoires du plugin. - -.. index:: vendor/cakephp-plugins.php - -Plugin Map File ---------------- - -Lorsque vous installez des plugins via Composer, vous pouvez voir que -**vendor/cakephp-plugins.php** est créé. Ce fichier de configuration contient -une carte des noms de plugin et leur chemin dans le système de fichiers. -Cela ouvre la possibilité pour un plugin d'être installé dans le dossier vendor -standard qui est à l'extérieur des dossiers de recherche standards. La classe -``Plugin`` utilisera ce fichier pour localiser les plugins lorsqu'ils sont -chargés avec ``load()`` ou ``loadAll()``. Généralement vous n'aurez pas à éditer -ce fichier à la main car Composer et le package ``plugin-installer`` le feront -pour vous. +**plugins**. Si vous voulez installer un plugin appelé ``ContactManager``, vous +créez un sous-répertoire nommé ``ContactManager`` dans **plugins**. C'est dans +ce sous-répertoire que vous mettrez les répertoires src, tests, et tous les +autres répertoires du plugin. -Charger un Plugin -================= +.. _autoloading-plugin-classes: -Après avoir installé un plugin et mis à jour l'autoloader, vous devrez charger -le plugin. Vous pouvez charger les plugins un par un, ou tous d'un coup avec une -méthode unique:: +Autoload Manuel des Classes de Plugin +------------------------------------- - // Dans config/bootstrap.php - // Ou dans Application::bootstrap() +Si vous installez vos plugins par ``composer`` ou ``bake``, vous ne devriez pas +avoir besoin de configurer l'autoload de classes pour vos plugins. - // Charge un Plugin unique - Plugin::load('ContactManager'); +Si vous installez manuellemen un plugin appelé par exemple ``MyPlugin``, vous +devrez modifier le fichier **composer.json** de votre application pour qu'il +contienne les informations suivantes: - // Charge un plugin unique, avec un namespace personnalisé. - Plugin::load('AcmeCorp/ContactManager'); +.. code-block:: json - // Charge tous les plugins d'un coup - Plugin::loadAll(); + { + "autoload": { + "psr-4": { + "MyPlugin\\": "plugins/MyPlugin/src/" + } + }, + "autoload-dev": { + "psr-4": { + "MyPlugin\\Test\\": "plugins/MyPlugin/tests/" + } + } + } -``loadAll()`` charge tous les plugins disponibles, vous permettant de définir -certaines configurations pour des plugins spécifiques. ``load()`` fonctionne de -la même manière, mais charge seulement les plugins que vous avez spécifié -explicitement. +Si vous utilisez un namespace pour vos plugins, le mappage du namespace vers le +chemin devra ressembler à: -.. note:: +.. code-block:: json - ``Plugin::loadAll()`` ne va pas charger les plugins se trouvant dans vendor - qui ne sont pas définis dans **vendor/cakephp-plugins.php**. + { + "autoload": { + "psr-4": { + "AcmeCorp\\Users\\": "plugins/AcmeCorp/Users/src/", + "AcmeCorp\\Users\\Test\\": "plugins/AcmeCorp/Users/tests/" + } + } + } -Il existe aussi une commande shell très pratique qui va activer le plugin. -Exécutez la ligne suivante: +De plus, vous devrez dire à Composer de rafraîchir son cache d'autoload: .. code-block:: console - bin/cake plugin load ContactManager + php composer.phar dumpautoload -Ceci va vous ajouter le bout de code ``Plugin::load('ContactManager');`` dans le -fichier bootstrap. +Charger un Plugin +================= -.. _autoloading-plugin-classes: +Si vous voulez utiliser des routes du plugin, des commandes de console, des +middlewares, des écouteurs d'événements, des templates ou des ressources du +webroot, il faudra d'abord charger le plugin. +C'est la function ``bootstrap()`` de votre application qui devra s'en charger:: -Autochargement des Classes du Plugin ------------------------------------- + // Dans src/Application.php + use Cake\Http\BaseApplication; + use ContactManager\ContactManagerPlugin; -Quand on utilise ``bake`` pour la création d'un plugin ou quand on en installe -un en utilisant Composer, vous n'avez typiquement pas besoin de faire des -changements dans votre application afin que CakePHP reconnaisse les classes qui -se trouvent dedans. + class Application extends BaseApplication { + public function bootstrap() + { + parent::bootstrap(); + // Charge la plugin ContactManager d'après son nom + $this->addPlugin(ContactManagerPlugin::class); -Dans tous les autres cas, vous avez peut-être besoin de modifier le fichier -composer.json de votre application pour contenir les informations suivantes:: + // Charger un plugin avec un namespace d'après son "nom court" + $this->addPlugin('AcmeCorp/ContactManager'); - "psr-4": { - (...) - "MyPlugin\\": "./plugins/MyPlugin/src", - "MyPlugin\\Test\\": "./plugins/MyPlugin/tests" + // Charger ne dépendance de développement qui n'existera pas en environnement de production. + $this->addOptionalPlugin('AcmeCorp/ContactManager'); + } } -Si vous utilisez des namespaces pour vos plugins, le mapping des namespaces -vers les dossiers doit ressembler à ceci:: +Si vous voulez juste utiliser des helpers, behaviors ou components d'un plugin, +vous n'avez pas besoin de le charger explicitement, bien que nous recommandions +de toujours le faire. - "psr-4": { - (...) - "AcmeCorp\\Users\\": "./plugins/AcmeCorp/Users/src", - "AcmeCorp\\Users\\Test\\": "./plugins/AcmeCorp/Users/tests" - } +Il existe aussi une commande de shell bien pratique pour activer un plugin. +Exécutez cette instruction: -De plus, vous aurez besoin de dire à Composer de refraichir le cache de -l'autochargement:: +.. code-block:: console - $ php composer.phar dumpautoload + bin/cake plugin load ContactManager -Si vous ne pouvez pas utiliser Composer pour toute raison, vous pouvez aussi -utiliser un autochargement fallback pour votre plugin:: +Cela va mettre à jour la méthode bootstrap de votre application, ou insérer le +code ``$this->addPlugin('ContactManager');`` dans le bootstrap à votre place. - Plugin::load('ContactManager', ['autoload' => true]); +.. versionadded:: 4.1.0 + Ajout de la méthode ``addOptionalPlugin()``. .. _plugin-configuration: Configuration du Plugin ======================= -Les méthodes ``load`` et ``loadAll`` peuvent vous aider pour la configuration et -le routing d'un plugin. Peut-être souhaiterez vous charger tous les plugins -automatiquement, en spécifiant des routes et des fichiers de bootstrap pour -certains plugins:: - - // dans config/bootstrap.php - // Ou dans Application::bootstrap() - - // En utilisant loadAll() - Plugin::loadAll([ - 'Blog' => ['routes' => true], - 'ContactManager' => ['bootstrap' => true], - 'WebmasterTools' => ['bootstrap' => true, 'routes' => true], - ]); - -Ou vous pouvez charger les plugins individuellement:: - - // Charge seulement le blog et inclut les routes - Plugin::load('Blog', ['routes' => true]); - - // Inclut le fichier de démarrage pour la configuration/initialisation. - Plugin::load('ContactManager', ['bootstrap' => true]); - -Avec ces deux approches, vous n'avez plus à faire manuellement un ``include()`` -ou un ``require()`` du fichier de configuration ou du fichier de routes du -plugin -- cela arrive automatiquement au bon moment et au bon endroit. +Les plugins proposent plusieurs *hooks* permettant à un plugin de s'injecter +lui-même aux endroits appropriés de votre application. Les *hooks* sont: + +* ``bootstrap`` Utilisé pour charger les fichiers de configuration par défaut + d'un plugin, définir des constantes et d'autres fonctions globales. +* ``routes`` Utilisé pour charger les routes pour un plugin. Il est déclenché + après le chargement des routes de l'application. +* ``middleware`` Utilisé pour ajouter un middleware de plugin à la file de + middlewares de l'application. +* ``console`` Utilisé pour ajouter des commandes de console à la collection des + commandes d'une application. -Vous pouvez spécifier un ensemble de valeurs par défaut pour ``loadAll()`` qui -vont s'appliquer à chaque plugin qui n'a pas de configuration spécifique. +En chargeant les plugins, vous pouvez configurer quels *hooks* doivent être +activés. Par défaut, tous les *hooks* sont désactivés dans les plugins qui n'ont +pas de :ref:`plugin-objects`. Les plugins du nouveau style autorisent les +auteurs de plugins à définir des valeurs par défaut, que vous pouvez configurer +dans votre application:: -L'exemple suivant va charger le fichier de bootstrap de tous les plugins, et -aussi les routes du plugin Blog:: + // Dans Application::bootstrap() + use ContactManager\ContactManagerPlugin; - Plugin::loadAll([ - ['bootstrap' => true], - 'Blog' => ['routes' => true] - ]); + // Désactiver les routes pour le plugin ContactManager + $this->addPlugin(ContactManagerPlugin::class, ['routes' => false]); -Notez que tous les fichiers spécifiés doivent réellement exister dans le(s) -plugin(s) configurés ou PHP vous donnera des avertissements pour chaque -fichier qu'il ne peut pas charger. Vous pouvez éviter les avertissements -potentiels en utilisant l'option ``ignoreMissing``:: +Vous pouvez configurer les *hooks* avec un tableau d'options, ou par les +méthodes fournies par les classes de plugin:: - Plugin::loadAll([ - ['ignoreMissing' => true, 'bootstrap' => true], - 'Blog' => ['routes' => true] - ]); + // Dans Application::bootstrap() + use ContactManager\ContactManagerPlugin; -Par défaut le namespace du Plugin doit correspondre au nom du plugin. Par -exemple si vous avez un plugin avec un namespace de haut niveau ``Users``, vous -le chargeriez en utilisant:: + // Utiliser disable/enable pour configurer les hooks. + $plugin = new ContactManagerPlugin(); - Plugin::load('User'); + $plugin->disable('bootstrap'); + $plugin->enable('routes'); + $this->addPlugin($plugin); -Si vous préférez avoir votre nom de vendor en haut niveau et avoir un namespace -comme ``AcmeCorp/Users``, alors vous devrez charger le plugin comme suit:: +Les objets plugins connaissent aussi leurs noms et leurs informations de +chemin:: - Plugin::load('AcmeCorp/Users'); + $plugin = new ContactManagerPlugin(); -Cela va assurer que les noms de classe sont résolus correctement lors de -l'utilisation de la :term:`syntaxe de plugin`. + // Obtenir le nom du plugin. + $name = $plugin->getName(); -La plupart des plugins vont indiquer la procédure correcte pour les configurer -et configurer la base de données dans leur documentation. Certains plugins -nécessitent plus de configurations que les autres. + // Chemin vers la racine du plugin, et autres chemins. + $path = $plugin->getPath(); + $path = $plugin->getConfigPath(); + $path = $plugin->getClassPath(); Utiliser un Plugin ================== Vous pouvez référencer les controllers, models, components, behaviors et -helpers du plugin en préfixant le nom du plugin avant le nom de classe. +helpers du plugin en préfixant le nom du plugin. -Par exemple, disons que vous voulez utiliser le ContactInfoHelper du plugin -ContactManager pour sortir de bonnes informations de contact dans une de -vos vues. Dans votre controller, le tableau ``$helpers`` pourrait ressembler -à ceci:: +Par exemple, Supposons que vous veuillez utiliser le ContactInfoHelper du plugin +ContactManager pour afficher des informations de contact formatées dans une de +vos vues. Dans votre controller, vous pouvez utiliser ``addHelper()`` de la +façon suivante:: - public $helpers = ['ContactManager.ContactInfo']; + $this->viewBuilder()->addHelper('ContactManager.ContactInfo'); .. note:: Ce nom de classe séparé par un point se réfère à la :term:`syntaxe de @@ -226,6 +212,15 @@ helper dans votre vue, comme ceci:: echo $this->ContactInfo->address($contact); +Le splugins peuvent utiliser des models, components, behaviors et helper fournis +par l'application, ou par d'autres plugins si nécessaire:: + + // Utiliser un component d'application + $this->loadComponent('AppFlash'); + + // Utiliser un behavior d'un autre plugin + $this->addBehavior('AutrePlugin.AuditLog'); + .. _plugin-create-your-own: Créer Vos Propres Plugins @@ -240,6 +235,7 @@ de répertoire basique. Cela devrait ressembler à ceci:: /ContactManager /config /src + /ContactManagerPlugin.php /Controller /Component /Model @@ -248,24 +244,24 @@ de répertoire basique. Cela devrait ressembler à ceci:: /Behavior /View /Helper - /Template - /Layout + /templates + /layout /tests /TestCase /Fixture /webroot -Notez que le nom du dossier du plugin, '**ContactManager**'. Il est important +Notez le nom du dossier du plugin, '**ContactManager**'. Il est important que ce dossier ait le même nom que le plugin. Dans le dossier plugin, vous remarquerez qu'il ressemble beaucoup à une application CakePHP, et c'est au fond ce que c'est. Vous n'avez à inclure aucun de vos dossiers si vous ne les utilisez pas. Certains plugins peuvent -ne contenir qu'un Component ou un Behavior, et dans certains cas, ils peuvent -carrément ne pas avoir de répertoire 'Template'. +ne contenir qu'un Component ou un Behavior, et dans ce cas ils peuvent +carrément ne pas avoir de répertoire 'templates'. -Un plugin peut aussi avoir tous les autres répertoires que votre application a, -comme Config, Console, Lib, webroot, etc... +Un plugin peut aussi avoir n'importe quels autres répertoires similaires à ceux +d'une application comme Config, Console, webroot, etc... Créer un Plugin en utilisant Bake --------------------------------- @@ -273,83 +269,149 @@ Créer un Plugin en utilisant Bake Le processus de création des plugins peut être grandement simplifié en utilisant le shell bake. -Pour cuisiner un plugin, utilisez la commande suivante: +Pour "cuisiner" (*bake*) un plugin, utilisez la commande suivante: .. code-block:: console bin/cake bake plugin ContactManager -Maintenant vous pouvez cuisiner en utilisant les mêmes conventions qui -s'appliquent au reste de votre app. Par exemple - baking controllers: +Vous pouvez utiliser bake pour créer des classes dans votre plugin. Par exemple, +pour générer un contrôleur de plugin, vous pouvez lancer: .. code-block:: console bin/cake bake controller --plugin ContactManager Contacts -Référez-vous au chapitre +Rendez-vous au chapitre :doc:`/bake/usage` si vous avez le moindre problème avec l'utilisation de la ligne de commande. Assurez-vous de -re-générer votre autoloader une fois que vous avez créé votre plugin: +re-générer votre autoloader après avoir créé votre plugin: .. code-block:: console php composer.phar dumpautoload +.. _plugin-objects: + +Plugin Objects +============== + +Les Objets Plugin permettent à un auteur de plugin de spécifier une logique de +démarrage, de définire des *hooks* par défaut, de charger des routes, un +middleware ou des commandes de console. Les objets Plugin se trouvent dans +**src/Plugin.php**. Pour notre plugin ContactManager, notre classe de plugin +pourrait ressembler à:: + + namespace ContactManager; + + use Cake\Core\BasePlugin; + use Cake\Core\ContainerInterface; + use Cake\Core\PluginApplicationInterface; + use Cake\Console\CommandCollection; + use Cake\Http\MiddlewareQueue; + + class ContactManagerPlugin extends BasePlugin + { + public function middleware(MiddlewareQueue $middleware): MiddlewareQueue + { + // Ajouter le middleware ici. + $middleware = parent::middleware($middleware); + + return $middleware; + } + + public function console(CommandCollection $commands): CommandCollection + { + // Ajouter les commandes de console ici. + $commands = parent::console($commands); + + return $commands; + } + + public function bootstrap(PluginApplicationInterface $app): void + { + // Ajouter des constantes, charger une configuration par défaut. + // Par défaut, cela chargera `config/bootstrap.php` dans le plugin. + parent::bootstrap($app); + } + + public function routes($routes): void + { + // Ajouter des routes. + // Par défaut, cela chargera `config/routes.php` dans le plugin. + parent::routes($routes); + } + + /** + * Enregistrer des services de container d'application. + * + * @param \Cake\Core\ContainerInterface $container Le Container à mettre à jour. + * @return void + * @link https://book.cakephp.org/4/fr/development/dependency-injection.html#dependency-injection + */ + public function services(ContainerInterface $container): void + { + // Ajoutez vos services ici + } + } + .. _plugin-routes: Routes de Plugins ================= -Les plugins peuvent contenir des fichiers de routes contenant leurs propres routes. -Chaque plugin contient un fichier **config/routes.php**. Ce fichier de routes -peut être chargé quand le plugin est ajouté ou dans le fichier de routes de l'application. +Les plugins peuvent mettre à disposition des fichiers de routes contenant leurs +propres routes. Chaque plugin peut contenir un fichier **config/routes.php**. Ce +fichier de routes peut être chargé quand le plugin est ajouté, ou dans le +fichier de routes de l'application. Pour créer les routes du plugin ContractManager, ajoutez le code suivant dans **plugins/ContactManager/config/routes.php**:: plugin( 'ContactManager', ['path' => '/contact-manager'], function ($routes) { + $routes->setRouteClass(DashedRoute::class); + $routes->get('/contacts', ['controller' => 'Contacts']); - $routes->get('/contacts/:id', ['controller' => 'Contacts', 'action' => 'view']); - $routes->put('/contacts/:id', ['controller' => 'Contacts', 'action' => 'update']); + $routes->get('/contacts/{id}', ['controller' => 'Contacts', 'action' => 'view']); + $routes->put('/contacts/{id}', ['controller' => 'Contacts', 'action' => 'update']); } ); -Le code ci-dessus connectera les routes par défaut de votre plugin. Vous pouvez -personnaliser ce fichier avec plus de routes plus tard. +Le code ci-dessus connectera les routes par défaut de votre plugin. Vous pourrez +personnaliser ce fichier plus tard avec des routes plus spécifiques. Avant de pouvoir accéder à vos controllers, assuez-vous que le plugin est bien chargé et que les routes du plugin le sont également. Dans votre fichier -**config/bootstrap.php**, ajoutez la ligne suivante:: +**src/Application.php**, ajoutez la ligne suivante:: - Plugin::load('ContactManager', ['routes' => true]); + $this->addPlugin('ContactManager', ['routes' => true]); Vous pouvez également charger les routes du plugin dans la liste des routes de votre -application. Le faire de cette manière vous permet d'avoir plus de contrôle sur la manière -dont les routes de plugin sont chargées et vous permet d'englober les routes du plugin -dans des préfixes et des 'scopes' spécifiques:: +application. De cette manière, vous avez plus de contrôle sur le chargement des +routes de plugin et cela vous permet d'englober les routes du plugin +dans des préfixes et des 'scopes' supplémentaires:: - Router::scope('/', function ($routes) { + $routes->scope('/', function ($routes) { // Connect other routes. $routes->scope('/backend', function ($routes) { $routes->loadPlugin('ContactManager'); }); }); -Le code ci-dessus vous permettrait d'avoir des URLs de la forme ``/backend/contact_manager/contacts``. +Le code ci-dessus vous permettrait d'avoir des URLs de la forme ``/backend/contact-manager/contacts``. Controllers du Plugin ===================== Les controllers pour notre plugin ContactManager seront stockés dans -**plugins/ContactManager/src/Controller/**. Puisque la principale chose que -nous souhaitons faire est la gestion des contacts, nous aurons besoin de créer -un ContactsController pour ce plugin. +**plugins/ContactManager/src/Controller/**. Puisque notre activité principale +est la gestion des contacts, nous aurons besoin d'un ContactsController pour ce +plugin. Ainsi, nous mettons notre nouveau ContactsController dans **plugins/ContactManager/src/Controller** et il ressemblerait à cela:: @@ -383,12 +445,12 @@ Un ``AppController`` dédié à votre plugin peut contenir la logique commune à tous les controllers de votre plugin, et n'est pas obligatoire si vous ne souhaitez pas en utiliser. -Si vous souhaitez accéder à ce qu'on a fait avant, visitez +Si vous souhaitez accéder à ce que nous avons fait jusqu'ici, visitez l'URL ``/contact-manager/contacts``. Vous aurez une erreur "Missing Model" -parce que nous n'avons pas de model Contact encore défini. +parce que nous n'avons pas encore défini de model Contact. -Si votre application inclut le routage par défaut que CakePHP fournit, vous -serez capable d'accéder aux controllers de votre plugin en utilisant les URLs +Si votre application inclut le routage par défaut fourni par CakePHP, vous +serez en mesure d'accéder aux controllers de votre plugin en utilisant des URLs comme:: // Accéder à la route index d'un controller de plugin. @@ -398,17 +460,17 @@ comme:: /contact-manager/contacts/view/1 Si votre application définit des préfixes de routage, le routage par défaut de -CakePHP va aussi connecter les routes qui utilisent le modèle suivant:: +CakePHP connectera aussi les routes qui utilisent le modèle suivant:: - /:prefix/:plugin/:controller - /:prefix/:plugin/:controller/:action + /{prefix}/{plugin}/{controller} + /{prefix}/{plugin}/{controller}/{action} Consultez la section sur :ref:`plugin-configuration` pour plus d'informations sur la façon de charger les fichiers de routes spécifiques à un plugin. Pour les plugins que vous n'avez pas créés avec bake, vous devrez aussi modifier -le fichier ``composer.json`` pour ajouter votre plugin aux classes d'autoload, -ceci peut être fait comme expliqué dans la documentation +le fichier ``composer.json`` pour ajouter votre plugin aux classes d'autoload. +Vous pouvez le faire en suivant la documentation :ref:`autoloading-plugin-classes`. .. _plugin-models: @@ -439,8 +501,8 @@ table et l'entity pour ce controller:: } Si vous avez besoin de faire référence à un model dans votre plugin lors de la -construction des associations, ou la définition de classes d'entity, vous devrez -inclure le nom du plugin avec le nom de la classe, séparé par un point. Par +construction des associations ou la définition de classes d'entity, vous devrez +inclure le nom du plugin avec le nom de la classe, séparés par un point. Par exemple:: // plugins/ContactManager/src/Model/Table/ContactsTable.php: @@ -457,7 +519,7 @@ exemple:: } Si vous préférez que les clés du tableau pour l'association n'aient pas le -préfix du plugin, utilisez la syntaxe alternative:: +préfixe du plugin, utilisez la syntaxe alternative:: // plugins/ContactManager/src/Model/Table/ContactsTable.php: namespace ContactManager\Model\Table; @@ -474,86 +536,82 @@ préfix du plugin, utilisez la syntaxe alternative:: } } -Vous pouvez utiliser ``TableRegistry`` pour charger les tables de votre plugin -en utilisant l'habituelle :term:`syntaxe de plugin`:: - - use Cake\ORM\TableRegistry; - - // Prior to 3.6 use TableRegistry::get('ContactManager.Contacts') - $contacts = TableRegistry::getTableLocator()->get('ContactManager.Contacts'); +Vous pouvez utiliser ``Cake\ORM\Locator\LocatorAwareTrait``` pour charger les +tables de votre plugin en utilisant l'habituelle :term:`syntaxe de plugin`:: -Si vous êtes dans un Controller, vous pouvez aussi utiliser:: + // Les controllers utilisent déjà LocatorAwareTrait, donc vous n'avez pas besoin d'ajouter ceci. + use Cake\ORM\Locator\LocatorAwareTrait; - $this->loadModel('ContactsMangager.Contacts'); + $contacts = $this->fetchTable('ContactManager.Contacts'); Vues du Plugin ============== Les Vues se comportent exactement comme elles le font dans les applications normales. Placez-les juste dans le bon dossier à l'intérieur du dossier -``plugins/[PluginName]/Template/``. Pour notre plugin ContactManager, nous -aurons besoin d'une vue pour notre action ``ContactsController::index()``, ainsi -incluons ceci aussi:: +``plugins/[PluginName]/templates/``. Pour notre plugin ContactManager, nous +aurons besoin d'une vue pour notre action ``ContactsController::index()``, donc +ajoutons-y ceci:: // plugins/ContactManager/templates/Contacts/index.php:

Contacts

Ce qui suit est une liste triable de vos contacts

-Les Plugins peuvent fournir leurs propres layouts. Ajoutez des layouts de -plugin, dans ``plugins/[PluginName]/templates/layout``. Pour utiliser le -layout d'un plugin dans votre controller, vous pouvez faire ce qui suit:: +Les Plugins peuvent fournir leurs propres layouts. Pour ajouter des layouts de +plugin, placez vos fichiers de template dans +``plugins/[PluginName]/templates/layout``. Pour utiliser le layout d'un plugin +dans votre controller, vous pouvez faire comme ceci:: - public $layout = 'ContactManager.admin'; + $this->viewBuilder()->setLayout('ContactManager.admin'); -Si le préfix de plugin n'est pas mis, le fichier de vue/layout sera localisé +Si le préfix de plugin n'est pas précisé, le fichier de vue/layout sera localisé normalement. .. note:: Pour des informations sur la façon d'utiliser les elements à partir d'un - plugin, regardez :ref:`view-elements`. + plugin, consultez :ref:`view-elements`. -Redéfinition des Template de Plugin depuis l'Intérieur de votre Application ---------------------------------------------------------------------------- +Redéfinir des Templates de Plugin depuis l'Intérieur de votre Application +------------------------------------------------------------------------- Vous pouvez redéfinir toutes les vues du plugin à partir de l'intérieur de votre app en utilisant des chemins spéciaux. Si vous avez un plugin appelé 'ContactManager', vous pouvez redéfinir les fichiers de template du plugin avec -une logique de vue de l'application plus spécifique, en créant des fichiers en -utilisant le template suivant -**templates/plugin/[Plugin]/[Controller]/[view].php**. Pour le controller -Contacts, vous pouvez faire le fichier suivant:: +une logique de vue spécifique à l'application, en créant des fichiers sur le +modèle de **templates/plugin/[Plugin]/[Controller]/[view].php**. Pour le +controller Contacts, vous pourriez écrire le fichier suivant:: templates/plugin/ContactManager/Contacts/index.php -Créer ce fichier vous permettra de redéfinir +La création de ce fichier vous permettra de redéfinir **plugins/ContactManager/templates/Contacts/index.php**. -Si votre plugin est dans une dépendence de Composer (ex: 'LeVendor/LePlugin), le -chemin vers la vue 'index' du controlleur Custom sera +Si votre plugin fait partie d'une dépendence de Composer (ex: +'LeVendor/LePlugin'), le chemin vers la vue 'index' du controller Contacts +sera:: templates/plugin/LeVendor/LePlugin/Custom/index.php -Créer ce fichier vous permettra de redéfinir +La création de ce fichier vous permettra de redéfinir **vendor/levendor/leplugin/templates/Custom/index.php**. Si le plugin implémente un préfixe de routing, vous devez inclure ce préfixe -dans la surcharge de template de votre application. - -Si le plugin 'ContactManager' implémente un préfixe 'admin', le chemin de la -redéfinition sera:: +dans le template réécrit par votre application. Par exemple, si le plugin +'ContactManager' implémente un préfixe 'Admin', le chemin du template réécrit +sera:: templates/plugin/ContactManager/Admin/ContactManager/index.php .. _plugin-assets: -Assets de Plugin -================ +Ressources de Plugin +==================== -Les assets web du plugin (mais pas les fichiers de PHP) peuvent être servis -à travers le répertoire ``webroot`` du plugin, juste comme les assets de -l'application principale:: +Les ressources web du plugin (mais pas les fichiers PHP) peuvent être servies +à travers le répertoire ``webroot`` du plugin, exactement comme les ressources +de l'application principale:: /plugins/ContactManager/webroot/ css/ @@ -562,20 +620,20 @@ l'application principale:: flash/ pdf/ -Vous pouvez mettre tout type de fichier dans tout répertoire, juste comme -un webroot habituel. +Vous pouvez mettre n'importe quel type de fichier dans tout répertoire, +exactement comme un webroot habituel. .. warning:: - La gestion des assets static, comme les fichiers images, Javascript et CSS, - à travers le Dispatcher est très inéfficace. Regardez :ref:`symlink-assets` - pour plus d'informations. + La gestion des ressources statiques comme les fichiers images, Javascript et + CSS à travers le Dispatcher est très inefficace. Consultez + :ref:`symlink-assets` pour plus d'informations. -Lier aux plugins ----------------- +Liens vers les Ressources dans des Plugins +------------------------------------------ -Vous pouvez utiliser la :term:`syntaxe de plugin` pour lier les assets de plugin -en utilisant les méthodes script, image ou css de +Vous pouvez utiliser la :term:`syntaxe de plugin` pour faire un lien vers les +ressources d'un plugin en utilisant les méthodes script, image ou css de :php:class:`~Cake\\View\\Helper\\HtmlHelper`:: // Génère une URL de /contact_manager/css/styles.css @@ -587,14 +645,14 @@ en utilisant les méthodes script, image ou css de // Génère une URL de /contact_manager/img/logo.jpg echo $this->Html->image('ContactManager.logo'); -Les assets de Plugin sont servis en utilisant le filtre du dispatcheur -``AssetFilter`` par défaut. C'est seulement recommandé pour le développement. -En production vous devrez :ref:`symlinker vos assets ` pour +Les ressources de plugins sont servies par défaut en utilisant le midlleware +``AssetMiddleware``. Ce n'est recommandé que pour le développement. +En production vous devriez :ref:`symlinker vos assets ` pour améliorer la performance. -Si vous n'utilisez pas les helpers, vous pouvez préfixer /plugin_name/ au -début de l'URL pour servir un asset du plugin . Lier avec -'/contact_manager/js/some_file.js' servirait l'asset +Si vous n'utilisez pas les helpers, vous pouvez préfixer l'URL par /plugin-name/ +pour servir une ressource du plugin . Un lien vers +'/contact_manager/js/some_file.js' renverrait la ressource **plugins/ContactManager/webroot/js/some_file.js**. Components, Helpers et Behaviors @@ -602,17 +660,16 @@ Components, Helpers et Behaviors Un plugin peut avoir des Components, Helpers et Behaviors tout comme une application CakePHP classique. Vous pouvez soit créer des plugins qui sont -composés seulement de Components, Helpers ou Behaviors ce qui peut être une +composés seulement de Components, Helpers ou Behaviors, ce qui peut être une bonne façon de construire des Components réutilisables qui peuvent être -facilement déplacés dans tout projet. +facilement déplacés dans n'importe quel projet. -Construire ces components est exactement la même chose que de les construire -à l'intérieur d'une application habituelle, avec aucune convention spéciale -de nommage. +On construit ces components est exactement de la même manière qu'à l'intérieur +d'une application habituelle, sans aucune convention spéciale de nommage. -Faire référence avec votre component, depuis l'intérieur ou l'extérieur de -votre plugin nécessite seulement que vous préfixiez le nom du plugin avant le -nom du component. Par exemple:: +Pour faire référence à votre component, que ce soit depuis l'intérieur ou +l'extérieur de votre plugin, vous devez seulement préfixer le nom du component +par le nom du plugin. Par exemple:: // Component défini dans le plugin 'ContactManager' namespace ContactManager\Controller\Component; @@ -632,50 +689,88 @@ nom du component. Par exemple:: La même technique s'applique aux Helpers et aux Behaviors. -Etendez votre Plugin -==================== +.. _plugin-commands: + +Commands +======== + +Les plugins peuvent enregistrer leurs commandes dans le *hook* ``console()``. +Par défaut, tous les shells et commandes du plugin sont découverts +automatiquement et ajoutés à la liste des commandes de l'application. Les +commandes de plugin sont préfixées par le nom du plugin. Par exemple, la +commande ``UserCommand`` fournie par le plugin ``ContactManager`` serait +enregistrée à la fois comme ``contact_manager.user`` et ``user``. Le nom non +préfixé sera retenu par un plugin seulement s'il n'est pas déjà utilisé par +l'application ou un autre plugin. -Cet exemple est un bon début pour un plugin, mais il y a beaucoup plus -à faire. En règle générale, tout ce que vous pouvez faire avec votre -application, vous pouvez le faire à l'intérieur d'un plugin à la place. +Vous pouvez personnaliser les noms de commandes au moment de définir chaque +commande dans votre plugin:: -Continuez, incluez certaines librairies tierces dans 'vendor', ajoutez -de nouveaux shells à la console de cake, et n'oubliez pas de créer des cas -de test ainsi les utilisateurs de votre plugin peuvent automatiquement tester -les fonctionnalités de votre plugin! + public function console($commands) + { + // Créez des commandes imbriquées + $commands->add('bake model', ModelCommand::class); + $commands->add('bake controller', ControllerCommand::class); + + return $commands; + } + +Tester votre Plugin +=================== + +Si vous testez des controllers ou si vous générez des URLs, assurez-vous que +votre plugin connecte les routes ``tests/bootstrap.php``. -Dans notre exemple ContactManager, nous pourrions créer des actions -add/remove/edit/delete dans le ContactsController, intégrer la validation -dans le model Contact, et intégrer la fonctionnalité à laquelle on -pourrait s'attendre quand on gère ses contacts. A vous de décider ce qu'il -faut intégrer dans vos plugins. N'oubliez juste pas de partager votre code -avec la communauté afin que tout le monde puisse bénéficier de votre -component génial et réutilisable! +Pour plus d'informations, consultez la page +:doc:`testing plugins `. -Publiez votre Plugin +Publier votre Plugin ==================== -Vous pouvez ajouter votre plugin sur -`plugins.cakephp.org `_. De cette façon, il peut -être facilement utilisé avec Composer. -Vous pouvez aussi proposer votre plugin à la liste `awesome-cakephp `_ - -Aussi, vous pouvez créer un fichier composer.json et publier votre plugin -sur `packagist.org `_. - -Choisissez un nom de package avec une sémantique qui a du sens. Il devra -idéalement être préfixé avec la dépendance, dans ce cas "cakephp" comme le -framework. -Le nom de vendor sera habituellement votre nom d'utilisateur sous GitHub. -**N'utilisez pas** le namespace CakePHP (cakephp) puisqu'il est reservé -aux plugins appartenant à CakePHP. -La convention est d'utiliser les lettres en minuscule et les tirets en -séparateur. - -Donc si vous créez un plugin "Logging" avec votre compte GitHub "FooBar", un -bon nom serait `foo-bar/cakephp-logging`. -Et le plugin "Localized" appartenant à CakePHP peut être trouvé dans -`cakephp/localized`. +Les plugins CakePHP devraient être publiés dans `le packagist +`__. De cette façon, d'autres personnes pourraient les +utiliser comme dépendances composer. Vous pouvez aussi proposer votre plugin +dans la `liste des outils formidables pour CakePHP +`_. + +Choisissez un nom qui ait du sens pour votre nom de package. Idéalement, il +faudrait le préfixer du nom de la dépendance, au cas présent "cakephp" comme le +nom du framework. Le nom de vendor sera généralement votre nom d'utilisateur +GitHub. **n'utilisez pas** le namespace de CakePHP (cakephp) car il est réservé +aux plugins appartenant à CakePHP. Par convention, on utilise des lettres en +minuscules et des traits d'union comme séparateurs. + +Donc si vous avez créé un plugin "Logging" avec votre compte GitHub "FooBar", +`foo-bar/cakephp-logging` serait un nom judicieux. Et respectivement, le plugin +"Localized" appartenant à CakePHP peut se trouver sous `cakephp/localized`. + +-.. index:: vendor/cakephp-plugins.php + +Fichier de Mappage de Plugin +============================ + +Quand vous installez des plugins par Composer, vous noterez la création de +**vendor/cakephp-plugins.php**. Ce fichier de configuration contient un mappage +des noms de plugins et de leurs chemins sur le système de fichiers. Cela rend +possible l'installation des plugins dans le répertoire standard vendor, qui est +en-dehors de l'arborescence de recherche normale. La classe ``Plugin`` utilisera +ce fichier pour localiser les plugins lorsqu'ils sont chargés avec +``addPlugin()``. Vous n'aurez généralement pas besoin d'éditer ce fichier +manuellement, dans la mesure où Composer et le package ``plugin-installer`` s'en +chargeront pour vous. + +Gérer Vos Plugins avec Mixer +============================ + +`Mixer `_ est un autre moyen de découvrir et +gérer les plugins dans votre application CakePHP. C'est un plugin CakePHP qui +aide à installer des plugins depuis Packagist. Il vous aide aussi à gérer les +plugins existants. + +.. note:: + + IMPORTANT: Ne l'utilisez pas en environnement de production. + .. meta:: :title lang=fr: Plugins From 23bc0f82816aee93736a02b5bd6b6660b0ed7147 Mon Sep 17 00:00:00 2001 From: Spencer Smith Date: Thu, 13 Jul 2023 00:35:05 -0600 Subject: [PATCH 41/53] Update cakephp-folder-structure.rst Fixed grammar conventions for the note at the bottom --- en/intro/cakephp-folder-structure.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/en/intro/cakephp-folder-structure.rst b/en/intro/cakephp-folder-structure.rst index b4ee93cd65..40ff9fd473 100644 --- a/en/intro/cakephp-folder-structure.rst +++ b/en/intro/cakephp-folder-structure.rst @@ -58,8 +58,8 @@ View .. note:: - The folders ``Shell`` is not present by default. - You can add them when you need them. + The folder ``Shell`` is not present by default. + You can add it when you need it. .. meta:: :title lang=en: CakePHP Folder Structure From 31578c349416d65c112614f2bda50006eb990b88 Mon Sep 17 00:00:00 2001 From: Spencer Smith Date: Thu, 13 Jul 2023 01:51:33 -0600 Subject: [PATCH 42/53] Update database.rst Fixed grammar errors throughout --- en/tutorials-and-examples/cms/database.rst | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/en/tutorials-and-examples/cms/database.rst b/en/tutorials-and-examples/cms/database.rst index 448bde6a07..575e3aedc0 100644 --- a/en/tutorials-and-examples/cms/database.rst +++ b/en/tutorials-and-examples/cms/database.rst @@ -57,7 +57,7 @@ necessary tables: VALUES (1, 'First Post', 'first-post', 'This is the first post.', 1, NOW(), NOW()); -If you are using PostgreSQL, connecting to ``cake_cms`` database and execute the +If you are using PostgreSQL, connect to the ``cake_cms`` database and execute the following SQL instead: .. code-block:: SQL @@ -109,14 +109,14 @@ following SQL instead: You may have noticed that the ``articles_tags`` table used a composite primary -key. CakePHP supports composite primary keys almost everywhere allowing you to +key. CakePHP supports composite primary keys almost everywhere, allowing you to have simpler schemas that don't require additional ``id`` columns. The table and column names we used were not arbitrary. By using CakePHP's :doc:`naming conventions `, we can leverage CakePHP more effectively and avoid needing to configure the framework. While CakePHP is flexible enough to accommodate almost any database schema, adhering to the -conventions will save you time as you can leverage the convention based defaults +conventions will save you time as you can leverage the convention-based defaults CakePHP provides. Database Configuration @@ -149,8 +149,8 @@ might look something like the following:: // More configuration below. ]; -Once you've saved your **config/app.php** file, you should see that 'CakePHP is -able to connect to the database' section have a green chef hat. +Once you've saved your **config/app.php** file, you should see that the 'CakePHP is +able to connect to the database' section has a green chef hat. .. note:: @@ -160,10 +160,10 @@ able to connect to the database' section have a green chef hat. Creating our First Model ======================== -Models are the heart of a CakePHP applications. They enable us to read and +Models are the heart of CakePHP applications. They enable us to read and modify our data. They allow us to build relations between our data, validate -data, and apply application rules. Models build the foundations necessary to -build our controller actions and templates. +data, and apply application rules. Models provide the foundation necessary to +create our controller actions and templates. CakePHP's models are composed of ``Table`` and ``Entity`` objects. ``Table`` objects provide access to the collection of entities stored in a specific table. @@ -185,7 +185,7 @@ this:: } } -We've attached the :doc:`/orm/behaviors/timestamp` behavior which will +We've attached the :doc:`/orm/behaviors/timestamp` behavior, which will automatically populate the ``created`` and ``modified`` columns of our table. By naming our Table object ``ArticlesTable``, CakePHP can use naming conventions to know that our model uses the ``articles`` table. CakePHP also uses @@ -200,7 +200,7 @@ conventions to know that the ``id`` column is our table's primary key. use the generated model instead. We'll also create an Entity class for our Articles. Entities represent a single -record in the database, and provide row level behavior for our data. Our entity +record in the database and provide row-level behavior for our data. Our entity will be saved to **src/Model/Entity/Article.php**. The completed file should look like this:: @@ -219,10 +219,10 @@ look like this:: ]; } -Our entity is quite slim right now, and we've only setup the ``_accessible`` -property which controls how properties can be modified by +Right now, our entity is quite slim; we've only set up the ``_accessible`` +property, which controls how properties can be modified by :ref:`entities-mass-assignment`. -We can't do much with our models right now, so next we'll create our first +We can't do much with our models yet. Next, we'll create our first :doc:`Controller and Template ` to allow us to interact with our model. From e813b2db0b8fc5e3b8d790a924bfa4a4611ada33 Mon Sep 17 00:00:00 2001 From: MarwanSalim <45453458+MarwanSalim@users.noreply.github.com> Date: Mon, 17 Jul 2023 12:49:06 +0800 Subject: [PATCH 43/53] Update routing.rst This is to provide the default match between route name and controller action used --- en/development/routing.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/en/development/routing.rst b/en/development/routing.rst index 25350acbc3..6e68828eac 100644 --- a/en/development/routing.rst +++ b/en/development/routing.rst @@ -1099,6 +1099,23 @@ only connect specific resource routes you can use the ``only`` option:: Would create read only resource routes. The route names are ``create``, ``update``, ``view``, ``index``, and ``delete``. +The default **route name and controller action used** are as follows: + +=========== ======================= +Route name Controller action used +=========== ======================= +create add +----------- ----------------------- +update edit +----------- ----------------------- +view view +----------- ----------------------- +index index +----------- ----------------------- +delete delete +=========== ======================= + + Changing the Controller Actions Used ------------------------------------ From 432d9787814c8bbd059465ad7af2a0c694fd311c Mon Sep 17 00:00:00 2001 From: Kevin Pfeifer Date: Wed, 19 Jul 2023 08:31:00 +0200 Subject: [PATCH 44/53] add deprecation info for Security Component --- en/controllers/components/security.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/en/controllers/components/security.rst b/en/controllers/components/security.rst index a958a86b89..e5434094e3 100644 --- a/en/controllers/components/security.rst +++ b/en/controllers/components/security.rst @@ -1,6 +1,10 @@ Security ######## +.. deprecated:: 4.0.0 + ``SecurityComponent`` has been deprecated. Use :doc:`/controllers/components/form-protection` instead + for form tampering protection or :doc:`/security/https-enforcer` to enforce use of HTTPS (TLS) for requests. + .. php:class:: SecurityComponent(ComponentCollection $collection, array $config = []) The Security Component creates a way to integrate tighter From 3358dc8cfde0631e2e0652d461dabb75d7a49cc9 Mon Sep 17 00:00:00 2001 From: Mark Scherer Date: Fri, 21 Jul 2023 12:30:25 +0200 Subject: [PATCH 45/53] Clarify convention for plugin class naming. (#7655) * Clarify convention for plugin class naming. * Clarify BC topic. * Update 4-4-migration-guide.rst * Reword --- en/appendices/4-4-migration-guide.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/en/appendices/4-4-migration-guide.rst b/en/appendices/4-4-migration-guide.rst index 62847d4518..f7dc37e8cb 100644 --- a/en/appendices/4-4-migration-guide.rst +++ b/en/appendices/4-4-migration-guide.rst @@ -112,10 +112,12 @@ ORM Plugins ------- -- Plugin class names now match the plugin name with a "Plugin" suffix. For - example, the plugin class for "ADmad/I18n" would be ``ADmad\I18n\I18nPlugin`` +- Plugin class names should now match the plugin name with a "Plugin" suffix. For + example, the plugin class for ``ADmad/I18n`` plugin would be ``ADmad\I18n\I18nPlugin`` instead of ``ADmad\I18n\Plugin``, as was the case for CakePHP 4.3 and below. - The old style name is still supported for backwards compatibility. + The old style name for existing majors should be kept to avoid BC breaks. + The new naming convention should be followed when developing a new plugin or + when doing a major release. Routing ------- @@ -209,7 +211,7 @@ Error Http ---- -* ``Response::checkNotModified()`` was deprecated. +* ``Response::checkNotModified()`` was deprecated. Use ``Response::isNotModified()`` instead. * ``BaseApplication::handle()`` now adds the ``$request`` into the service container all the time. @@ -228,11 +230,11 @@ ORM * The ``cascadeCallbacks`` option was added to ``TreeBehavior``. When enabled, ``TreeBehavior`` will iterate a ``find()`` result and delete records individually. This enables ORM callbacks to be used when deleting tree nodes. - + Plugins ------- -* Plugin classes can now be named to match the plugin name instead of just ``Plugin``. +* Plugin classes should now be named to match the plugin name instead of just ``Plugin``. For example, you should now use ``ADmad\I18n\I18nPlugin`` instead of ``ADmad\I18n\Plugin``. Routing From 667293d434d801cbcc3e6e815efaf4e5fd040323 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 23 Jul 2023 22:27:50 -0700 Subject: [PATCH 46/53] Improve wording. --- en/development/errors.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/en/development/errors.rst b/en/development/errors.rst index 05eceb2c9b..4fec2a5dd9 100644 --- a/en/development/errors.rst +++ b/en/development/errors.rst @@ -416,7 +416,7 @@ If your application contained the following exception:: use Cake\Core\Exception\CakeException; - class MissingWidgetException extends Exception + class MissingWidgetException extends CakeException { } @@ -424,8 +424,9 @@ You could provide nice development errors, by creating **templates/Error/missing_widget.php**. When in production mode, the above error would be treated as a 500 error and use the **error500** template. -If your exceptions have a code between ``400`` and ``506`` the exception code -will be used as the HTTP response code. +Exceptions that subclass ``Cake\Http\Exception\HttpException``, will have their +error code used as an HTTP status code if the error code is between ``400`` and +``506``. The constructor for :php:exc:`Cake\\Core\\Exception\\CakeException` allows you to pass in additional data. This additional data is interpolated into the the From fd0049031d2fe46549ee6ba1e97062c53608a0e1 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 23 Jul 2023 22:39:46 -0700 Subject: [PATCH 47/53] Small correction in error handling docs. --- en/development/errors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/development/errors.rst b/en/development/errors.rst index 4fec2a5dd9..243f0a8ad0 100644 --- a/en/development/errors.rst +++ b/en/development/errors.rst @@ -217,7 +217,7 @@ If you want to control the entire exception rendering and logging process you can use the ``Error.exceptionRenderer`` option in **config/app.php** to choose a class that will render exception pages. Changing the ExceptionRenderer is useful when you want to change the logic used to create an error controller, -choose the error template, or control how the overall rendering process. +choose the error template, or control the overall rendering process. Your custom exception renderer class should be placed in **src/Error**. Let's assume our application uses ``App\Exception\MissingWidgetException`` to indicate From 47a05840f5c92da604928cd12cd39ef282391a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Tue, 25 Jul 2023 16:16:33 +0200 Subject: [PATCH 48/53] Mention the DIC API to be considered stable https://github.com/cakephp/docs/pull/7312 --- en/appendices/4-4-migration-guide.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/en/appendices/4-4-migration-guide.rst b/en/appendices/4-4-migration-guide.rst index f7dc37e8cb..363145c424 100644 --- a/en/appendices/4-4-migration-guide.rst +++ b/en/appendices/4-4-migration-guide.rst @@ -192,6 +192,11 @@ Controller need to implement the static method ``contentType()`` to participate in content-type negotiation. +Core +---- + +* The previously experimental API for the :doc:`/development/dependency-injection` container, introduced in CakePHP 4.2, is now considered stable. + Database -------- From 234a779fd88c136bb8cac09d9b116cbeaddd6cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=BCrth?= Date: Tue, 25 Jul 2023 16:18:24 +0200 Subject: [PATCH 49/53] Shorten line length --- en/appendices/4-4-migration-guide.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/en/appendices/4-4-migration-guide.rst b/en/appendices/4-4-migration-guide.rst index 363145c424..5098bbface 100644 --- a/en/appendices/4-4-migration-guide.rst +++ b/en/appendices/4-4-migration-guide.rst @@ -195,7 +195,8 @@ Controller Core ---- -* The previously experimental API for the :doc:`/development/dependency-injection` container, introduced in CakePHP 4.2, is now considered stable. +* The previously experimental API for the :doc:`/development/dependency-injection` container, + introduced in CakePHP 4.2, is now considered stable. Database -------- From 18c15cb5f59ede446ead94a623a987e1c27b7280 Mon Sep 17 00:00:00 2001 From: celsowm Date: Tue, 25 Jul 2023 14:48:22 -0300 Subject: [PATCH 50/53] Update saving-data.rst saving many-to-many additional example --- en/orm/saving-data.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/en/orm/saving-data.rst b/en/orm/saving-data.rst index 55ab8c5def..6b385264b9 100644 --- a/en/orm/saving-data.rst +++ b/en/orm/saving-data.rst @@ -1035,6 +1035,18 @@ by setting data to the ``_joinData`` property:: $studentsTable->save($student); +The example above will only work if the property ``_joinData`` is already a +reference to a Join Table Entity. If this is not your case you can populate +using the Table to create the entity:: + + $coursesMembershipsTable = $this->getTableLocator()->get('CoursesMemberships'); + $student->courses[0]->_joinData = $coursesMembershipsTable->newEntity([ + 'grade' => 80.12, + 'days_attended' => 30 + ]); + + $studentsTable->save($student); + The ``_joinData`` property can be either an entity, or an array of data if you are saving entities built from request data. When saving junction table data from request data your POST data should look like:: From e9bef8caf8d5e9058e2b09104bd643da4078696d Mon Sep 17 00:00:00 2001 From: Mark Story Date: Tue, 25 Jul 2023 13:18:47 -0700 Subject: [PATCH 51/53] Tweak wording. --- en/orm/saving-data.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/en/orm/saving-data.rst b/en/orm/saving-data.rst index 6b385264b9..61c4769f86 100644 --- a/en/orm/saving-data.rst +++ b/en/orm/saving-data.rst @@ -1036,8 +1036,8 @@ by setting data to the ``_joinData`` property:: $studentsTable->save($student); The example above will only work if the property ``_joinData`` is already a -reference to a Join Table Entity. If this is not your case you can populate -using the Table to create the entity:: +reference to a Join Table Entity. If you don't already have a ``_joinData`` +entity, you can create one using ``newEntity()``:: $coursesMembershipsTable = $this->getTableLocator()->get('CoursesMemberships'); $student->courses[0]->_joinData = $coursesMembershipsTable->newEntity([ From 89b939b86b5e2ddb4da6006c5ea835266d7bcdcd Mon Sep 17 00:00:00 2001 From: xpyoda <122009162+xpyoda@users.noreply.github.com> Date: Thu, 27 Jul 2023 08:39:13 +0900 Subject: [PATCH 52/53] Update request-response.rst Correct "type()" to "setTypeMap()". Maybe it wasn't updated from an older version. --- ja/controllers/request-response.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ja/controllers/request-response.rst b/ja/controllers/request-response.rst index 306488bf5b..08bb052b9e 100644 --- a/ja/controllers/request-response.rst +++ b/ja/controllers/request-response.rst @@ -639,7 +639,7 @@ URIの操作 :php:meth:`Cake\\Http\\Response::withType()` を使用して、アプリケーションのレスポンスの コンテンツタイプを制御することができます。アプリケーションが Response に組み込まれていない -コンテンツの種類に対処する必要がある場合は、以下のように ``type()`` を使って設定することができます。 :: +コンテンツの種類に対処する必要がある場合は、以下のように ``setTypeMap()`` を使って設定することができます。 :: // vCard タイプを追加 $this->response->setTypeMap('vcf', ['text/v-card']); From b3d08dc73ade3eb860bea62993a864ad8ef72a89 Mon Sep 17 00:00:00 2001 From: Corey Taylor Date: Tue, 4 Jul 2023 18:43:17 -0500 Subject: [PATCH 53/53] Upgrade to Sphinx 7 --- .github/workflows/ci.yml | 2 +- Dockerfile | 10 +++++++--- en/Makefile | 25 ++++++++++++------------- es/Makefile | 25 ++++++++++++------------- fr/Makefile | 25 ++++++++++++------------- ja/Makefile | 25 ++++++++++++------------- pt/Makefile | 27 +++++++++++++-------------- requirements.txt | 4 ++-- 8 files changed, 71 insertions(+), 72 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 639805e460..7d10af65ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: 3.11 - name: Install dependencies run: | diff --git a/Dockerfile b/Dockerfile index 9d880c1083..a3c82aa89d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,14 @@ -FROM debian:bullseye +FROM debian:bookworm ENV DEBIAN_FRONTEND noninteractive LABEL Description="This image is used to create an environment to contribute to the cakephp/docs" RUN apt-get update && apt-get install -y \ + build-essential \ latexmk \ php \ - python3-pip \ + python3-full \ texlive-fonts-recommended \ texlive-lang-all \ texlive-latex-extra \ @@ -15,8 +16,11 @@ RUN apt-get update && apt-get install -y \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +RUN python3 -m venv /tmp/venv +ENV PATH="/tmp/venv/bin:$PATH" + COPY requirements.txt /tmp/ -RUN pip3 install -r /tmp/requirements.txt +RUN pip install -r /tmp/requirements.txt WORKDIR /data VOLUME "/data" diff --git a/en/Makefile b/en/Makefile index 17d949a216..a463687658 100644 --- a/en/Makefile +++ b/en/Makefile @@ -8,13 +8,12 @@ PAPER = BUILDDIR = ../build CONFDIR = ../config PYTHON = python3 -LANG = en SPHINX_LANG = en # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(SPHINX_LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest @@ -41,9 +40,9 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(LANG) + $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(SPHINX_LANG) @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(LANG)." + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(SPHINX_LANG)." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @@ -66,10 +65,10 @@ json: @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(LANG) + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(SPHINX_LANG) @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp/$(LANG)." + ".hhp project file in $(BUILDDIR)/htmlhelp/$(SPHINX_LANG)." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @@ -90,22 +89,22 @@ devhelp: @echo "# devhelp" epub: - $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(LANG) + $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(SPHINX_LANG) @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(LANG)." + @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(SPHINX_LANG)." latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(LANG)." + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex/$(LANG) all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(LANG)." + make -C $(BUILDDIR)/latex/$(SPHINX_LANG) all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text diff --git a/es/Makefile b/es/Makefile index d1954803a6..ad4fde2697 100644 --- a/es/Makefile +++ b/es/Makefile @@ -8,13 +8,12 @@ PAPER = BUILDDIR = ../build CONFDIR = ../config PYTHON = python3 -LANG = es SPHINX_LANG = es # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(SPHINX_LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest @@ -41,9 +40,9 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(LANG) + $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(SPHINX_LANG) @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(LANG)." + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(SPHINX_LANG)." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @@ -66,10 +65,10 @@ json: @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(LANG) + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(SPHINX_LANG) @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp/$(LANG)." + ".hhp project file in $(BUILDDIR)/htmlhelp/$(SPHINX_LANG)." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @@ -90,22 +89,22 @@ devhelp: @echo "# devhelp" epub: - $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(LANG) + $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(SPHINX_LANG) @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(LANG)." + @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(SPHINX_LANG)." latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(LANG)." + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex/$(LANG) all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(LANG)." + make -C $(BUILDDIR)/latex/$(SPHINX_LANG) all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text diff --git a/fr/Makefile b/fr/Makefile index 1827e4417a..ae8709114b 100644 --- a/fr/Makefile +++ b/fr/Makefile @@ -8,13 +8,12 @@ PAPER = BUILDDIR = ../build CONFDIR = ../config PYTHON = python3 -LANG = fr SPHINX_LANG = fr # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(SPHINX_LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest @@ -41,9 +40,9 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(LANG) + $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(SPHINX_LANG) @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(LANG)." + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(SPHINX_LANG)." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @@ -66,10 +65,10 @@ json: @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(LANG) + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(SPHINX_LANG) @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp/$(LANG)." + ".hhp project file in $(BUILDDIR)/htmlhelp/$(SPHINX_LANG)." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @@ -90,22 +89,22 @@ devhelp: @echo "# devhelp" epub: - $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(LANG) + $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(SPHINX_LANG) @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(LANG)." + @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(SPHINX_LANG)." latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(LANG)." + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex/$(LANG) all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(LANG)." + make -C $(BUILDDIR)/latex/$(SPHINX_LANG) all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text diff --git a/ja/Makefile b/ja/Makefile index 9cd4dbb416..601438f2e7 100644 --- a/ja/Makefile +++ b/ja/Makefile @@ -8,13 +8,12 @@ PAPER = BUILDDIR = ../build CONFDIR = ../config PYTHON = python3 -LANG = ja SPHINX_LANG = ja # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(SPHINX_LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest @@ -41,9 +40,9 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(LANG) + $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(SPHINX_LANG) @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(LANG)." + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(SPHINX_LANG)." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @@ -66,10 +65,10 @@ json: @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(LANG) + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(SPHINX_LANG) @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp/$(LANG)." + ".hhp project file in $(BUILDDIR)/htmlhelp/$(SPHINX_LANG)." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @@ -90,22 +89,22 @@ devhelp: @echo "# devhelp" epub: - $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(LANG) + $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(SPHINX_LANG) @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(LANG)." + @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(SPHINX_LANG)." latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(LANG)." + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex/$(LANG) all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(LANG)." + make -C $(BUILDDIR)/latex/$(SPHINX_LANG) all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text diff --git a/pt/Makefile b/pt/Makefile index 9f3182401a..ad13d861b8 100644 --- a/pt/Makefile +++ b/pt/Makefile @@ -8,13 +8,12 @@ PAPER = BUILDDIR = ../build CONFDIR = ../config PYTHON = python3 -LANG = pt -SPHINX_LANG = pt_BR +SPHINX_LANG = pt_BB # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees/$(SPHINX_LANG) -c $(CONFDIR) -D language=$(SPHINX_LANG) $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest @@ -41,9 +40,9 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(LANG) + $(SPHINXBUILD) -b html -D "exclude_patterns=*-contents.rst" $(ALLSPHINXOPTS) $(BUILDDIR)/html/$(SPHINX_LANG) @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(LANG)." + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html/$(SPHINX_LANG)." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @@ -66,10 +65,10 @@ json: @echo "Build finished; now you can process the JSON files." htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(LANG) + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp/$(SPHINX_LANG) @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp/$(LANG)." + ".hhp project file in $(BUILDDIR)/htmlhelp/$(SPHINX_LANG)." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @@ -90,22 +89,22 @@ devhelp: @echo "# devhelp" epub: - $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(LANG) + $(SPHINXBUILD) -b epub -D master_doc='epub-contents' $(ALLSPHINXOPTS) $(BUILDDIR)/epub/$(SPHINX_LANG) @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(LANG)." + @echo "Build finished. The epub file is in $(BUILDDIR)/epub/$(SPHINX_LANG)." latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(LANG)." + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(LANG) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex/$(SPHINX_LANG) @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex/$(LANG) all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(LANG)." + make -C $(BUILDDIR)/latex/$(SPHINX_LANG) all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex/$(SPHINX_LANG)." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text diff --git a/requirements.txt b/requirements.txt index 9dbc679f1d..5793b68834 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -docutils==0.17.1 -sphinx==4.5.0 +docutils==0.20.1 +sphinx==7.0.1 sphinxcontrib-phpdomain==0.11.1 cakephpsphinx>=0.1.57,<1.0