SQLite Component

Extends the BootPress Database Component to create and update tables and indexes at will, and simplifies FTS full-text searching.

use BootPress\SQLite\Component as Sqlite;

Packagist License MIT HHVM Tested PHP 7 Supported Build Status Code Climate Test Coverage


Extends the BootPress Database Component to easily create and update SQLite database tables and indexes at will. It overrides the underlying PDO wrappers of the Database Component to use the PHP SQLite3 class. The main reason is so that you can free the file from it's cold dead hands when you $db->connection()->close(). The only side effect of that is you can't fetch 'obj' or 'named' rows. Otherwise, we are just adding more functionality here. It also facilitates FTS full-text searching.

public object $fts ;

@var

A BootPress\SQLite\Fts instance.

public bool create ( string $table , mixed $fields [, string $tokenize = 'porter' ] )

Create an SQLite FTS4 virtual table for fulltext searching.

@param $table

The database table name.

@param $fields

An array($field, ...) of names to create, or just a string (eg. 'search') if there is only one field name.

@param $tokenize

Either 'simple', or 'porter' (the default).

@return

Either false if the table has already been created, or true if the table has been created anew.

@example
if ($db->created) {

    $db->fts->create('results', 'search');

    // You can insert, update, and query an FTS table the same as any other.
    if ($stmt = $db->insert('results', array('docid', 'search'))) {
        $db->insert($stmt, array(100, 'Fisherman never die, they just get reel tired.'));
        $db->insert($stmt, array(101, 'If wishes were fishes, we\'d have a fish fry.'));
        $db->insert($stmt, array(102, 'Women want me, fish fear me.'));
        $db->insert($stmt, array(103, 'Good things come to those who bait.'));
        $db->insert($stmt, array(104, 'A reel expert can tackle anything.'));
    }

}

public int count ( string $table , string $search [, string $where ] )

Get the total number of search results.

@param $table

The database table name.

@param $search

The search term(s) to 'MATCH'.

@param $where

An additional string of restrictions you would like to place. If you don't include 'WHERE' we will add it for you. If you are combining tables to deliver results then put your 'INNER JOIN ... WHERE' clause here, and prefix the search $table and fields with 's.' eg. INNER JOIN my_table AS my ON s.docid = my.id WHERE my.field = ...

@return

The total count.

@example
echo $db->fts->count('results', 'fish'); // 2

public array search ( string $table , string $search [, mixed $limit [, string $where [, array $fields [, array $weights ]]]] )

Queries an FTS $table for the relevant $search word(s) found within.

@param $table

The database table name.

@param $search

The search term(s) to 'MATCH'.

@param $limit

If you are not paginating results and only want the top whatever, then this is an integer. Otherwise it is an SQL ' LIMIT offset, length' clause.

@param $where

An additional string of restrictions you would like to place. If you don't include 'WHERE' we will add it for you. If you are combining tables to deliver results then put your 'INNER JOIN ... WHERE' clause here, and prefix the search $table and fields with 's.' eg. INNER JOIN my_table AS my ON s.docid = my.id WHERE my.field = ...

@param $fields

An array('s.field', ...) of additional fields you would like to include in the search results. Remember to specify the table prefixes if needed.

@param $weights

An array of importance that you would like to place on the $table fields searched in whatever order you placed them originally. The default weights are 1 for each field, meaning they are all of equal importance. If you want to make one field more relevant than another, then make this an array($weight, ...) of importance to place on each corresponding $table field. Even if you place an importance of 0 on a field it will still be included among the search results, it will just have a lower rank (possibly 0). All of this assumes you have more than one field in your $table, otherwise this will make no difference whatsoever.

@return

An associative array of results.

@example
var_export($db->fts->search('results', 'fish'));
array(
    array(
        'docid' => 101,
        'snippet' => "If wishes were <b>fishes</b>, we'd have a <b>fish</b> fry.",
        'offsets' => '0 0 15 6 0 0 35 4',
        'rank' => 1.333,
    ),
    array(
        'docid' => 102,
        'snippet' => 'Women want me, <b>fish</b> fear me.',
        'offsets' => '0 0 15 4',
        'rank' => .666,
    ),
);

public array words ( string $table , string $search , mixed $docid )

Get the words that made your $search relevant for $docid.

@param $table

The database table name.

@param $search

The search term(s) to 'MATCH'.

@param $docid

The $table row's docid.

@return

The unique words found which made the $search relevant.

@example
echo implode(', ', $db->fts->words('results', 'fish', 101)); // fishes, fish

public array offset ( array $row , array $fields )

Sorts through the $row['offsets'] integers, and retrieves the words they reference.

@param $row

An associative array of each $fields value, including an 'offsets' key.

@param $fields

An array of field names in the same order as they are found in the database search table.

@return

The words that made this row relevant.

@example
print_r($db->fts->offset(array(
    'search' => "If wishes were fishes, we'd have a fish fry.",
    'offsets' => '0 0 15 6 0 0 35 4',
), array('search'))); // array('fishes', 'fish');
@link
Document Your Code

public bool $created = false ;

@var

Whether or not this is a new database.

public __construct ( [ string $file = null ] )

Connects to an SQLite database $file, and creates one if it doesn't already exist.

@param $file

The SQLite database file location, or just leave it null to create an SQLite database in ':memory:'.

public bool create ( string $table , array $fields [, mixed $index [, array $changes ]] )

Either create an SQLite $table if it has not already been created, or verify that it matches the sqlite_master table index. If something has changed, then the $table will be altered accordingly.

@param $table

The database table name.

@param $fields

An array($name => $type, ...) of fields that define this $table.

@param $index

A string of comma-separated 'field, name, ...'s to index. If you are creating multiple indexes, then make this an array('field', 'name', ... ) of all the indexes you would like to create. If it is a unique index, then make it an array('unique' => 'field, name, ...').

@param $changes

When changing field names, make an array($old => $new, ...) to map the old field name with the new field name, so that all of the data is updated accordingly. You can change the $fields order and type no problem, but if you change field names and don't map them, we'll send the old (missing) field name to the scrapheap, and every new field name will receive it's default value.

@return

Either false if nothing has changed and the $table is exactly as you would like it, or true if the $table has been newly created or updated in any way.

@example
if ($db->created) {

    $db->create('employees', array(
        'id' => 'INTEGER PRIMARY KEY',
        'name' => 'TEXT COLLATE NOCASE',
        'position' => 'TEXT NOT NULL DEFAULT ""',
    ), array('unique'=>'position'));

    // Wait, I just changed my mind
    $db->create('employees', array(
        'id' => 'INTEGER PRIMARY KEY',
        'name' => 'TEXT UNIQUE COLLATE NOCASE',
        'title' => 'TEXT DEFAULT ""',
    ), 'title', array(
        'position' => 'title',
    ));

}

public mixed settings ( [ string $name = null [, mixed $value = null ]] )

Create and retrieve database settings.

@param $name

What you want to either set or return.

@param $value

The setting's value. If you want to remove the setting, then set this explicitly to null.

@return

An array of all the settings (if no parameters are given), or the setting's value (if no value is given).

@example
$db->settings('version', '1.2');

echo $db->settings('version'); // 1.2

public string inOrder ( string $field , array $ids )

Returns the $field . 'IN(' . implode(',', $ids) . ')', in the same order given. This method is patterned after using MySQL's FIELD() function, which unfortunately is unavailable in SQLite.

@param $field

Database column.

@param $ids

Those passed to the IN() clause.

@return

An SQL string to put at the end of your query.

@example
if ($ids = $db->ids('SELECT id FROM employees ORDER BY name ASC')) {
    foreach ($db->all(array(
        'SELECT name, title FROM employees',
        'WHERE '.$db->inOrder('id', $ids),
    )) as $row) {
        list($name, $title) = $row;
    }
}

public recreate ( string $file )

When you overwhelm an SQLite database with overlapping inserts and updates, there's a chance it may become corrupted. If it does, I've been able to recreate it using this method.

@param $file

The NEW SQLite database file location. The one you want to create.

Document Your Code

SQLite Overview

Installation

Add the following to your composer.json file.

{
    "require": {
        "bootpress/sqlite": "^1.0"
    }
}

Example Usage

<?php

use BootPress\SQLite\Component as Sqlite;

$db = new Sqlite; // An in-memory database

if ($db->created) {

    $db->settings('version', '1.0');

    $db->create('employees', array(
        'id' => 'INTEGER PRIMARY KEY',
        'name' => 'TEXT COLLATE NOCASE',
        'position' => 'TEXT NOT NULL DEFAULT ""',
    ), array('unique'=>'position'));

    // Wait, I just changed my mind:
    $db->create('employees', array(
        'id' => 'INTEGER PRIMARY KEY',
        'name' => 'TEXT UNIQUE COLLATE NOCASE',
        'title' => 'TEXT DEFAULT ""',
    ), 'title', array(
        'position' => 'title',
    ));

    $db->fts->create('results', 'search');

    // You can insert, update, and query an FTS table the same as any other.
    if ($stmt = $db->insert('results', array('docid', 'search'))) {
        $db->insert($stmt, array(100, 'Fisherman never die, they just get reel tired.'));
        $db->insert($stmt, array(101, 'If wishes were fishes, we\'d have a fish fry.'));
        $db->insert($stmt, array(102, 'Women want me, fish fear me.'));
        $db->insert($stmt, array(103, 'Good things come to those who bait.'));
        $db->insert($stmt, array(104, 'A reel expert can tackle anything.'));
    }

}

echo $db->settings('version'); // 1.0

echo $db->fts->count('results', 'fish')); // 2

print_r($db->fts->search('results', 'fish'));
/*
array(
    array(
        'docid' => 101,
        'snippet' => "If wishes were <b>fishes</b>, we'd have a <b>fish</b> fry.",
        'offsets' => '0 0 15 6 0 0 35 4',
        'rank' => 1.333,
    ),
    array(
        'docid' => 102,
        'snippet' => 'Women want me, <b>fish</b> fear me.',
        'offsets' => '0 0 15 4',
        'rank' => .666,
    ),
)
*/

echo implode(', ', $db->fts->words('results', 'fish', 101)); // fishes, fish