Drupal 7 db_set_active() in mymodule_init()? - drupal

I am trying to change which DB connection to used based on several conditions inside a custom module hook, aptly named mymodule_init()
hook_init() seemed a logical place to put this functionality because it's called so early in the bootstrap game, before any DB queries???
So I have several connections in a pool and which one is used is determined by the module. For the life of I can't get the system to persist the DB - seems to be resetting itself back to 'default' after this hook is executed. Searching the codebase has little effect as well only one or two calls to db_set_active() are made.
ANy ideas? What hook should I override to change the DB connection at runtime before any DB activity has be done???
Cheers,
Alex

Hardly is hook_init "early in the game" and certainly not the first to fire database queries. The bootstrap order is: load configuration, try to serve the page from cache, initialize the database, load variables, load session, page header. The first hook to fire is hook_boot either if the page cache has a hit or in page header -- by then at least the variable init phase have fired a query either to load the variables from the database (or to retrieve them from cache but you can't rely on cache and the default cache is database anyways). All is not lost, however. You can either put your code right in settings.php or write a small cache handler, something like this:
class HackyDatabaseCache extends DrupalDatabaseCache {
function __construct($bin) {
// your code finding the database here.
parent::__construct($bin);
}
}
add $conf['cache_backends'][] = 'path/to/hackydatabasecache.inc'; and $conf['cache_class_cache_page'] = 'HackyDatabaseCache'; to your settings.php. This will make sure your code fires before any queries. If you are using memcache or mongodb for caching, then extend that with the same code just change which class is extended.

Related

How should I design a multiscreen feature?

I work on a webapp with a workspace, where the user can create, load, and edit documents. This workspace is built with several areas, each taking care of a part of the job. A set of document loaded in a workspace is called a "project" and is stored in a "project" collection.
The data involved in a project is of two types:
the set of documents attached to the project. It is stored in the mongo document in the "project" collection
the current document a specific user is working on. I do not store it yet, I just use a set of global reactive variables to load a document and the attached informations when a user click on it. It means every time a user access to the workspace/project, he will not find the previously loaded documents but no documents loaded at all.
I now want to store the second type of data with one major requirement: to allow the user to work in an "extended mode" where one of the panels is in a dedicated browser window (supposedly on another screen). It means that if he clicks on a document in a window, the document is loaded in the other window/screen.
As far as I know, I can't send information directly from one browser window to another. I have to use the server to relay the information. So the user clicks on a document > the new loaded document id is sent to the server > the other window update accordingly.
Is my assumption correct? (the server must relay the info)
To implement this feature, I figured out a couple of solutions:
I attach a "project" field to the user profile mongo document. In each of these fields, I will have the last items loaded for each project and I will use this field to update one screen from the other.
I create a specific field in each project document where, for each user who worked on the project, I store the currently loaded document and its settings.
The first option suppose to load every project information along with the user profile (i.e. in every page) and could lead to send many times useless informations.
The second option will trigger the meteor reactivity mechanisms each time a user loads an item (without actually modifying the project) for every user connected to the project.
Each option has serious downsides, and I would like to know which one seems to be the better to you and if you can think of other alternatives.
You ought to be able to use one of the reactive local storage packages for Meteor especially if you are not concerned about not supporting non-HTML5 browsers... Can't give a massive amount of guidance on what one having not used most of them but the HTML5 local storage is usable across tabs and seems like a good place to store your data without a round trip to the server whilst also allowing it to persist between tabs.
You could also roll your own implementation (may be simpler than trying to find a package to match your needs exactly) by adding a listener to the app for local storage setitem() and removeItem() events as per this helpful guide from which the below code has been shamelessly copied...
if (window.addEventListener) {
// Normal browsers
window.addEventListener("storage", handler, false);
} else {
// for IE (why make your life more difficult)
window.attachEvent("onstorage", handler);
};
function handler(e) {
console.log('Successfully communicate with other tab');
console.log('Received data: ' + localStorage.getItem('data'));
//Add in your code to display the document on the second tab
}
localStorage.setItem('data', 'hello world');

Storing data in AppState and Session

In my AppStart.cshtml I fetch some data from the database, do calculations, serialize/deserialize json strings and such, etc, and I store the result in a couple AppState-variables by doing something like the following:(C#)
AppState["myVar1"]="aString";
AppState["myVar2"]=anArray;
These variables are accessed frequently and are a bit heavy to define so I thought something like this would make sense rather than creating the data from scratch every time it's needed. Even if the optimization isn't needed it still makes sense to me since it also increases readability and definitely maintainability by not having the same code in a bunch of places where that data is needed.
Likewise, I do similar actions on a per-user basis by putting data in Session whenver a user logs in, e.g.
Session["userVar1"]="myString";
Session["userVar2"]=myAray;
However, I've just read that we should never rely on that the data stored in these still exist when we want to read them because they're stored in the server-memory which might have been cleared.
Is this true?
So when we want to access one of these we should first check whether it's null or not? And if we're lucky it's not null and we can use it straight away, otherwise we set it again.
Is this how data stored in AppState and Session are supposed to be used? And if so, what would be a good way of re-setting them if they're null? I suppose doing something like creating a function which sets them if they're null?
In your case it sounds like it's fine if the data is occasionally cleared by the server (re-starting the app process from IIS, for example) because what you've described is just a caching scenario. Cache data is inherently transient. If it's there, use it. If it's not there, re-fetch it (and populate the cache again with the result).
What I would suggest is abstracting your cache mechanism (app state and session state) from the structure of the cache itself. And within this structure you can check if the data is cached and, if not, re-cache it. Consider an object like this:
public class CacheManager
{
public static string MyString
{
get
{
if (string.IsNullOrWhiteSpace(AppState["myVar1"]))
{
// Fetch the value to be cached and set it in AppState["myVar1"]
}
return AppState["myVar1"];
}
}
}
Now anywhere in your application you can get the value by calling:
CacheManager.MyString
The rest of the application doesn't know or care if it's from app state, or session state, or a database, or a file, or any other transient location for cached data. That's entirely handled by the cache manager object. So if you ever want to change where certain values are located, you change them in that one place. Or if, for testing purposes, you want to remove the cache entirely and always get the data live, you'd just swap out the cache manager implementation with one that always returns re-fetched data. The rest of the application is blissfully unaware of the implementation.

How to rollback any transaction when doing test with phpUnit in symfony2

I'm testing the controllers using the crawler, but when I'm posting a form that doesn't generate any errors, it save the form in the database.
How can I prevent him to do so without changing the controller, and without testing something else.
Is there best practice about this kinds of test ?
I tried the rollback, but in the ControllerTest there is no more active transactions
You need to write your own test client class extending Symfony\Bundle\FrameworkBundle\Client.
It's because default client doesn't share connection object between requests (so you can't use transactions outside test client). If you extend test client you can handle transaction by your own.
In your client class you need make static connection object, and override method doRequest() to avoid creating new connection object every time but use our static one instead.
It's well described here:
http://alexandre-salome.fr/blog/Symfony2-Isolation-Of-Tests
When you have your own doRequest method all you need is handle transaction, so you wrap handle() method with begin and rollback. Your doRequest method could look sth like that:
protected function doRequest($request)
{
// here you need create your static connection object if it's doesn't exist yet
// and put it into service container as 'doctrine.dbal.default_connection'
(...)
self::$connection->beginTransaction();
$response = $this->kernel->handle($request);
self::$connection->rollback();
(...)
return $response
}
You can read the documentation of PHPUnit for database testing
http://www.phpunit.de/manual/3.6/en/database.html
You will need setup your database and teardown the changes you made.
If you think that the above is too complicated maybe you are interested in make a mockup of your database layer
http://www.phpunit.de/manual/3.6/en/test-doubles.html
Mockup is create a custom object based in the original object where put your own test controls. Probably in this case you are interested in mockup the Entity Manager of Doctrine

How do I execute an action in drupal after each time a node is saved?

I'm developing an Action in Drupal which is supposed to activate after saving a node, exporting content to XML (which includes data from the node that was just saved), using the "Trigger: After saving an updated post" trigger.
Unfortunately this action actually happens right before the information from the recently saved post is saved to the database. ie. when looking at the XML later, I find that the most recent change I made was not included. Saving after editing a different node will restore the previously missing data.
How can I get my action to fire after the saving process is complete?
There is a common pitfall in this context, regardless of whether you use a trigger or Mike Munroes suggestion via hook_nodeapi() (+1):
As long as your export logic runs on the same page cycle that processed the update, and it uses node_load() to get the nodes data, node_load()might return a statically cached version of the node from before the update that does not contain the changes yet. If this is the problem in your case, you can work around it in two ways:
Force a reset of the static node cache by passing TRUE as the third parameter to node_load(). This would ensure that the node gets populated freshly from the database (at the price of some additional db queries, so be aware of a potential performance impact).
If you are going the hook_nodeapi() route, you could avoid the need to call node_load() altogether if you pass the $node object available there directly to your export function, as it will be a representation of the updated state.
You should use hook_nodeapi and invoke your action on insert and update. Look over the documenation for hook_nodeapi for other instances where you could call your export logic.
example where module name = 'export_to_xml':
/**
* Implementation of hook_nodeapi().
*/
function export_to_xml_nodeapi(&$node, $op, $a3, $a4) {
if ($op == 'update' || $op == 'insert') {
export_logic_function();
}
}

ASP.NET - Loading controls at one time (on application load)

We are working on an ASP.NET application. It has 3- 4 forms displaying country list dropdown. Here we would like to avoid binding these dropdowns each time by getting data from database. Instead looking for a better practice of binding it one time, say on application load/some other.
Would you please let me know how we could go head on this? Any reference link or document would be great.
Many Thanks,
Regards,
Nani
Place the drop down in a user control and enable output caching on the user control.
This solution cause the rendered HTML to be cached so the databinding won't need to be called on every page request.
Another possibility would be to use some caching mechanism on your BL logic. For instance in your page/usercontrol you could have (don't take my syntax too strict ;) )
public partial class MyPaged: Page
{
public void PageLoad(..)
{
if(!IsPostBack)
{
dropDownCountries.DataSource = CountryBL.GetCountries();
dropDownCountries.DataBind();
}
...
}
}
and in your business logic class you do some kind of caching where you may have a singleton class that holds the countries and functions as your cache. A pseudocode method could be
public IList<Country> GetCountries
{
//if the cache is empty or it should be refreshed, fills the local
//list of countries, i.e. the cache, with fresh entries from the DB
//there could be some time condition, i.e. refresh every day or so
EnsureCacheValid();
return CachedCountries; //the cache of countries
}
This could be another option with the advantage that your presentation logic doesn't even know about the caching and if you would add a webservice access or so, you would also benefit from the caching. The only thing you have to pay attention at is if there is the possibility that the user can change the countries (which in your example I don't suppose).

Resources