El concepto es sencillo, mediante una configuración específica le indicamos al bundle que rutas queremos que "escuche" para poder registrar ese evento en la tabla, acto seguido se muestra el enlace original.
Básicamente esto se resuelve en el onKernelRequest del Listener:
public function onKernelRequest(GetResponseEvent $event)
{
$route = $event->getRequest()->attributes->get('_route');
// this intercepts the click
if( isset($this->routesNames[$route]) ){
// aqui va el codigo que procesa el click
}
}
Evidentemente para poder comprobar la ruta con las que queremos procesar necesitamos rellenar el array routesNames, esto lo haremos el constructor del mismo listener, y aprovecharemos la posibilidad que nos ofrece Symfony2 para inyectar por dependencia las rutas a procesar, que estarán en el config.yml.
#every time a route is visited
jaitec_click:
routes:
# this is a logic name and can be anything
demo:
# this match to logic route (not pattern) defined in routing.yml
route: _demo_hello
# the type in wich is save at jaitec_click table
entity_type: demo
# this is for no id, the route contains a name or slug
entity_id: ~
entity_name: name
another:
route: _demo
entity_type: demo
# the route not contains any info because is a fixed route
entity_id: 1
entity_name: ~
Como podéis ver he puesto de ejemplo dos de las rutas que vienen con la instalación básica de Symfony2, como os decía en la declaración del servicio inyectamos las rutas de config.yml
services:
jaitec_click_request_listener:
class: Jaitec\ClickBundle\Listener\JaitecClickListener
arguments:
router: @router
container: @service_container
routes: %jaitec_click.routes%
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Ahora ya por fin podemos ver el constructor que recibe esos parámetros
public function __construct( RouterInterface $router, Container $container, $routes )
{
$this->router = $router;
$this->container = $container;
$this->routes = $routes;
$this->routesNames = array();
foreach($routes as $name=>$route){
$this->routesNames[$route['route']] = $name;
}
}
Lo demás os lo podéis imaginar, rellenar un registro en la tabla para la página o enlace visitado o si ya existe incrementar el número de click hechos.
Para rematar el bundle he añadido un controller que permite integrar la vista de las veces que se ha visto la página en nuestras propias vistas:
{% extends "AcmeDemoBundle::layout.html.twig" %}
{% block title "Hello " ~ name %}
{% block content %}
Hello {{ name }}!
Esta página se ha visto
{% render "JaitecClickBundle:View:clicksShow" with
{'entity_type':'demo', 'entity_id':null, 'entity_name':name} %}
{% endblock %}
El controller que hace esto es tan sencillo como ésto:
public function clicksShowAction( $entity_type, $entity_id, $entity_name )
{
$em = $this->getDoctrine()->getEntityManager();
$click = $em->getRepository('JaitecClickBundle:Click')->findOneBy(
array(
'entity_type' => $entity_type,
'entity_id' => $entity_id,
'entity_name' => $entity_name,
)
);
$times = $this->get('translator')->trans('times');
$time = $this->get('translator')->trans('time');
if(!$click){
$clicks = 0;
$msg = 'any '.$times;
}else{
$clicks = $click->getClicks();
if($clicks==1){
$msg = 'one '.$time;
}else{
$msg = $clicks . ' ' . $times;
}
}
return $this->render("JaitecClickBundle::include.html.twig",array(
'clicks' => $clicks,
'msg' => $msg,
));
}
El resto del código lo podéis descargar de aquí
Excelente artículo que me ayuda mucho a comprender por donde debo tirar. "Sólo" hay un problema para mi caso particular, y es que estoy trabajando con una BBDD NoSQL, MongoDB concretamente. ¿Sabes como extrapolar esta información para su implementación en Mongo? Me sería de mucha ayuda.
ResponderEliminarGracias,
Cándido Hernández
Gracias Cándido por tus elogios.
ResponderEliminarMe parece muy interesante lo que comentas y ya que ahora estoy utilizando MongoDB no me costaría mucho hacer una continuación del artículo en esta línea, esta semana publico algo en este sentido.
Eso estaría genial. Estaré atento a las publicaciones.
ResponderEliminarHola, he actualizado el bundle para que se pueda instalar en versiones más recientes de SF y se pueda configurar para usar con MongoDB o MySQL.
ResponderEliminarhttps://github.com/jlaso/visit-control-bundle
Además lo he añadido a una estructura básica que tengo para probar lo de las traducciones, para que se vea en funcionamiento.
https://github.com/jlaso/tradukoj-symfony2-demo
En cuanto encuentre algo de tiempo preparo un artículo completo.
Hola Cándido, me he confundido y he comentado más abajo.
ResponderEliminarEsta solución es buena pero en un caso de que el usuario visita muchas veces una pagina en un intervalo corto de tiempo y no quisiera que esas visitas cuenten que tendría que hacer?
ResponderEliminarHola Daymer, primero que nada, muchas gracias por comentar.
ResponderEliminarPara el caso que comentas yo establecería unas reglas de negocio: primero guardas la IP del visitante y compruebas en cada visita que hace de nuevo si es desde la misma IP y si han transcurrido al menos x segundos desde la última visita.
Sería una buena mejora para el bundle descrito. Lo cual te invito a hacer.
Gracias de nuevo.