Skip Navigation

Behind the Scenes

This document was previously part of the entity selector main page, and provides information on the swallowing and merging process that the entity selector uses internally, and some general info on how the entity selector works.

Swallowing and Merging

Occansionally, you may have two queries that you are similar that you want to combine into one query. This can happen if you're trying to develop a complicated query but realize that it's basically a combination of two simpler queries. The entity_selector allows you to do this using two different techniques called swallowing and merging.

I will start with swallowing since it's a bit simpler. The basic idea for swallowing is that we take another entity_selector (or db_selector) and swallow it whole. We take all tables, fields, relations, and types from the original and add them to the current object. Then we take the start, number, and order from the new one (if they exist) and use them to replace the old ones. Thus, our entity_selector will look much like the old one, but will have more things added to it, and may have some of its original data trampled.

The second idea is merging. Merging is a more complex idea, but is much nicer than swallowing since it attempts to modify the data in a more meaningful way. What merging does is takes the second query, checks the tables against the first query, and then attempts to link the two. A brief example may help to clarify.

Say es1 is using tables entity and chunk, is selecting entity.name, and has relation entity.id = chunk.id. Another entity selector es2 is using tables entity and meta, is selecting entity.last_modified and has the relation entity.id = meta.id. Then we want to merge es2 with es1. If we were using the swallowing method, the entity selector would see that entity was already a table and not bother to add a new one. Thus, we would end up with three tables—entity, chunk, and meta—and would have the relations and fields of both. However, if we want to do this using the merge method, it would notice that both entity selectors have the table entity and would rename the second so that there would be no conflict. After the merge, the new entity selector would look something like this:

  • Tables:
    • entity as entity,
    • chunk as chunk,
    • entity as entity2,
    • meta as meta
  • Fields:
    • entity.name,
    • entity2.last_modified
  • Relations:
    • entity.id = chunk.id,
    • entity2.id = meta.id,
    • entity.id = entity2.id

You notice that everywhere entity appeared in the second es has now been replace by an alias, entity2. You will also notice the last relation "entity.id = entity2.id". This relation did you exist in either entity selector before the merge took place. This is a new relation that merge puts in (if possible) to make sure the two separate queries are linked together. If this were not put in, the result set we would see would essentially be the cartesian product of the original two queries. If the entity selector doesn't find an entity table in each es, this last relation will not be put it.

How the entity selector works

The nuts and bolts of the entity selector may seem confusing at first. It is written this way so that it is able to support multiple types at the same time. I will run through the basics of run(), run_one(), and get_one_query() here.

The basics of run are pretty simple. You have two optional parameters. The first is called status, which refers to the state of the entity. By default, it is set to select live entities, but when changed, can select entities of any state. If you want to select all entities regardless of state, pass the variable the value 'All'. The second is an error message, which will show up if the DB query crashes. All this funciton does is set up an array, then loops through the list of types and calls run_one() for each type, putting the results of each one into the array as it goes and then returns the array at the end.

The run_one() function takes three parameters, the first being the type id, and the other two being status and error message as described above. If run_one() doesn't receive a type, it uses type[0]. This function also sets up an array, and then uses the db_query() and get_one_query() functions. It loops through the mysql result set, creating a new entity with each one. Then, for each entity it sets the "private" variable $_values in entity to the results of each row. This is sort of cheating, but it is done for a good reason. It is much easier to just initialize the values of each entity now, while we have them. If we don't do this here, we'll have to do a separate query later for each entity that we've selected, which can significantly slow down the page. This should be the ONLY TIME the values for an entity are every set up outside of the class. After run_one() is done running through the loop, it returns the array containing all the entities.

Finally, the get_one_query() funciton. This is the sort of bizarre part of entity selector. Get one query creates a new entity selector inside of the entity class. It then proceeds to swallow a DBSelector made by the function get_entities_by_type_object(), which is defined in the util.php3 page. After this, it swallows the current entity selector! This assures that we will grab the correct type of entity, and will apply all restrictions to it that have been set up in the current entity selector without changing the current ES at all. After the new ES does its swallowing, it uses the get_query() function which is defined in the DBSelector class to get the new query, and then returns it.