Searching a module
A program accesses an EMu module (or table, the terms are used interchangeably)
using the IMuModule
class. The name of the table to be accessed is passed
to the IMuModule
constructor. For example:
require_once IMu::$lib . '/Module.php'; // ⋯ $parties = new IMuModule('eparties', $session);
This code assumes that a IMuSession
object called session has already
been created. If a IMuSession
object is not passed to the IMuModule
constructor, a session will be created automatically using the defaultHost
and defaultPort
class properties. See Connecting to an IMu server for details.
Once a IMuModule
object has been created, it can be used to search the
specified module and retrieve records.
Any one of the following methods can be used to search for records within a module:
The findKey
method searches for a single record by its key.
For example, the following code searches for a record with a key of 42 in the Parties module:
require_once IMu::$lib . '/Module.php'; // ⋯ $parties = new IMuModule('eparties', $session); $hits = $parties->findKey(42);
The method returns the number of matches found, which is either 1 if the record exists or 0 if it does not.
The findKeys
method searches for a set of key values. The keys are passed
as an array:
$parties = new IMuModule('eparties', $session); $keys = array(52, 42, 17); $hits = $parties->findKeys(keys);
The method returns the number of records found.
The findTerms
method is the most flexible and powerful way to search for
records within a module. It can be used to run simple single term queries or
complex multi-term searches.
The terms are specified using a IMuTerms
object. Once a IMuTerms
object has been created, add specific terms to it (using the add
method)
and then pass the IMuTerms
object to the findTerms
method. For
example, to specify a Parties search for records that contain a first name of John
and a last name
of Smith
:
require_once IMu::$lib . '/Terms.php'; $search = new IMuTerms(); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith'); $hits = $parties->findTerms($search);
There are several points to note:
- The first argument passed to the
add
method element contains the name of the column or an alias in the module to be searched. - An alias associates a supplied value with one or more actual columns.
Aliases are created using the
addSearchAlias
oraddSearchAliases
methods. - The second argument contains the value to search for.
-
Optionally, a comparison operator can be supplied as a third argument (see example here). The operator specifies how the value supplied as the second argument should be matched. Operators are the same as those used in TexQL (See Texpress Query Language Guide for details). If not supplied, the operator defaults to "matches". This is not a real TexQL operator, but is translated by the search engine as the most "natural" operator for the type of column being searched. For example, for text columns "matches" is translated as the
contains
TexQL operator and for integer columns it is translated as the=
TexQL operator.
Note: Unless it is really necessary to specify an operator, consider using
the matches
operator, or better still supplying no operator at
all as this allows the server to determine the best type of search.
Examples
- To search for the name
Smith
in the last name field of the Parties module, the following term can be used:$search = new IMuTerms(); $search->add('NamLast', 'Smith');
- Specifying search terms for other types of columns is straightforward. For
example, to search for records inserted on April 4, 2011:
$search = new IMuTerms(); $search->add('AdmDateInserted', 'Apr 4 2011');
- To search for records inserted before April 4, 2011, it is necessary to
add an operator:
$search = new IMuTerms(); $search->add('AdmDateInserted', 'Apr 4 2011', '<');
- By default, the relationship between the terms is a Boolean
AND
. This means that to find records which match both a first name containingJohn
and a last name containingSmith
theIMuTerms
object can be created as follows:$search = new IMuTerms(); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith');
- A
IMuTerms
object where the relationship between the terms is a BooleanOR
can be created by passing the string value'OR'
to theIMuTerms
constructor:$search = new IMuTerms('OR'); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith');
This specifies a search for records where either the first name contains
John
or the last name containsSmith
. - Combinations of
AND
andOR
search terms can be created. TheaddAnd
method adds a new set ofAND
terms to the originalIMuTerms
object. Similarly, theaddOr
method adds a new set ofOR
terms. For example, to restrict the search for a first name ofJohn
and a last name ofSmith
to matching records inserted before April 4, 2011 or on May 1, 2011, specify:$search = new IMuTerms(); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith'); $dates = $search->addOr(); $dates->add('AdmDateInserted', 'Apr 4 2011', '<'); $dates->add('AdmDateInserted', 'May 1 2011');
- To run a search, pass the
IMuTerms
object to thefindTerms
method:$parties = new IMuModule('eparties', $session); $search = new IMuTerms(); $search->add('NamLast', 'Smith'); $hits = $parties->findTerms($search);
As with other find methods, the return value contains the estimated number of matches.
- To use a search alias, call the
addSearchAlias
method to associate the alias with one or more real column names before callingfindTerms
. Suppose we want to allow a user to search the Catalogue module for keywords. Our definition of a keywords search is to search the SummaryData, CatSubjects_tab and NotNotes columns. We could do this by building anOR
search:$keyword = '⋯'; // ⋯ $search = new IMuTerms('OR'); $search->add('SummaryData', $keyword); $search->add('CatSubjects_tab', $keyword); $search->add('NotNotes', $keyword);
Another way of doing this is to register the association between the name keywords and the three columns we are interested in and then pass the name keywords as the column to be searched:
$keyword = '⋯'; // ⋯ $catalogue = new IMu::Module('ecatalogue', $session); $columns = array ( 'SummaryData', 'CatSubjects_tab', 'NotNotes' ); $catalogue->addSearchAlias('keywords', $columns); // ⋯ $search = new IMuTerms(); $search->add('keywords', $keyword); $catalogue->findTerms($search);
An alternative to passing the columns as an array of strings is to pass a single string, with the column names separated by semi-colons:
$keyword = '⋯'; // ⋯ $catalogue = new IMuModule('ecatalogue', $session); $columns = 'SummaryData;CatSubjects_tab;NotNotes'; $catalogue->addSearchAlias('keywords', $columns); // ⋯ $search = new IMuTerms(); $search->add('keywords', $keyword); $catalogue->findTerms($search);
The advantage of using a search alias is that once the alias is registered a simple name can be used to specify a more complex
OR
search. - To add more than one alias at a time, build an associative array of names
and columns and call the
addSearchAliases
method:$aliases = array ( 'keywords' => 'SummaryData;CatSubjects_tab;NotNotes', 'title' => 'SummaryData;TitMainTitle' ); $module->addSearchAliases($aliases);
With the findWhere
method it is possible to submit a complete TexQL
where clause:
$parties = new IMuModule('eparties', $session); $where = "NamLast contains 'Smith'"; $hits = $parties->findWhere($where);
Although this method provides complete control over exactly how a search is
run, it is generally better to use findTerms
to submit a search rather than
building a where clause. There are (at least) two reasons to prefer
findTerms
over findWhere
:
-
Building the where clause requires the code to have detailed knowledge of the data type and structure of each column. The
findTerms
method leaves this task to the server. For example, specifying the term to search for a particular value in a nested table is straightforward. To find Parties records where the Roles nested table contains Artist,findTerms
simply requires:$search->add('NamRoles_tab', 'Artist');
On the other hand, the equivalent TexQL clause is:
exists(NamRoles_tab where NamRoles contains 'Artist')
The TexQL for double nested tables is even more complex.
-
More importantly,
findTerms
is more secure.With
findTerms
a set of terms is submitted to the server which then builds the TexQL where clause. This makes it much easier for the server to check for terms which may contain SQL-injection style attacks and to avoid them. If your code builds a where clause from user-entered data so it can be run usingfindWhere
, it is much more difficult, if not impossible, for the server to check and avoid SQL-injection. The responsibility for checking for SQL-injection becomes yours.
All of the find methods return the number of matches found by the search. For
findKey
and findKeys
this number is always the exact number of matches
found. The number returned by findTerms
and findWhere
is best thought
of as an estimate. This estimate is almost always correct but because of the
nature of the indexing used by the server's data engine (Texpress) the number
can sometimes be an over-estimate of the real number of matches. This is
similar to the estimated number of hits returned by a Google search.