Sunteți pe pagina 1din 25

Programacin III

2012

Action Controllers y Estructura Modular de Directorio

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
Introduccin
Abordaremos luego en este en nuevo nuevos captulo un primer que repaso la de

2012

los clase,

Action para

Controllers, explicaremos ingresar usando Zend Tool.

mtodos

provee

la explicacin de cmo "modularizar" nuestro sistema ZF

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
Repaso sobre Action Controllers Zend_Controller_Action Action es una clase abstracta utilizada para

2012

implementar

Controllers, cuando queremos construir aplicaciones web basadas en MVC y se utiliza en conjunto con el Front Controller.

Heredando la clase Action Controller


Para usar Zend_Controller_Action, es necesario crear una sub clase que herede de sta. Se utiliza Controller Action para crear nuestra propia clase que representa un conjunto de acciones, cada accin son implementaciones de mtodos que sirven para crear una a pgina web en particular y manejar las y peticiones relacionadas sta. Lo ms sencillo es heredar de esta,

crear mtodos que correspondern a varias acciones de nuestra aplicacin. Por ejemplo:
class FooController extends Zend_Controller_Action { public function barAction() { // hacer alguna lgica de negocio }

public function bazAction() { // hacer alguna lgica de negocio } }

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III

2012

En el ejemplo la clase FooController (controlador foo) define dos acciones, bar y baz. Por diseo, Zend_Controller_Action debe ser heredada a fin de crear un action controller (Aplicacin MVC). Como mnimo se necesita definir los mtodos Action que el controlador llamar en una determinada peticin. Tambin repitiendo podramos encontrarnos con el problema de que estamos

las mismas configuraciones o mtodos (tiles) en muchos de nuestros class) que para resolver dicha

controladores; si es as, es recomendable crear una clase base abstracta en comn (common base controller extienda redundancia. a Zend_Controller_Action

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
Iniciar el Objeto Action Controllers
Aun cuando es posible no Zend_Controller_Action::__construct sobrescribir el constructor es ejecuta algunas del

2012

action

controller

recomendado. importantes

tareas, tales como registrar el objeto Request y Response, as como tambin cualquier argumento de invocacin pasado por el Front Controller. En caso de que vayamos a sobrescribir el constructor hay que asegurar llamar a: parent::__construct($request, $response, $invokeArgs). La ms apropiada va para hacer una inicializacin es usar el mtodo init(), el cual es llamado como la ltima tarea en el constructor __construct(). Por ejemplo si quiero iniciar clases del modelo o una conexin a la base de datos:

class FooController extends Zend_Controller_Action { public function init() { $this->db = Zend_Db::factory('Pdo_Mysql', array( 'host' => 'myhost',

'username' => 'user', 'password' => 'XXXXXXX', 'dbname' )); } } => 'website'

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
Mtodos Pre- y Post-Dispatch
Zend_Controller_Action especifica dos mtodos que pueden ser sobrescritos

2012
para dar

mayor apoyo y funcionalidad a una accin determinada, preDispatch() y postDispatch().

preDispatch() es llamado justo antes de ejecutar el mtodo de la accin en cuestin postDispatch() como indica su nombre es llamado justo despus de ejecutar la accin en cuestin.

Estos mtodos pueden ser bastante tiles al momento de verificar una autenticacin o ACL antes de ejecutar la accin, en otras palabras trabajan, como interceptores de las acciones ("antes de hacer algo", "luego de hacer algo").

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
Mtodos Accessors

2012

Un nmero de objetos y variables son registradas en el objeto Action Controller y cada una de estas tienen sus mtodos getter y setter (tambin llamados mtodos accessor).

Request Object: getRequest() puede ser usado para obtener el objeto Request usado para llamar la accin con los parmetros de la peticin actual.
$this->getRequest()->getParam(id);

Response el

Object:

getResponse()

puede

ser

usado

para

obtener

objeto Response

para agregar o configurar un tipo de respuesta

final, como por ejemplo:


$this->getResponse()->setHeader('Content-Type', 'text/xml'); $this->getResponse()->appendBody($content);

Invocation dentro del

Arguments: Router,

el Front Controller puede agregar parmetros y Action Controller. Para obtener

Dispatcher,

estos, usamos el mtodo getInvokeArg($key); alternativamente para obtener todos los parametros usamos el mtodo getInvokeArgs().

Request parameters: El objeto request agrega los parmetros del Request, tales como los parmetros $_GET o $_POST, o los parmetros especificados en la URL. Para obtener estos, usamos _getParam($key) o _getAllParams(). Tambin podemos agregar parametros al request mediante el metodo _setParam(); esto es til al momento de reenviar hacia una adicional accin _forward(). Para verificar si el parmetro del request existe o no usamos el til mtodo
hasParam($key).

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
Integracin con el Objeto Vista, Zend_View

2012

Zend_Controller_Action provee un flexible mecanismo para la integracin con el objeto view a travs de dos mtodos: initView() y render(); El primero view carga dentro y da el la valor al atributo $view, que corresponde e inicializa al el

objeto objeto

que implementa

Interface

Zend_View_Interface

del controlador, y el segundo ejecuta el render de la vista

correspondiente a actual accin en cuestin. El mtodo initView() inicializa el objeto de vista (view) dentro de la clase controladora Zend_Controller_Action. Implcitamente el mtodo render() llama a initView() a su vez para inicializar y recibir el objeto vista (sin embargo este puede ser inicializar en cualquier momento), por defecto este poblar a la propiedad $view de la clase controladora con el objeto Zend_View. En definitiva la funcionalidad del mtodo initView() es simplemente iniciar el objeto de vista para que lo podamos utilizar en el controlador, todo el proceso lo realiza en forma implcita o internamente, esto es transparente para el desarrollador. Las vistas/plantillas phtml asume que debe estar en el subdirectorio views/scripts/, y se asume que el sub-directorio views debe de contener las carpetas helpers y filters. Al determinar el nombre de la vista y su ubicacin (View Script Name y Path), el directorio views/scripts/ ser usado como el directorio principal (base path), dentro de este contendr a los subdirectorios nombrados segn cada unos de los controladores de nuestra aplicacin y estos a su vez contendrn a las vistas (view scripts) con extensin .phtml nombradas segn cada acciones (actions) del controlador (controller).

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
El mtodo render() tiene la siguiente estructura:

2012

string render(string $action = null, string $name = null, bool $noController = false);

El mtodo render() ejecuta propiamente dicho el cdigo de la vista. Si no se pasa ningn parmetro, esta asume que debe hacer render (ejecutar la vista) del controlador y accin de la peticin, en otras palabras [controller]/[action].phtml (donde .phtml es el valor del sufijo o extencin de el script de vista). Al pasar un valor en el parmetro $action del mtodo: render($action), este ejecutar el render de la vista (nombrada como el parmetro $action) en el subdirectorio [controller].
$this->view->render(listado);

Para sobrescribir usando el subdirectorio [controller], se debe pasar a true el valor de $noController. El ltimo parmetro nos dice que no tome en cuenta el directorio del controlador (noController) y nos sirve para ir a buscar la vista en la raz del directorio donde tenemos las vistas o bien en otro controlador. Es decir podramos de forma explcita especificar el directorio donde se encuentra la vista y de esta forma podemos reutilizar las distintas vistas entre los controladores (e incluso entre mdulos): Nos fijamos en el siguiente ejemplo donde tenemos dos controladores IndexController y UsuarioController, la idea aqu es reutilizar la vista del formulario del controlador Usuario en el de Index:

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

Programacin III
Accin formulario en IndexController:
public function formAction() { $this->render("usuario/form", null, true); }

2012

Nos fijamos que le estamos diciendo al render que no busque la vista en el controlador actual (no buscar en controlador index) sino que la busque en el controlador usuario. Finalmente, la vista es ejecutada ("rendereada") dentro del objeto Response, si deseamos ejecutar la vista (hacer render) hacia un especifico segmento en el objeto response debemos pasar el nombre del segmento como parmetro $name.

$this->view->render(listado, header_segmento);

Tanto como los nombres de los controladores y las acciones pueden contener caracteres delimitadores tales como Internamente, entonces una peticin bar/baz-bat el script foo-bar/baz-bat.phtml. hay que Si camelCasing, separar recordar del o el que tipo '.', y '-', /foo.bar/baz-bat har la en de o render() bien /fooen para normaliza estos hacia '-' cuando determina el nombre de la vista (view script name). /foo.bar/baz.bat, mtodo este resultar el render un '-'

accin

contiene

la palabras en una determinada vista (view script file name).

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

10

Programacin III
Ejemplos:
class MyController extends Zend_Controller_Action { public function fooAction() { // Hace el Render de my/foo.phtml $this->render();

2012

// Hace el Render de my/bar.phtml $this->render('bar');

// Hace el Render de baz.phtml $this->render('baz', null, true);

// Renders my/login.phtml hacia el segmento 'form' de l // objeto response $this->render('login', 'form');

// Renders site.phtml hacia el segment 'page' de el objeto response // No se debe usar el sub-directorio 'my/' $this->render('site', 'page', true); }

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

11

Programacin III
public function bazBatAction() { // Renders my/baz-bat.phtml $this->render(); } }

2012

En este ltimo ejemplo podemos ver cmo al ejecutar el mtodo bazBatAction el sistema buscar una vista con el nombre baz-bat.phtml

Otros mtodos tiles


Adems de los mtodos getter y setter (accessors) y de los de integracin con el objeto View, Zend_Controller_Action tiene varios tiles mtodos para ejecutar tareas comunes desde dentro del mtodo action o incluso desde los mtodos pre-/post-dispatch. Tenemos dos formas de re-direccin en ZF: _redirect y _forward, de las cuales hay una notable diferencia, a grandes rasgos el primero redirige a una nueva peticin HTTP, es decir una nueva URL (por lo que se pierden todos los objetos y variables) y el segundo redirige a otra accin y/o controlador y/o modulo dentro de la misma peticin (aqu mantenemos los datos y objetos, ya que seguimos estando dentro de la misma peticin HTTP). _forward($action, $controller = null, $module = null, array $params = null): ejecuta otra accin. Si es llamado dentro de el preDispatch(), la actual accin ser saltada para ejecutar esta nueva, en otras palabras la accin solicitada ser remplazada a favor de esta nueva. _redirect($url, array $options = array()): re-direcciona hacia otra localizacin. Este mtodo toma la URL y un opcional set de opciones, por defecto este ejecuta un HTTP 302 redirect.

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

12

Programacin III
Estructura Modular de Directorios

2012

La estructura de directorio modular permite separar nuestra aplicacin en diferentes mdulos, agregando un nivel ms a nuestro sistema, cada uno con su estructura MVC individual y re-usar estos a lo largo de nuestro sistema e incluso entre distintos proyectos. Cada mdulo es una sub-aplicacin independiente que tiene que tener la estructura la misma estructura de directorio MVC que vimos hasta ahora. Para ilustrar la nueva estructura de directorios con mdulos como "default" y "usuarios":

Proyecto-zf/ public/index.php application/ config/config.ini layouts/scripts/main.phtml modules/ default/ controllers/ IndexController.php FooController.php models/ views/ scripts/ index/ foo/ helpers/ filters/ usuarios/ controllers/ IndexController.php models/ views/ scripts/ index/ helpers/ filters/

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

13

Programacin III

2012

Observamos que dentro de cada modulo tenemos carpetas MVC (models, views, controllers), es decir, cada mdulo es un sub-aplicacin de nuestro gran sistema y tiene su estructura MVC interna con la misma estructura que el primer ejemplo "no modular" donde antes tenamos un subdirectorio que representaba el lugar donde guardar todos nuestros controllers, ahora tenemos un nivel mayor de abstraccin y de organizacin: el mdulo. Observemos las diferencias entre el Antes y el Despus:

Antes:
/proyecto/controller/action/par1/var1/par2/var2/

Ahora:
/proyecto/modulo/controller/action/par1/var1/par2/var2/ Lo que nos permite cambiar la estrategia de organizacin de nuestro proyecto:

Antes
/proyecto-zf/usuarios/ver/id/1

Ahora
/proyecto-zf/frontend/usuarios/ver/id/1 /proyecto-zf/admin/usuarios/ver/id/1

En el primer caso decidimos dividir nuestro sistema en dos mdulos, toda la la funcionalidad de "frontend" (zona pblica de nuestro sitio) y el "backend" (zona privada, que requiere autenticacin). En el segundo caso, decimos que en vez de "backend" tendremos un mdulo "admin" donde todas las operaciones de gestin debern estar ah, y esto podr reusarse entre sistemas (ya que la administracin de usuarios no cambiar y la mantendremos como un mdulo estndar).

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

14

Programacin III

2012

Cuando trabajamos con Mdulos en Zend Framework hay que especificar dentro del nombre de la clase controladora el NameSpace, que corresponde al nombre del modulo al cual pertenece, seguido de un guin bajo y el nombre del controlador:

Nombremodulo_NombrecontroladorController (NameSpace_NameController)

Para ilustrarlo en un ejemplo, tenemos una clase controladora Index dentro del modulo usuarios (nombre de archivo IndexController.php):

Antes (sin mdulos)


class IndexController extends Zend_Controller_Action { public function indexAction() {} }

Ahora (con mdulos)


class Usuarios_IndexController extends Zend_Controller_Action { public function indexAction() {} }

Nos fijamos que el nombre de la clase comienza con Usuarios, esta primera parte tiene que coincidir con el nombre de nuestro mdulo llamado "usuarios" (donde cada mdulo tiene su propio directorio dentro de la carpeta application/ de nuestro proyecto), luego el nombre de la clase se compone de un guin abajo _ seguido por el nombre del controlador IndexControler.

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

15

Programacin III

2012

IMPORTANTE: NO se agrega el prefijo namespacing en los controladores del mdulo default a menos que se configure en el application.ini con prefixDefaultModule=1 Hay que tener en cuenta que en el mdulo default, los controladores no necesitan un prefijo de nombre del modulo o namespacing, excepto que se configure la regla prefixDefaultModule=1 en el application.ini. As, en el ejemplo anterior, los controladores por defecto en el mdulo no es necesario un prefijo de 'Default_' - se trata simplemente con el nombre del controlador: IndexController, ErrorController 'y' FooController. No obstante el prefijo namespacing se utiliza en todos los otros mdulos.

Repasemos lo visto hasta ahora


Con esta nueva estructura van a cambiar las URL para ejecutar la peticin correcta en el modulo, controlador y accin correspondiente, lo que hace es agregar un segmento ms en el comienzo:

:module/:controller/:action/ http:// midominio.com/usuarios/index/listado http://midominio.com/usuarios/index/ver/id/1 http:// midominio.com/usuarios/index

El re-cuadro tener las

anterior

ilustra

ejemplos

de

la

estructura

que

tienen el

que primer el

peticiones de URL, las

cuales

mantendr la el controlador

convencin que

que

segmento representar siempre al mdulo al cual debemos dirigirnos, el segundo segmento representar modulo accin y finalmente los parmetros de la peticin. deber contener (dentro del directorio controllers), luego es seguido por el nombre de la

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

16

Programacin III
En resumidas cuentas tomando el segundo ejemplo de url http://midominio.com/usuarios/index/ver/id/1 podemos decir que estamos

2012

accediendo mediante url al detalle del usuario 1, donde el mdulo es usuarios, el controlador es IndexController y la accin es verAction() y recibe por parmetro de peticin GET id=1.

Creando / Agregando nuestros mdulos con Zend Tool


zf create module usuarios zf create module admin zf create module default

Como pueden ver, crea un nuevo directorio llamado "modules" dentro del directorio application. Ah se crea el directorio para el mdulo "usuarios", "admin" y "default" con una estructura similar para el mdulo como hemos descrito anteriormente. Adems nos genera una nueva entrada de configuracin en el application.ini

resources.frontController.moduleDirectory = APPLICATION_PATH "/ modules"

Y manualmente agregamos la siguiente lnea justo debajo de la creada:


resources.modules[] = ""

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

17

Programacin III
creamos un mdulo default, se agrega lo siguiente en el .ini

2012

Hasta ahora crea solo directorios sin afectar la configuracin del sistema, pero, si

resources.frontController.params.prefixDefaultModule = "1" Ante ambas opciones, deshabilitarlo o no, preferimos mantener el criterio nico de que todo tenga un prefijo (esto lo podemos cambiar a justo del consumidor).

Sinnimos
Podemos definir nuestros valores booleanos de distintas formas: resources.frontController.params.prefixDefaultModule = "1" resources.frontController.params.prefixDefaultModule = 1 resources.frontController.params.prefixDefaultModule = true Con sta configuracin, que viene por defecto cuando trabajamos mdulos con Zend Tool, permite a las clases Controllers del mdulo Default agregar el prefijo del mdulo y funcionar de la misma forma: Default_IndexController y Default_ErrorController.

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

18

Programacin III
Configuracin bsica en un proyecto que usa mdulos

2012

Por defecto, cuando construimos nuestra aplicacin, esta no viene con mdulos, y la configuracin para encontrar los controllers es la siguiente

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"

La sugerencia es que no usen un hbrido, si el proyecto es por defecto no-modular, trabajen siempre de esta forma, si es modular, saquen (borren) toda la estructura no-modular que cuelga de application (controllers, models, views) y de ahora en ms todo es un mdulo, hasta uno por defecto (default), as evitan problemas con la configuracin del sistema.
Cmo se vera nuestra estructura modular actual

Lo primer que habra que hacer es cambiar esta lnea por otra (en el application.ini): resources.frontController.moduleDirectory = APPLICATION_PATH "/modules" ;resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers" (esta linea la debemos comentar o la eliminar) Tambin tenemos las siguientes directivas para forzar el comportamiento por defecto o por si queremos cambiar el comportamiento por otro, cambiar el mdulo por defecto, cambiar las rutas, etc: resources.frontController.defaultModule = "default" resources.frontController.moduleControllerDirectoryName = "controllers" Y hay que dejar inicializado: resources.modules[] = "" Luego de crear los mdulos veremos la segunda parte de la configuracin (s, an falta para que todo funcione correctamente y detecte todos los componentes de forma automtica).
AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

19

Programacin III
Implementando Clases de Modelos en nuestros Mdulos en Zend

2012

Ahora vamos a implemenar y trabajar con Modelos en nuestro proyecto con estructura modular. El siguiente paso es crear una clase que herede Zend_Application_Module_Bootstrap en la raz de cada mdulo de nuestra aplicacin, esta clase nos permite tener un autoloader o cargador automtico de nuestras clases de modelo y ms adelante las clases de Formularios de Zend:

Una vez ms, el nombramiento es importante, el nombre de clase debe ser el {nombre del mdulo}_Bootstrap y debe extenderse Zend_Application_Module_Bootstrap. Se debe almacenar en un archivo llamado Bootstrap.php dentro de la raz del mdulo. Luego tenemos que aadir (o chequear que est) una lnea en application.ini para habilitar mdulos al final de la seccin [production] debajo de la regla moduleDirectory:
resources.modules[] = ""

De esta manera todas nuestras clases de modelo se cargaran automticamente mediante el Auto Loader de Zend, implcitamente (no lo vemos), sin necesidad de usar require_once ni dada por el estilo.

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

20

Programacin III

2012

Adems ser necesario nombrar nuestras clases de modelo que estn dentro de la carpeta models del mdulo de la siguiente forma: el nombre de clase debe ser el {nombre del mdulo}_Model_{nombre de la clase}

Dentro de nuestro mdulo de usuarios

Entonces sobre el modulo usuarios segn imagen de arriba, nada nuevo y luego creamos la clase Bootstrap del mdulo usuarios para el Auto Loader de las clases del modelo:

El archivo lo nombramos como Bootstrap.php y lo guardamos dentro de la carpeta usuarios (raz del mdulo usuarios).

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

21

Programacin III

2012

Luego dentro de la carpeta models del mdulo usuarios, deberamos renombrar nuestras clases de modelo de la siguiente forma:

Y el DAO:

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

22

Programacin III
Lo que sucede internamente en la clase Bootstrap
Entrando ms en profundidad con la forma de trabajar con mdulos en Zend

2012

Framework, nuestro Bootstrap (internamente) quedara de la siguiente forma:

Por ejemplo, aunque no lo vemos, dentro de la clase Bootstrap, cuando trabajamos con mdulos en Zend Framework implcitamente y internamente maneja e invoca el Front Controller a travs de la clase Zend_Controller_Front en su forma modular implementado por el mtodo addModuleDirectory. Observando, nos damos cuenta de que Zend_Controller_Front agrega la raz del directorio modules el cual contendr todos los mdulos del sistema, mediante el mtodo addModuleDirectory. El mtodo addModuleDirectory() internamente implementa SPL DirectoryIterator y agrega los nombres directorio (dentro de la carpeta "modules") como mdulos o sub-sitios del sistema, lo que lo hace ms eficiente y menos lneas de cdigo por parte del cliente.

/** ETC ETC */ require_once 'Zend/Controller/Front.php'; $frontController = Zend_Controller_Front::getInstance(); $frontController->addModuleDirectory($rootPath . '/application/modules') ->throwExceptions(true)->dispatch();

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

23

Programacin III

2012

Otros comandos de Zend Tool para mdulos


Si desea crear un controlador para un mdulo especfico, utilice cualquiera de los siguientes comandos:
1. 2. 3. zf create controller Post 1 blog zf create controller Post -m blog zf create controller Post --module=blog

Nota: En el primer comando, 1 es el valor para "incluir el IndexAction" al crear el controlador. Nos crear el controlador PostController dentro del mdulo blog:
class Blog_PostController extends Zend_Controller_Action

Nos crear una accin registrarAction del controlador PostController dentro del mdulo blog:
cd C:\xampp\htdocs C:\xampp\htdocs>cd proyecto-zf C:\xampp\htdocs\proyecto-zf>zf create action registrar Post 1 blog

..\zf create action [action name] [controller name] 1 [module name] El nmero 1 es para crear un la vista de esta accin, si no asignamos el 1 no la crea. Para clases del modelo en un determinado mdulo:
zf create model Post -m blog

Nos crear una clase de modelo Post dentro del mdulo blog:
class Blog_Model_Post

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

24

Programacin III
oficial de Zend Framework: Zend Tool.

2012

Para ms informacin del uso de la lnea de comando de Zend Tool visitar el manual

En Resumen final
. Aunque pensemos "el proyecto ser pequeo y no crecer", generalmente ser todo lo contrario, sin contar que por cada que proyecto se que desarrollemos, por lo tanto

enfrentaremos constantemente

mdulos

repetirn,

pasaremos el resto de nuestros das programando mdulos de administracin de usuarios o reusaremos el mismo mdulo y disfrutaremos desarrollando solo nuevos e interesantes mdulos?

FIN.

AUTOR: Fredy Cabrera Arias. Email: fredyc20@hotmail.com

25

S-ar putea să vă placă și