* dblayeroo : add a new dblayer class. More OO, supports more options than dblayer
* fts : The Full Text Search module for dummies git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@3459 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
@@ -6,6 +6,16 @@ spl_autoload_register(function ($class) {
|
|||||||
|
|
||||||
define ("PHPUNIT", "ON-GOING");
|
define ("PHPUNIT", "ON-GOING");
|
||||||
|
|
||||||
|
|
||||||
|
file_put_contents ("Tests/dblayerooSqliteTest.php",
|
||||||
|
str_replace ("{ENGINE}", "sqlite",
|
||||||
|
file_get_contents ("Tests/dblayerooComplet.php")));
|
||||||
|
file_put_contents ("Tests/dblayerooMySQLTest.php",
|
||||||
|
str_replace ("{ENGINE}", "mysql",
|
||||||
|
file_get_contents ("Tests/dblayerooComplet.php")));
|
||||||
|
file_put_contents ("Tests/dblayerooPostgreSQLTest.php",
|
||||||
|
str_replace ("{ENGINE}", "pgsql",
|
||||||
|
file_get_contents ("Tests/dblayerooComplet.php")));
|
||||||
file_put_contents ("Tests/dblayerSqliteTest.php",
|
file_put_contents ("Tests/dblayerSqliteTest.php",
|
||||||
str_replace ("{ENGINE}", "sqlite",
|
str_replace ("{ENGINE}", "sqlite",
|
||||||
file_get_contents ("Tests/dblayerComplet.php")));
|
file_get_contents ("Tests/dblayerComplet.php")));
|
||||||
|
|||||||
363
Tests/dblayerooComplet.php
Normal file
363
Tests/dblayerooComplet.php
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
<?php
|
||||||
|
/** DomFramework - Tests
|
||||||
|
@package domframework
|
||||||
|
@author Dominique Fournier <dominique@fournier38.fr> */
|
||||||
|
|
||||||
|
class test_dblayeroo_{ENGINE} extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
// Test with column name 'group', 'object', 'where', 'with space'
|
||||||
|
// Test with table name 'group', 'object', 'where', 'with space'
|
||||||
|
// For the 3 DB engines
|
||||||
|
|
||||||
|
public $engine="{ENGINE}";
|
||||||
|
public $confs = array (
|
||||||
|
"sqlite" => array (
|
||||||
|
"dsn" => "sqlite:/tmp/databaseDBLayeroo.db",
|
||||||
|
"username" => null,
|
||||||
|
"password" => null,
|
||||||
|
"driver_options" => null,
|
||||||
|
"tableprefix" => "",
|
||||||
|
),
|
||||||
|
"mysql" => array (
|
||||||
|
"dsn" => "mysql:host=127.0.0.1;port=3306;dbname=test",
|
||||||
|
"username" => "root",
|
||||||
|
"password" => "lqsym",
|
||||||
|
"driver_options" => null,
|
||||||
|
"tableprefix" => "",
|
||||||
|
),
|
||||||
|
"pgsql" => array (
|
||||||
|
"dsn" => "pgsql:host=127.0.0.1;port=5432;dbname=dbname",
|
||||||
|
"username" => "root",
|
||||||
|
"password" => "root",
|
||||||
|
"driver_options" => null,
|
||||||
|
"tableprefix" => "",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
private function db1 ()
|
||||||
|
{
|
||||||
|
$dbconfig = $this->confs["{ENGINE}"];
|
||||||
|
$db1 = new dblayeroo ($dbconfig["dsn"], $dbconfig["username"],
|
||||||
|
$dbconfig["password"], $dbconfig["driver_options"]);
|
||||||
|
$db1->table ("groupedoo");
|
||||||
|
$db1->fields (array ("group"=>array ("varchar(255)", "not null"),
|
||||||
|
"object"=>array ("varchar(255)", "not null"),
|
||||||
|
"where"=>array ("varchar(255)", "not null"),
|
||||||
|
"with space"=>array ("varchar(255)")));
|
||||||
|
$db1->unique (array ());
|
||||||
|
$db1->primary ("group");
|
||||||
|
return $db1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function db2 ()
|
||||||
|
{
|
||||||
|
$dbconfig = $this->confs["{ENGINE}"];
|
||||||
|
$db2 = new dblayeroo ($dbconfig["dsn"], $dbconfig["username"],
|
||||||
|
$dbconfig["password"], $dbconfig["driver_options"]);
|
||||||
|
$db2->table ("usersoo");
|
||||||
|
$db2->fields (array ("uid"=>array ("integer", "not null", "autoincrement"),
|
||||||
|
"gecos"=>array ("varchar(255)", "not null"),
|
||||||
|
"password"=>array ("varchar(255)", "not null"),
|
||||||
|
"group" => array ("varchar(255)", "not null"),
|
||||||
|
));
|
||||||
|
$db2->unique (array ("gecos","password"));
|
||||||
|
$db2->primary ("uid");
|
||||||
|
$db2->foreign (array ("group" => array ("groupedoo", "group", "ON DELETE CASCADE")));
|
||||||
|
return $db2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function db3 ()
|
||||||
|
{
|
||||||
|
$dbconfig = $this->confs["{ENGINE}"];
|
||||||
|
$db3 = new dblayeroo ($dbconfig["dsn"], $dbconfig["username"],
|
||||||
|
$dbconfig["password"], $dbconfig["driver_options"]);
|
||||||
|
return $db3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_dropTable ()
|
||||||
|
{
|
||||||
|
$dbconfig = $this->confs["{ENGINE}"];
|
||||||
|
$db = new dblayeroo ($dbconfig["dsn"], $dbconfig["username"],
|
||||||
|
$dbconfig["password"], $dbconfig["driver_options"]);
|
||||||
|
foreach (array ("usersoo", "groupedoo", "multipleoo", "multiple2oo", "users3oo",
|
||||||
|
"readORoo") as
|
||||||
|
$table)
|
||||||
|
{
|
||||||
|
$db->table ($table);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$res = $db->dropTable();
|
||||||
|
}
|
||||||
|
catch (Exception $e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db->disconnect ();
|
||||||
|
// Never generate an error, just drop the table if it exists, and do noting
|
||||||
|
// if it doesn't exists
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_createTable1 ()
|
||||||
|
{
|
||||||
|
// Create a table named groupedoo
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->createTable ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (0, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_createTable2 ()
|
||||||
|
{
|
||||||
|
// Create a table named usersoo
|
||||||
|
$db2 = $this->db2 ();
|
||||||
|
$res = $db2->createTable ();
|
||||||
|
$db2->disconnect ();
|
||||||
|
$this->assertSame (0, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select1 ()
|
||||||
|
{
|
||||||
|
// Select all on the table : nothing
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->select()->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (array (), $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_insert1 ()
|
||||||
|
{
|
||||||
|
// Insert without value : raise an exception
|
||||||
|
$this->setExpectedException ("Exception");
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->insert()->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_insert2 ()
|
||||||
|
{
|
||||||
|
// Insert : missing not null field : exception
|
||||||
|
$this->setExpectedException ("Exception");
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->insert()
|
||||||
|
->setValues(array ("group"=>"group1", "where"=>"where"))
|
||||||
|
->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_insert3 ()
|
||||||
|
{
|
||||||
|
// Insert : first row inserted
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->insert()->setValues(array ("group"=>"group1", "where"=>"where",
|
||||||
|
"object"=>"object"))->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
// As the key is not an autoincrement, the lastInsertID can be 0 or 1
|
||||||
|
$this->assertGreaterThanOrEqual ($res, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select2 ()
|
||||||
|
{
|
||||||
|
// Select all on the table : nothing
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->select()->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (array (array ("group"=>"group1", "object"=>"object",
|
||||||
|
"where"=>"where", "with space"=>null)),
|
||||||
|
$res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update1 ()
|
||||||
|
{
|
||||||
|
// update the all the rows of the table (without WHERE)
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->update()->setValues(array ("group"=>"group2", "where"=>"where",
|
||||||
|
"object"=>"object"))->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (1, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select3 ()
|
||||||
|
{
|
||||||
|
// Select all on the table after update
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->select()->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (array (array ("group"=>"group2", "object"=>"object",
|
||||||
|
"where"=>"where", "with space"=>null)),
|
||||||
|
$res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update2 ()
|
||||||
|
{
|
||||||
|
// update the all the rows of the table (with inexisting WHERE)
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->update()
|
||||||
|
->setValues(array ("group"=>"group2", "where"=>"where",
|
||||||
|
"object"=>"object"))
|
||||||
|
->whereAdd ("group", "=", "group1")
|
||||||
|
->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (0, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update3 ()
|
||||||
|
{
|
||||||
|
// update the all the rows of the table (with existing WHERE)
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->update()
|
||||||
|
->setValues(array ("group"=>"group1", "where"=>"where",
|
||||||
|
"object"=>"object"))
|
||||||
|
->whereAdd ("group", "=", "group2")
|
||||||
|
->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (1, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update4 ()
|
||||||
|
{
|
||||||
|
// update the all the rows of the table : NOT NULL value not provided
|
||||||
|
// (already existing in the table)
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->update()
|
||||||
|
->setValues(array ("group"=>"group1"))
|
||||||
|
->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (1, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete1 ()
|
||||||
|
{
|
||||||
|
// Delete : WHERE return nothing
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->delete ()
|
||||||
|
->whereAdd ("group", "=", "group2")
|
||||||
|
->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (0, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete2 ()
|
||||||
|
{
|
||||||
|
// Delete all
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->delete ()
|
||||||
|
->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (1, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select4 ()
|
||||||
|
{
|
||||||
|
// Select all on the table : nothing
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->select()->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$this->assertSame (array (), $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_insert5 ()
|
||||||
|
{
|
||||||
|
// Insert : first row inserted for TABLE 2 tests
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$res = $db1->insert()->setValues(array ("group"=>"group1", "where"=>"where",
|
||||||
|
"object"=>"object"))->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
// As the key is not an autoincrement, the lastInsertID can be 0 or 1
|
||||||
|
$this->assertGreaterThanOrEqual ($res, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
/// TABLE 2 ///
|
||||||
|
///////////////////
|
||||||
|
public function test_insertAutoincrement1 ()
|
||||||
|
{
|
||||||
|
// Test autoincrement
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$db2 = $this->db2 ();
|
||||||
|
$db2->setForeignObj ($db1);
|
||||||
|
$res = $db2->insert()->setValues(array ("gecos"=>"name",
|
||||||
|
"password"=>"toto",
|
||||||
|
"group"=>"group1"))->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$db2->disconnect ();
|
||||||
|
$this->assertSame ("1", $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_insertAutoincrement2 ()
|
||||||
|
{
|
||||||
|
// Test autoincrement
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$db2 = $this->db2 ();
|
||||||
|
$db2->setForeignObj ($db1);
|
||||||
|
$res = $db2->insert()->setValues(array ("gecos"=>"firstname2",
|
||||||
|
"password"=>"toto2",
|
||||||
|
"group"=>"group1"))->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$db2->disconnect ();
|
||||||
|
$this->assertSame ("2", $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_insertAutoincrement3 ()
|
||||||
|
{
|
||||||
|
// Test autoincrement
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$db2 = $this->db2 ();
|
||||||
|
$db2->setForeignObj ($db1);
|
||||||
|
$res = $db2->insert()->setValues(array ("gecos"=>"firstname3",
|
||||||
|
"password"=>"toto3",
|
||||||
|
"group"=>"group1"))->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$db2->disconnect ();
|
||||||
|
$this->assertSame ("3", $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_delete3 ()
|
||||||
|
{
|
||||||
|
// Delete with WHERE clause
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$db2 = $this->db2 ();
|
||||||
|
$db2->setForeignObj ($db1);
|
||||||
|
$res = $db2->delete ()
|
||||||
|
->whereAdd ("gecos", "LIKE", "firstname%")
|
||||||
|
->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$db2->disconnect ();
|
||||||
|
$this->assertSame (2, $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_select5 ()
|
||||||
|
{
|
||||||
|
// Select all on the table : one entry "gecos"=>"name"
|
||||||
|
$db1 = $this->db1 ();
|
||||||
|
$db2 = $this->db2 ();
|
||||||
|
$db2->setForeignObj ($db1);
|
||||||
|
$res = $db2->select()->execute ();
|
||||||
|
$db1->disconnect ();
|
||||||
|
$db2->disconnect ();
|
||||||
|
$this->assertSame (array (array ("uid"=>1,
|
||||||
|
"gecos"=>"name",
|
||||||
|
"password"=>"toto",
|
||||||
|
"group"=>"group1")), $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SCHEMA MANAGEMENT ///
|
||||||
|
public function test_getTableSchema1 ()
|
||||||
|
{
|
||||||
|
$db3 = $this->db3 ();
|
||||||
|
$res = $db3->getTableSchema ("usersoo");
|
||||||
|
$db3->disconnect ();
|
||||||
|
$this->assertSame (
|
||||||
|
array ("fields"=>array (
|
||||||
|
"uid"=>array ("integer", "not null", "autoincrement"),
|
||||||
|
"gecos"=>array ("varchar(255)", "not null"),
|
||||||
|
"password"=>array ("varchar(255)", "not null"),
|
||||||
|
"group" => array ("varchar(255)", "not null"),
|
||||||
|
),
|
||||||
|
"primary"=>"uid",
|
||||||
|
"unique"=>array ("gecos","password"),
|
||||||
|
"foreign" => array (
|
||||||
|
"group" => array ('groupedoo', 'group', 'ON DELETE CASCADE'),
|
||||||
|
),
|
||||||
|
), $res);
|
||||||
|
}
|
||||||
|
}
|
||||||
174
Tests/ftsTest.php
Normal file
174
Tests/ftsTest.php
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once ("fts.php");
|
||||||
|
|
||||||
|
/** Test the FTS */
|
||||||
|
class test_fts extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function test_tokenizerSearch0 ()
|
||||||
|
{
|
||||||
|
// Empty
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array (),
|
||||||
|
"minuses"=>array ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSearch1 ()
|
||||||
|
{
|
||||||
|
// Too small
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("X");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array (),
|
||||||
|
"minuses"=>array ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSearch2 ()
|
||||||
|
{
|
||||||
|
// One word
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("XYZ");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ"),
|
||||||
|
"minuses"=>array ("")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSearch3 ()
|
||||||
|
{
|
||||||
|
// Two word
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("XYZ 123");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ", "123"),
|
||||||
|
"minuses"=>array ("", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSearch4 ()
|
||||||
|
{
|
||||||
|
// Three word
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("XYZ 123 ABC");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ", "123", "ABC"),
|
||||||
|
"minuses"=>array ("", "", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSearch5 ()
|
||||||
|
{
|
||||||
|
// Three word
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("XYZ 123 ABC KLM");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ", "123",
|
||||||
|
"ABC", "KLM"),
|
||||||
|
"minuses"=>array ("", "", "", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSearch6 ()
|
||||||
|
{
|
||||||
|
// Three word
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("Louis-XYZ 123 -AéBCé KLM");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("Louis-XYZ", "123",
|
||||||
|
"AéBCé", "KLM"),
|
||||||
|
"minuses"=>array ("", "", "-", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function test_tokenizerSentence0 ()
|
||||||
|
{
|
||||||
|
// Empty sentence
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("\"\"");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array (),
|
||||||
|
"minuses"=>array ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSentence1 ()
|
||||||
|
{
|
||||||
|
// One sentence only
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("\"XYZ 123\"");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ 123"),
|
||||||
|
"minuses"=>array ("")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSentence2 ()
|
||||||
|
{
|
||||||
|
// Two sentence
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("\"XYZ 123\" \"ABC KLM\"");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ 123", "ABC KLM"),
|
||||||
|
"minuses"=>array ("", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerSentence3 ()
|
||||||
|
{
|
||||||
|
// Three sentence
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("\"XYZ 123\" -\"ABC KLM\" \"RPO YUI\"");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ 123", "ABC KLM",
|
||||||
|
"RPO YUI"),
|
||||||
|
"minuses"=>array ("", "-", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerMixed1 ()
|
||||||
|
{
|
||||||
|
// One word and one sentence, starting by word
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("XYZ \"ABC KLM\"");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("XYZ", "ABC KLM"),
|
||||||
|
"minuses"=>array ("", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerMixed2 ()
|
||||||
|
{
|
||||||
|
// One word and one sentence, starting by sentence
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("\"ABC KLM\" XYZ");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("ABC KLM", "XYZ"),
|
||||||
|
"minuses"=>array ("", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerMixed3 ()
|
||||||
|
{
|
||||||
|
// One word and two sentences, starting by sentence
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("\"ABC KLM\" XYZ \"RPO YUI\"");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("ABC KLM", "XYZ",
|
||||||
|
"RPO YUI"),
|
||||||
|
"minuses"=>array ("", "", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerMixed4 ()
|
||||||
|
{
|
||||||
|
// Two words and two sentences, starting by sentence
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("\"ABC KLM\" XYZ \"RPO YUI\" 123");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("ABC KLM", "XYZ",
|
||||||
|
"RPO YUI", "123"),
|
||||||
|
"minuses"=>array ("", "", "", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_tokenizerMixed5 ()
|
||||||
|
{
|
||||||
|
// Two words and two sentences, starting by a word
|
||||||
|
$fts = new fts ();
|
||||||
|
$fts->search ("123 \"ABC KLM\" XYZ \"RPO YUI\"");
|
||||||
|
$res = $fts->getTokensMin ();
|
||||||
|
$this->assertSame ($res, array ("tokens"=>array ("123", "ABC KLM",
|
||||||
|
"XYZ", "RPO YUI"),
|
||||||
|
"minuses"=>array ("", "", "", "")));
|
||||||
|
}
|
||||||
|
}
|
||||||
2107
dblayeroo.php
Normal file
2107
dblayeroo.php
Normal file
File diff suppressed because it is too large
Load Diff
222
fts.php
Normal file
222
fts.php
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
<?php
|
||||||
|
/** DomFramework
|
||||||
|
* @package domframework
|
||||||
|
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** The Full Text Search
|
||||||
|
* Analyze the provided search text (like a search engine), and create the
|
||||||
|
* sql query to found the answer.
|
||||||
|
* Manage the sentences (enclosed in quotes), or the standalone words,
|
||||||
|
* Manage the non wanted field (beginning by -),
|
||||||
|
* Do not search if the word is smaller than a parameter.
|
||||||
|
*/
|
||||||
|
class fts
|
||||||
|
{
|
||||||
|
/** The minimum length of a token to search
|
||||||
|
*/
|
||||||
|
public $minLength = 3;
|
||||||
|
|
||||||
|
/** The tokens found in the query, with the minus state if the user do not
|
||||||
|
* want the provided token
|
||||||
|
*/
|
||||||
|
private $tokens = null;
|
||||||
|
|
||||||
|
/** The tokens without the too small tokens
|
||||||
|
*/
|
||||||
|
private $tokensMin =null;
|
||||||
|
|
||||||
|
/** The regexes created by the parser
|
||||||
|
*/
|
||||||
|
private $regexes = null;
|
||||||
|
|
||||||
|
/** Get the tokens store after the search
|
||||||
|
*/
|
||||||
|
public function getTokens ()
|
||||||
|
{
|
||||||
|
return $this->tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the tokens store after the search, without the too small ones
|
||||||
|
*/
|
||||||
|
public function getTokensMin ()
|
||||||
|
{
|
||||||
|
return $this->tokensMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the regexes defined after the analyzer
|
||||||
|
*/
|
||||||
|
public function getRegexes ()
|
||||||
|
{
|
||||||
|
return $this->regexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search the text provided in $query in the database
|
||||||
|
* @param string $query The text to found in the database
|
||||||
|
* @return array The operator and the associated regex value to search
|
||||||
|
*/
|
||||||
|
public function search ($query)
|
||||||
|
{
|
||||||
|
$query = trim ($query);
|
||||||
|
$this->tokens = $this->tokenizer ($query);
|
||||||
|
$this->tokensMin = $this->tokenMinLength ($this->tokens["tokens"],
|
||||||
|
$this->tokens["minuses"]);
|
||||||
|
$this->regexes = $this->regex ($this->tokensMin["tokens"],
|
||||||
|
$this->tokensMin["minuses"]);
|
||||||
|
return $this->regexes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search in SQL
|
||||||
|
* @param string $query The text to found in the database
|
||||||
|
* @param object $dblayeroo The dblayeroo object to query
|
||||||
|
* @param array|null $fields The fields in $dblayeroo to look for data. If
|
||||||
|
* null, look in all the fields defined in the dblayeroo object
|
||||||
|
* @return array The result of the query
|
||||||
|
*/
|
||||||
|
public function searchSQL ($query, $dblayeroo, $fields)
|
||||||
|
{
|
||||||
|
$regexes = $this->search ($query);
|
||||||
|
// Clone the object to not modify a previously defined query
|
||||||
|
$dbl = clone $dblayeroo;
|
||||||
|
$dbl->clearRequest ();
|
||||||
|
$dbl->select ();
|
||||||
|
if ($fields === null)
|
||||||
|
$fields = array_keys ($dbl->fields ());
|
||||||
|
$i = 0;
|
||||||
|
foreach ($fields as $field)
|
||||||
|
{
|
||||||
|
if (! array_key_exists ($field, $dbl->fields ()))
|
||||||
|
throw new \Exception (sprintf (
|
||||||
|
_("The field '%s' doesn't exists in database"),
|
||||||
|
$field), 500);
|
||||||
|
if ($i > 0)
|
||||||
|
$dbl->whereAddOR ();
|
||||||
|
$dbl->whereAddParenthesisOpen ();
|
||||||
|
$j = 0;
|
||||||
|
foreach ($regexes["operator"] as $key=>$operator)
|
||||||
|
{
|
||||||
|
if ($j > 0)
|
||||||
|
$dbl->whereAddAND ();
|
||||||
|
$dbl->whereAdd ($field, $operator, $regexes["value"][$key]);
|
||||||
|
$j++;
|
||||||
|
}
|
||||||
|
$dbl->whereAddParenthesisClose ();
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
return $dbl->execute ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create the regex associated to the provided tokens and minuses
|
||||||
|
* @param array $tokens The token list
|
||||||
|
* @param array $minuses The minuses list
|
||||||
|
* @return array The operator and the associated regex value to search
|
||||||
|
*/
|
||||||
|
private function regex ($tokens, $minuses)
|
||||||
|
{
|
||||||
|
if (! is_array ($tokens))
|
||||||
|
throw new \Exception ("Invalid tokens provided to fts:tokenMinLength",
|
||||||
|
500);
|
||||||
|
if (! is_array ($minuses))
|
||||||
|
throw new \Exception ("Invalid minuses provided to fts:tokenMinLength",
|
||||||
|
500);
|
||||||
|
$operator = array ();
|
||||||
|
$value = array ();
|
||||||
|
foreach ($tokens as $key=>$token)
|
||||||
|
{
|
||||||
|
if ($minuses[$key] === "-")
|
||||||
|
$operator[$key] = "NOT REGEXP";
|
||||||
|
else
|
||||||
|
$operator[$key] = "REGEXP";
|
||||||
|
$value[$key] = "(^|[<> \(\",.;/:!?])".
|
||||||
|
preg_quote ($token).
|
||||||
|
"([<> \)\",.;/:!?]|$)";
|
||||||
|
}
|
||||||
|
return array ("operator"=>$operator, "value"=>$value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove the tokens with too small length. Remove the not desired minuses
|
||||||
|
* too.
|
||||||
|
* @param array $tokens The token list
|
||||||
|
* @param array $minuses The minuses list
|
||||||
|
* @return array tokens and minuses
|
||||||
|
*/
|
||||||
|
private function tokenMinLength ($tokens, $minuses)
|
||||||
|
{
|
||||||
|
if (! is_array ($tokens))
|
||||||
|
throw new \Exception ("Invalid tokens provided to fts:tokenMinLength",
|
||||||
|
500);
|
||||||
|
if (! is_array ($minuses))
|
||||||
|
throw new \Exception ("Invalid minuses provided to fts:tokenMinLength",
|
||||||
|
500);
|
||||||
|
$newTokens = array ();
|
||||||
|
$newMinuses = array ();
|
||||||
|
foreach ($tokens as $key=>$token)
|
||||||
|
{
|
||||||
|
if (mb_strlen ($token) >= $this->minLength)
|
||||||
|
{
|
||||||
|
$newTokens[] = $token;
|
||||||
|
$newMinuses[] = $minuses[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return array ("tokens"=>$newTokens, "minuses"=>$newMinuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return an array with the $query tokenized
|
||||||
|
* @param string $query The text to tokenize
|
||||||
|
* @return array tokens and minuses
|
||||||
|
*/
|
||||||
|
private function tokenizer ($query)
|
||||||
|
{
|
||||||
|
if (! is_string ($query))
|
||||||
|
throw new \Exception ("Invalid query provided to fts:tokenizer", 500);
|
||||||
|
$debug = false;
|
||||||
|
$tokens = array ();
|
||||||
|
$minuses = array ();
|
||||||
|
// Look for sentences
|
||||||
|
$offset = 0;
|
||||||
|
if ($debug) echo "\n012345678901234567890123456789\n$query\n";
|
||||||
|
while ($offset <= mb_strlen ($query))
|
||||||
|
{
|
||||||
|
if ($debug) echo "OFFSET=$offset\n";
|
||||||
|
if (substr ($query, $offset, 1) === "-")
|
||||||
|
{
|
||||||
|
if ($debug) echo "MINUS\n";
|
||||||
|
$minus = "-";
|
||||||
|
$offset++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
$minus = "";
|
||||||
|
$start = strpos ($query, "\"", $offset);
|
||||||
|
if ($start === $offset)
|
||||||
|
{
|
||||||
|
// Sentence, see if there is a end
|
||||||
|
$end = strpos ($query, "\"", $offset + 1);
|
||||||
|
if ($end !== false)
|
||||||
|
{
|
||||||
|
// Complete sentence (with ending double quote)
|
||||||
|
$nbchars = $end - $offset - 1;
|
||||||
|
if ($debug)
|
||||||
|
echo "COMPLETE SENTENCE (Start ".($offset+1).
|
||||||
|
" with $nbchars chars)\n";
|
||||||
|
$token = substr ($query, $offset + 1, $nbchars);
|
||||||
|
$tokens[] = $token;
|
||||||
|
$minuses[] = $minus;
|
||||||
|
$offset = $end + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Word analysis
|
||||||
|
$end = strpos ($query, " ", $offset);
|
||||||
|
if ($end === false)
|
||||||
|
$end = strlen ($query);
|
||||||
|
$nbchars = $end - $offset;
|
||||||
|
if ($debug) echo "WORD FOUND (Start $offset with $nbchars chars)\n";
|
||||||
|
$token = substr ($query, $offset, $nbchars);
|
||||||
|
$tokens[] = $token;
|
||||||
|
$minuses[] = $minus;
|
||||||
|
$offset = $end + 1;
|
||||||
|
}
|
||||||
|
if ($debug) print_r ($tokens);
|
||||||
|
return array ("tokens"=>$tokens, "minuses"=>$minuses);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user