1

I wrote a custom module that records page views. So each time a user views a node, it creates an entry in a database table. Essentially I wanted my own custom statistics module.

The problem is, it's only called once. I would assume some kind of caching is applied to this function. I have this:

function hook_node_view( $node,  $display, $view_mode, $langcode)
{
    $nodeObject = $node['#node'];

    $insert = array(
        'created'    => REQUEST_TIME,
        'nid'        => $nodeObject->id(),
        'uid'        => \Drupal::currentUser()->id(),
        'ip'         => \Drupal::request()->getClientIp(),
        'session_id' => session_id(),
    );

    db_insert('node_view_log')
    ->fields($insert)
    ->execute();

}

But it is only called once per node, and not each time the node is viewed. Any idea as to why this is happening? Is there a way to turn of caching for this function only? Or is there perhaps a better place to log page views?

4
  • drupal.stackexchange.com/questions/176753/… follow this link Oct 12, 2016 at 5:22
  • I don't really want to disable all caching. I just want to make sure this specific function is called every time a node is viewed. Oct 12, 2016 at 5:23
  • Its the problem with caching the node view is cached so the cached page is being viewed . So you need to disable the caching first. Oct 12, 2016 at 5:42
  • Then it sounds like there must be a better way to log statistics. Oct 12, 2016 at 6:29

2 Answers 2

1

Drupal core provides the statistics module which does basically this. It just maintains a counter and not a record per visit, but that's the basic idea.

And it does that with JS that triggers a callback. The reason it does it like that is that nothing on the server side can reliably do this in many situations. You might have something like varnish in front of your site, then most requests will not even reach your webserver.

0

Usually you do this outside of drupal in access.log. Or use the statistics module, which does the logging in javascript with ajax.

If you need to do this in drupal, the only way to catch all requests is with symfony middlewares, before the drupal kernel is loaded:

namespace Igorw\Middleware;

use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;

class Logger implements HttpKernelInterface
{
    private $app;
    private $logger;

    public function __construct(HttpKernelInterface $app, LoggerInterface $logger)
    {
        $this->app = $app;
        $this->logger = $logger;
    }

    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
    {
        $response = $this->app->handle($request, $type, $catch);

        $this->logger->info(sprintf('%s "%s %s %s" %d',
            $request->getHost(),
            $request->getMethod(),
            $request->getRequestUri(),
            $request->server->get('SERVER_PROTOCOL'),
            $response->getStatusCode()));

        return $response;
    }
}

Source: https://igor.io/2013/02/02/http-kernel-middlewares.html

You would need to adapt the example for drupal. But I wouldn't do this. See this warning from the same source:

A word of warning

Middlewares are neat, but they are not suited for everything.

For one, infrastructure tasks like logging and caching really belong into your webserver. Re-implementing that in PHP is just going to slow things down. Use Varnish.

The more important point however is that middlewares are coupled to HTTP. They should only be considered an integration point. The specific pieces of functionality they provide should still be moved to separate classes so that they can be properly unit tested and perhaps re-used.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.