Install rsyslog on your web server (should already be installed)
Enable the syslog module in Drupal
To allow Drupal to log to rsyslog, you have to enable the Drupal syslog module. Syslog is included with Drupal core.
Configure the Drupal module
In admin/config/development/logging , you can select one of the following prefixes for your website:
LOG_LOCAL0
LOG_LOCAL1
LOG_LOCAL2
LOG_LOCAL3
LOG_LOCAL4
LOG_LOCAL5
LOG_LOCAL6
LOG_LOCAL7
If you log one site, it really doesn’t matter which one you choose. If however you have multiple sites running on the same machine, and you want each site to log to a different file, the selection does matter. Eg: site A logs to LOG_LOCAL0, site B logs to LOG_LOCAL1, etc.
Configure rsyslog
vim /etc/rsyslog.d/50-default.confadd the line:
local0.* /var/log/drupal.logThis will log all local0 logs to /var/log/drupal.log
If you have selected local1 in the previous step, you have to replace “local0” by “local1″ in the configuration line, etc. You can name your log file different from “drupal.log”, in fact you can choose any name that hasn’t been taken yet.
Restart rsyslog
service rsyslog restartYou should now cause an error (eg. 404) and see if /var/log/drupal.log has been created and gets filled. If you're having problems check if /var/log/messages gets filled with Drupal log messages. If it does recheck the previous steps and see if you made any mistakes.
Disable dblog
At this point, Drupal will log to both the log system and the regular dblog. You can simply disable the module “database logging” in admin/modules .
Install rsyslog on your web server (should already be installed)
Enable the syslog module in Drupal
To allow Drupal to log to rsyslog, you have to enable the Drupal syslog module. Syslog is included with Drupal core.
Configure the Drupal module
In admin/config/development/logging , you can select one of the following prefixes for your website:
LOG_LOCAL0
LOG_LOCAL1
LOG_LOCAL2
LOG_LOCAL3
LOG_LOCAL4
LOG_LOCAL5
LOG_LOCAL6
LOG_LOCAL7
If you log one site, it really doesn’t matter which one you choose. If however you have multiple sites running on the same machine, and you want each site to log to a different file, the selection does matter. Eg: site A logs to LOG_LOCAL0, site B logs to LOG_LOCAL1, etc.
Configure rsyslog
vim /etc/rsyslog.d/50-default.confadd the line:
local0.* /var/log/drupal.logThis will log all local0 logs to /var/log/drupal.log
If you have selected local1 in the previous step, you have to replace “local0” by “local1″ in the configuration line, etc. You can name your log file different from “drupal.log”, in fact you can choose any name that hasn’t been taken yet.
Restart rsyslog
service rsyslog restartYou should now cause an error (eg. 404) and see if /var/log/drupal.log has been created and gets filled. If you're having problems check if /var/log/messages gets filled with Drupal log messages. If it does recheck the previous steps and see if you made any mistakes.
Disable dblog
At this point, Drupal will log to both the log system and the regular dblog. You can simply disable the module “database logging” in admin/modules .
titantemplatescom posted a photo:
titantemplatescom posted a photo:
Mike Crittenden recently wrote an article on an "Invented Here" aversion in the Drupal community. One of the main points made there is that often a module will do what you want, but also introduce new things that you actually don't want that may outweigh or negate the good in the long term. It could be as innocent as a form alter adding a description to an existing form, or some CSS intended to make a module seem more appealing "out of the box", but if it doesn't match what your designer handed you (my experience with designers is that the chance of a design matching the styles of a contrib module the designer hasn't explicitly referenced is somewhere under one in a million) it means more work, and there's a huge range of how much more work it means depending on the current requirements and how the module is written.
A huge number of modules on d.o are very small (in terms of lines of code) and only aim solve a single, very specific use-case. I often find that, after reading over the code there's only 1-5 functions that "do the work" and the bulk of the code is just implementing Drupal hooks to provide a nice UI, default settings, page callbacks, permissions, etc...
Given that:
...when I see a new module that promises to add a new block or node links or javascript widget I approach it with a degree of caution and find myself wondering "Could I just copy/paste this module's API and then do/render exactly what I actually want directly?".
The Flippy moduleCheck out the Flippy module. It's a really simple way to get first/previous/next/last style pagination on your nodes based on node creation dates and the content type of the current node.
The module code is pretty easy to read over (the main module file is under 500 lines of code), so I thought it would be a nice example on how to deconstruct a Drupal module into "Internal API + Drupal API implementations".
Let's say that for our requirements we want exactly what Flippy provides but we also want:
We're unlikely to find an existing contrib module that satisfies these requirements exactly without searching pretty hard, so let's see if we can just adapt Flippy to our needs.
Here's the list of all the functions in flippy.module with a summary of what they do:
Drupal Hooks:
Flippy internal API
As you can see, the majority of the functions here are Drupal hooks: preparing variables for templates, exposing the pager to the Field API, implementing theme templates, defining and rendering blocks, etc.
Because we don't need a UI or any particular rendering implementation to satisfy our requirements we only need to appropriate one function here, flippy_build_list() which looks like this:
/** * Function that builds the list of nodes */ function flippy_build_list($node) { $master_list = &drupal_static(__FUNCTION__); if (!isset($master_list)) { $master_list = array(); } if (!isset($master_list[$node->nid])) { // Create a starting-point query object $query = db_select('node') ->fields('node', array('nid', 'title')) ->condition('nid', $node->nid, '!=') ->condition('status', 1) ->condition('type', $node->type, '=') ->range(0, 1); $first = clone $query; $list['first'] = $first ->condition(db_or() ->condition('created', $node->created, '<') ->condition(db_and() ->condition('created', $node->created, '=') ->condition('nid', $node->nid, '<'))) ->orderBy('created', 'ASC') ->execute()->fetchAssoc(); $list['current'] = array( 'nid' => $node->nid, 'title' => $node->title, ); $prev = clone $query; $list['prev'] = $prev ->condition(db_or() ->condition('created', $node->created, '<') ->condition(db_and() ->condition('created', $node->created, '=') ->condition('nid', $node->nid, '<'))) ->orderBy('created', 'DESC') ->execute()->fetchAssoc(); $next = clone $query; $list['next'] = $next ->condition(db_or() ->condition('created', $node->created, '>') ->condition(db_and() ->condition('created', $node->created, '=') ->condition('nid', $node->nid, '>'))) ->orderBy('created', 'ASC') ->execute()->fetchAssoc(); $last = clone $query; $list['last'] = $last ->condition(db_or() ->condition('created', $node->created, '>') ->condition(db_and() ->condition('created', $node->created, '=') ->condition('nid', $node->nid, '>'))) ->orderBy('created', 'DESC') ->execute()->fetchAssoc(); $random = clone $query; $list['random'] = $random ->orderRandom() ->execute()->fetchAssoc(); $master_list[$node->nid] = $list; } return $master_list[$node->nid]; } "Just the good bits" - Meeting our requirementsprovide an array of structured data rather than a fully rendered pager.
Because Flippy provides its own API before using it, in the form of flippy_build_list() our first requirement is really easy to satisfy - this function already returns a nice, simple array of data based on the queries it runs. All we need to do is renamespace the function to MODULENAME_get_pager_info() or similar and put it in one of our custom modules and we've done step 1.
pagination to be based on updated date rather than created date.
For this we have to update the queries within flippy_build_list() to sort by updated date rather than created date.
If you haven't used the OOP database queries available in D7 then have a look at Berdir's conversion guide to get you up to scratch on the differences between DBTNG queries and the "old style" db_query("SELECT * FROM ....", $var1, $var2, ...) Drupal db functions.
Firstly, Flippy creates a "base" query in $query with some conditions shared by all the pagination links:
Flippy then clones this base query 6 times then extends (and actually executes) each new query object with the conditions specific to building that link:
For first/previous/next/last we also check the order of nids in the case that the created times are identical.
All we need to do to achieve sorting by updated date is to edit the conditions and the sorts in the overrides in a consistent way.
We should end up with something like this (modifying "created" to "changed"):
function MODULENAME_get_pager_info($node) { $master_list = &drupal_static(__FUNCTION__); if (!isset($master_list)) { $master_list = array(); } if (!isset($master_list[$node->nid])) { // Create a starting-point query object $query = db_select('node') ->fields('node', array('nid', 'title')) ->condition('nid', $node->nid, '!=') ->condition('status', 1) ->condition('type', $node->type, '=') ->range(0, 1); $first = clone $query; $list['first'] = $first ->condition(db_or() ->condition('changed', $node->changed, '<') ->condition(db_and() ->condition('changed', $node->changed, '=') ->condition('nid', $node->nid, '<'))) ->orderBy('changed', 'ASC') ->execute()->fetchAssoc(); $list['current'] = array( 'nid' => $node->nid, 'title' => $node->title, ); $prev = clone $query; $list['prev'] = $prev ->condition(db_or() ->condition('changed', $node->changed, '<') ->condition(db_and() ->condition('changed', $node->changed, '=') ->condition('nid', $node->nid, '<'))) ->orderBy('changed', 'DESC') ->execute()->fetchAssoc(); $next = clone $query; $list['next'] = $next ->condition(db_or() ->condition('changed', $node->changed, '>') ->condition(db_and() ->condition('changed', $node->changed, '=') ->condition('nid', $node->nid, '>'))) ->orderBy('changed', 'ASC') ->execute()->fetchAssoc(); $last = clone $query; $list['last'] = $last ->condition(db_or() ->condition('changed', $node->changed, '>') ->condition(db_and() ->condition('changed', $node->changed, '=') ->condition('nid', $node->nid, '>'))) ->orderBy('changed', 'DESC') ->execute()->fetchAssoc(); $random = clone $query; $list['random'] = $random ->orderRandom() ->execute()->fetchAssoc(); $master_list[$node->nid] = $list; } return $master_list[$node->nid]; }We can now call this function wherever we have a loaded node object to get a list of simple pagination links and we didn't need to install a whole new module to achieve this.
Persistent caching of our calculated pager info on a per-node basis.
Flippy doesn't provide this at all so we have to implement it ourselves whether we want to use Flippy or our custom adaption.
I'm actually not going to show the code required for this here, as Lullabot already have the best introductory guide I've ever read on the topic so I don't feel the need to duplicate their efforts.
The point here is less about showing exact code examples and more that if you're on a deadline with a specific brief it would be easier (maybe not "better", but definitely easier) to just write the extra caching hooks around this one custom function in your own module than try to get a feature patch committed to a contrib module (Flippy is in "Maintenance fixes only" mode).
The end resultSo let's have a quick look at what we gain and lose by taking the "DIY" approach using an existing module as an example rather than a framework/turnkey solution.
ProsIn summary, I'm definitely not saying to always "do this" or "do that". I just wanted to show an example of going through a process that highlights an option that I have found new developers often don't realise they have, or they do realise it's something they could do but they overstate the amount of difficulty/effort involved in adapting some existing body of work vs. using it directly. The important thing for us developers is that we're always mindful of what's really in our toolkit and when/how to apply each of our tools to the task at hand.
Syndicate: planet drupaltitantemplatescom posted a photo: