Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
Hygiene release: update README.
+7
View File
@@ -0,0 +1,7 @@
# Contributing
We are happy to review any contributions you want to make. When contributing, please follow the rules outlined at <http://auraphp.com/contributing>.
The time between submitting a contribution and its review one may be extensive; do not be discouraged if there is not immediate feedback.
Thanks!
+23
View File
@@ -0,0 +1,23 @@
Copyright (c) 2011-2016, Aura for PHP
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+613
View File
@@ -0,0 +1,613 @@
# Aura.SqlQuery
Provides query builders for MySQL, Postgres, SQLite, and Microsoft SQL Server.
These builders are independent of any particular database connection library,
although [PDO](http://php.net/PDO) in general is recommended.
## Foreword
### Installation
This library requires PHP 5.3.9 or later; we recommend using the latest available version of PHP as a matter of principle. It has no userland dependencies.
It is installable and autoloadable via Composer as [aura/sqlquery](https://packagist.org/packages/aura/sqlquery).
Alternatively, [download a release](https://github.com/auraphp/Aura.SqlQuery/releases) or clone this repository, then require or include its _autoload.php_ file.
### Quality
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/auraphp/Aura.SqlQuery/badges/quality-score.png?b=2.x)](https://scrutinizer-ci.com/g/auraphp/Aura.SqlQuery/?branch=2.x)
[![Code Coverage](https://scrutinizer-ci.com/g/auraphp/Aura.SqlQuery/badges/coverage.png?b=2.x)](https://scrutinizer-ci.com/g/auraphp/Aura.SqlQuery/?branch=2.x)
[![Build Status](https://travis-ci.org/auraphp/Aura.SqlQuery.png?branch=2.x)](https://travis-ci.org/auraphp/Aura.SqlQuery)
To run the unit tests at the command line, issue `phpunit` at the package root. (This requires [PHPUnit][] to be available as `phpunit`.)
[PHPUnit]: http://phpunit.de/manual/
This library attempts to comply with [PSR-1][], [PSR-2][], and [PSR-4][]. If
you notice compliance oversights, please send a patch via pull request.
[PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md
[PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
[PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md
### Community
To ask questions, provide feedback, or otherwise communicate with the Aura community, please join our [Google Group](http://groups.google.com/group/auraphp), follow [@auraphp on Twitter](http://twitter.com/auraphp), or chat with us on #auraphp on Freenode.
## Getting Started
First, instantiate a _QueryFactory_ with a database type:
```php
<?php
use Aura\SqlQuery\QueryFactory;
$query_factory = new QueryFactory('sqlite');
?>
```
You can then use the factory to create query objects:
```php
<?php
$select = $query_factory->newSelect();
$insert = $query_factory->newInsert();
$update = $query_factory->newUpdate();
$delete = $query_factory->newDelete();
?>
```
The query objects do not execute queries against a database. When you are done
building the query, you will need to pass it to a database connection of your
choice. In the examples below, we will use [PDO](http://php.net/pdo) for the
database connection, but any database library that uses named placeholders and
bound values should work just as well (e.g. the [Aura.Sql][] _ExtendedPdo_
class).
[Aura.Sql]: https://github.com/auraphp/Aura.Sql/tree/develop-2
## Identifier Quoting
In most cases, the query objects will quote identifiers for you. For example,
under the common _Select_ object with double-quotes for identifiers:
```php
<?php
$select->cols(array('foo', 'bar AS barbar'))
->from('table1')
->from('table2')
->where('table2.zim = 99');
echo $select->getStatement();
// SELECT
// "foo",
// "bar" AS "barbar"
// FROM
// "table1",
// "table2"
// WHERE
// "table2"."zim" = 99
?>
```
If you discover that a partially-qualified identifier has not been auto-quoted
for you, change it to a fully-qualified identifer (e.g., from `col_name` to
`table_name.col_name`).
## Common Query Objects
Although you must specify a database type when instantiating a _QueryFactory_,
you can tell the factory to return "common" query objects instead of database-
specific ones. This will make only the common query methods available, which
helps with writing database-portable applications. To do so, pass the constant
`QueryFactory::COMMON` as the second constructor parameter.
```php
<?php
use Aura\SqlQuery\QueryFactory;
// return Common, not SQLite-specific, query objects
$query_factory = new QueryFactory('sqlite', QueryFactory::COMMON);
?>
```
> N.b. You still need to pass a database type so that identifiers can be
> quoted appropriately.
All query objects implement the "Common" methods.
### SELECT
#### Building A Query
Build a _Select_ query using the following methods. They do not need to
be called in any particular order, and may be called multiple times.
```php
<?php
$select = $query_factory->newSelect();
$select
->distinct() // SELECT DISTINCT
->cols(array( // select these columns
'id', // column name
'name AS namecol', // one way of aliasing
'col_name' => 'col_alias', // another way of aliasing
'COUNT(foo) AS foo_count' // embed calculations directly
))
->from('foo AS f') // FROM these tables
->fromSubSelect( // FROM sub-select AS my_sub
'SELECT ...',
'my_sub'
)
->join( // JOIN ...
'LEFT', // left/inner/natural/etc
'doom AS d', // this table name
'foo.id = d.foo_id' // ON these conditions
)
->joinSubSelect( // JOIN to a sub-select
'INNER', // left/inner/natural/etc
'SELECT ...', // the subselect to join on
'subjoin', // AS this name
'sub.id = foo.id' // ON these conditions
)
->where('bar > :bar') // AND WHERE these conditions
->where('zim = ?', 'zim_val') // bind 'zim_val' to the ? placeholder
->orWhere('baz < :baz') // OR WHERE these conditions
->groupBy(array('dib')) // GROUP BY these columns
->having('foo = :foo') // AND HAVING these conditions
->having('bar > ?', 'bar_val') // bind 'bar_val' to the ? placeholder
->orHaving('baz < :baz') // OR HAVING these conditions
->orderBy(array('baz')) // ORDER BY these columns
->limit(10) // LIMIT 10
->offset(40) // OFFSET 40
->forUpdate() // FOR UPDATE
->union() // UNION with a followup SELECT
->unionAll() // UNION ALL with a followup SELECT
->bindValue('foo', 'foo_val') // bind one value to a placeholder
->bindValues(array( // bind these values to named placeholders
'bar' => 'bar_val',
'baz' => 'baz_val',
));
?>
```
> N.b.: The `*where()` and `*having()` methods take an arbitrary number of
trailing arguments, each of which is a value to bind to a sequential question-
mark placeholder in the condition clause.
>
> Similarly, the `*join*()` methods take an optional final argument, a
sequential array of values to bind to sequential question-mark placeholders in
the condition clause.
#### Resetting Query Elements
The _Select_ class comes with the following methods to "reset" various clauses
a blank state. This can be useful when reusing the same query in different
variations (e.g., to re-issue a query to get a `COUNT(*)` without a `LIMIT`, to
find the total number of rows to be paginated over).
- `resetCols()` removes all columns
- `resetTable()` removes all `FROM` and `JOIN` clauses
- `resetWhere()`, `resetGroupBy()`, `resetHaving()`, and `resetOrderBy()`
remove the respective clauses
- `resetUnions()` removes all `UNION` and `UNION ALL` clauses
- `resetFlags()` removes all database-engine-specific flags
- `resetBindValues()` removes all values bound to named placeholders
#### Issuing The Query
Once you have built the query, pass it to the database connection of your
choice as a string, and send the bound values along with it.
```php
<?php
// a PDO connection
$pdo = new PDO(...);
// prepare the statment
$sth = $pdo->prepare($select->getStatement());
// bind the values and execute
$sth->execute($select->getBindValues());
// get the results back as an associative array
$result = $sth->fetch(PDO::FETCH_ASSOC);
?>
```
### INSERT
#### Single-Row Insert
Build an _Insert_ query using the following methods. They do not need to
be called in any particular order, and may be called multiple times.
```php
<?php
$insert = $query_factory->newInsert();
$insert
->into('foo') // INTO this table
->cols(array( // bind values as "(col) VALUES (:col)"
'bar',
'baz',
))
->set('ts', 'NOW()') // raw value as "(ts) VALUES (NOW())"
->bindValue('foo', 'foo_val') // bind one value to a placeholder
->bindValues(array( // bind these values
'bar' => 'foo',
'baz' => 'zim',
));
?>
```
The `cols()` method allows you to pass an array of key-value pairs where the
key is the column name and the value is a bind value (not a raw value):
```php
<?php
$insert = $query_factory->newInsert();
$insert->into('foo') // insert into this table
->cols(array( // insert these columns and bind these values
'foo' => 'foo_value',
'bar' => 'bar_value',
'baz' => 'baz_value',
));
?>
```
Once you have built the query, pass it to the database connection of your
choice as a string, and send the bound values along with it.
```php
<?php
// the PDO connection
$pdo = new PDO(...);
// prepare the statement
$sth = $pdo->prepare($insert->getStatement());
// execute with bound values
$sth->execute($insert->getBindValues());
// get the last insert ID
$name = $insert->getLastInsertIdName('id');
$id = $pdo->lastInsertId($name);
?>
```
#### Multiple-Row (Bulk) Insert
If you want to do a multiple-row or bulk insert, call the `addRow()` method
after finishing the first row, then build the next row you want to insert. The
columns in the rows after the first will be inserted in the same order as the
first row.
```php
<?php
$insert = $query_factory->newInsert();
// insert into this table
$insert->into('foo');
// set up the first row
$insert->cols(array(
'bar' => 'bar-0',
'baz' => 'baz-0'
));
$insert->set('ts', 'NOW()');
// set up the second row. the columns here are in a different order
// than in the first row, but it doesn't matter; the INSERT object
// keeps track and builds them the same order as the first row.
$insert->addRow();
$insert->set('ts', 'NOW()');
$insert->cols(array(
'bar' => 'bar-1',
'baz' => 'baz-1'
));
// set up further rows ...
$insert->addRow();
// ...
// execute a bulk insert of all rows
$pdo = new PDO(...);
$sth = $pdo->prepare($insert->getStatement());
$sth->execute($insert->getBindValues());
?>
```
> N.b.: If you add a row and do not specify a value for a column that was
> present in the first row, the _Insert_ will throw an exception.
If you pass an array of column key-value pairs to `addRow()`, they will be
bound to the next row, thus allowing you to skip setting up the first row
manually with `col()` and `cols()`:
```php
<?php
// set up the first row
$insert->addRow(array(
'bar' => 'bar-0',
'baz' => 'baz-0'
));
$insert->set('ts', 'NOW()');
// set up the second row
$insert->addRow(array(
'bar' => 'bar-1',
'baz' => 'baz-1'
));
$insert->set('ts', 'NOW()');
// etc.
?>
```
If you only need to use bound values, and do not need to set raw values, and
have the entire data set as an array already, you can use `addRows()` to add
them all at once:
```php
<?php
$rows = array(
array(
'bar' => 'bar-0',
'baz' => 'baz-0'
),
array(
'bar' => 'bar-1',
'baz' => 'baz-1'
),
);
$insert->addRows($rows);
?>
```
> N.b.: SQLite 3.7.10 and earlier do not support the "standard" multiple-row
> insert syntax. Thus, bulk inserts with _Insert_ object will not work on those
> earlier versions of SQLite. We suggest wrapping multuple INSERT operations
> with a transaction as an alternative.
### UPDATE
Build an _Update_ query using the following methods. They do not need to
be called in any particular order, and may be called multiple times.
```php
<?php
$update = $query_factory->newUpdate();
$update
->table('foo') // update this table
->cols(array( // bind values as "SET bar = :bar"
'bar',
'baz',
))
->set('ts', 'NOW()') // raw value as "(ts) VALUES (NOW())"
->where('zim = :zim') // AND WHERE these conditions
->where('gir = ?', 'doom') // bind this value to the condition
->orWhere('gir = :gir') // OR WHERE these conditions
->bindValue('bar', 'bar_val') // bind one value to a placeholder
->bindValues(array( // bind these values to the query
'baz' => 99,
'zim' => 'dib',
'gir' => 'doom',
));
?>
```
The `cols()` method allows you to pass an array of key-value pairs where the
key is the column name and the value is a bind value (not a raw value):
```php
<?php
$update = $query_factory->newUpdate();
$update->table('foo') // update this table
->cols(array( // update these columns and bind these values
'foo' => 'foo_value',
'bar' => 'bar_value',
'baz' => 'baz_value',
));
?>
```
Once you have built the query, pass it to the database connection of your
choice as a string, and send the bound values along with it.
```php
<?php
// the PDO connection
$pdo = new PDO(...);
// prepare the statement
$sth = $pdo->prepare($update->getStatement())
// execute with bound values
$sth->execute($update->getBindValues());
?>
```
### DELETE
Build a _Delete_ query using the following methods. They do not need to
be called in any particular order, and may be called multiple times.
```php
<?php
$delete = $query_factory->newDelete();
$delete
->from('foo') // FROM this table
->where('zim = :zim') // AND WHERE these conditions
->where('gir = ?', 'doom') // bind this value to the condition
->orWhere('gir = :gir') // OR WHERE these conditions
->bindValue('bar', 'bar_val') // bind one value to a placeholder
->bindValues(array( // bind these values to the query
'baz' => 99,
'zim' => 'dib',
'gir' => 'doom',
));
?>
```
Once you have built the query, pass it to the database connection of your
choice as a string, and send the bound values along with it.
```php
<?php
// the PDO connection
$pdo = new PDO(...);
// prepare the statement
$sth = $pdo->prepare($delete->getStatement())
// execute with bound values
$sth->execute($delete->getBindValues());
?>
```
## MySQL Query Objects ('mysql')
These 'mysql' query objects have additional MySQL-specific methods:
- SELECT
- `calcFoundRows()` to add or remove `SQL_CALC_FOUND_ROWS` flag
- `cache()` to add or remove `SQL_CACHE` flag
- `noCache()` to add or remove `SQL_NO_CACHE` flag
- `bigResult()` to add or remove `SQL_BIG_RESULT` flag
- `smallResult()` to add or remove `SQL_SMALL_RESULT` flag
- `bufferResult()` to add or remove `SQL_BUFFER_RESULT` flag
- `highPriority()` to add or remove `HIGH_PRIORITY` flag
- `straightJoin()` to add or remove `STRAIGHT_JOIN` flag
- INSERT
- `highPriority()` to add or remove `HIGH_PRIORITY` flag
- `lowPriority()` to add or remove `LOW_PRIORITY` flag
- `ignore()` to add or remove `IGNORE` flag
- `delayed()` to add or remove `DELAYED` flag
- UPDATE
- `lowPriority()` to add or remove `LOW_PRIORITY` flag
- `ignore()` to add or remove `IGNORE` flag
- `where()` and `orWhere()` to add WHERE conditions flag
- `orderBy()` to add an ORDER BY clause flag
- `limit()` to set a LIMIT count
- DELETE
- `lowPriority()` to add or remove `LOW_PRIORITY` flag
- `ignore()` to add or remove `IGNORE` flag
- `quick()` to add or remove `QUICK` flag
- `orderBy()` to add an ORDER BY clause
- `limit()` to set a LIMIT count
In addition, the _Insert_ object has support for `ON DUPLICATE KEY UPDATE`:
- `onDuplicateKeyUpdate($col, $raw_value)` sets a raw value
- `onDuplicateKeyUpateCol($col, $value)` is a `col()` equivalent for the update
- `onDuplicateKeyUpdateCols($cols)` is a `cols()`equivalent for the update
Placeholders for bound values in the `ON DUPLICATE KEY UPDATE` portions will be
automatically suffixed with `__on_duplicate key` to deconflict them from the
insert placeholders.
## PostgreSQL Query Objects ('pgsql')
These 'pgsql' query objects have additional PostgreSQL-specific methods:
- INSERT
- `returning()` to add a `RETURNING` clause
- UPDATE
- `returning()` to add a `RETURNING` clause
- DELETE
- `returning()` to add a `RETURNING` clause
### Last Insert ID Names in PostgreSQL
PostgreSQL determines the default sequence name for the last inserted ID by concatenating the table name, the column name, and a `seq` suffix, using underscore separators (e.g. `table_col_seq`).
However, when inserting into an extended or inherited table, the parent table is used for the sequence name, not the child (insertion) table. This package allows you to override the default last-insert-id name with the method `setLastInsertIdNames()` on both _QueryFactory_ and the _Insert_ object itself. Pass an array of `inserttable.col` keys mapped to `parenttable_col_seq` values, and the _Insert_ object will use the mapped sequence names instead of the default names.
```php
<?php
$query_factory->setLastInsertIdNames(array(
'child.id' => 'parent_id_seq'
));
$insert = $query_factory->newInsert();
$insert->into('child');
// ...
$seq = $insert->getLastInsertIdName('id');
?>
```
The `$seq` name is now `parent_id_seq`, not `child_id_seq` as it would have been by default.
## SQLite Query Objects ('sqlite')
These 'sqlite' query objects have additional SQLite-specific methods:
- INSERT
- `orAbort()` to add or remove an `OR ABORT` flag
- `orFail()` to add or remove an `OR FAIL` flag
- `orIgnore()` to add or remove an `OR IGNORE` flag
- `orReplace()` to add or remove an `OR REPLACE` flag
- `orRollback()` to add or remove an `OR ROLLBACK` flag
- UPDATE
- `orAbort()` to add or remove an `OR ABORT` flag
- `orFail()` to add or remove an `OR FAIL` flag
- `orIgnore()` to add or remove an `OR IGNORE` flag
- `orReplace()` to add or remove an `OR REPLACE` flag
- `orRollback()` to add or remove an `OR ROLLBACK` flag
- `orderBy()` to add an ORDER BY clause
- `limit()` to set a LIMIT count
- `offset()` to set an OFFSET count
- DELETE
- `orAbort()` to add or remove an `OR ABORT` flag
- `orFail()` to add or remove an `OR FAIL` flag
- `orIgnore()` to add or remove an `OR IGNORE` flag
- `orReplace()` to add or remove an `OR REPLACE` flag
- `orRollback()` to add or remove an `OR ROLLBACK` flag
- `orderBy()` to add an ORDER BY clause
- `limit()` to set a LIMIT count
- `offset()` to set an OFFSET count
## Microsoft SQL Query Objects ('sqlsrv')
The 'sqlsrv' query objects have no additional methods specific to Microsoft SQL Server.
In general, `limit()` and `offset()` with Microsoft SQL Server are best
combined with `orderBy()`. The `limit()` and `offset()` methods on the
Microsoft SQL Server query objects will generate sqlsrv-specific variations of
`LIMIT ... OFFSET`:
- If only a `LIMIT` is present, it will be translated as a `TOP` clause.
- If both `LIMIT` and `OFFSET` are present, it will be translated as an
`OFFSET ... ROWS FETCH NEXT ... ROWS ONLY` clause. In this case there *must*
be an `ORDER BY` clause, as the limiting clause is a sub-clause of `ORDER
BY`.
## Table Prefixes
One frequently-requested feature for this package is support for "automatic
table prefixes" on all queries. This feature sounds great in theory, but in
practice is it (1) difficult to implement well, and (2) even when implemented it
turns out to be not as great as it seems in theory. This assessment is the
result of the hard trials of experience. For those of you who want modifiable
table prefixes, we suggest using constants with your table names prefixed as
desired; as the prefixes change, you can then change your constants.
+41
View File
@@ -0,0 +1,41 @@
<?php
spl_autoload_register(function ($class) {
// the package namespace
$ns = 'Aura\SqlQuery';
// what prefixes should be recognized?
$prefixes = array(
"{$ns}\\" => array(
__DIR__ . '/src',
__DIR__ . '/tests',
),
);
// go through the prefixes
foreach ($prefixes as $prefix => $dirs) {
// does the requested class match the namespace prefix?
$prefix_len = strlen($prefix);
if (substr($class, 0, $prefix_len) !== $prefix) {
continue;
}
// strip the prefix off the class
$class = substr($class, $prefix_len);
// a partial filename
$part = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
// go through the directories to find classes
foreach ($dirs as $dir) {
$dir = str_replace('/', DIRECTORY_SEPARATOR, $dir);
$file = $dir . DIRECTORY_SEPARATOR . $part;
if (is_readable($file)) {
require $file;
return;
}
}
}
});
+3
View File
@@ -0,0 +1,3 @@
<?php
error_reporting(E_ALL);
require __DIR__ . '/autoload.php';
+12
View File
@@ -0,0 +1,12 @@
<phpunit bootstrap="./phpunit.php">
<testsuites>
<testsuite>
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>
+159
View File
@@ -0,0 +1,159 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery;
/**
*
* Abstract query object for data manipulation (Insert, Update, and Delete).
*
* @package Aura.SqlQuery
*
*/
abstract class AbstractDmlQuery extends AbstractQuery
{
/**
*
* Column values for INSERT or UPDATE queries; the key is the column name and the
* value is the column value.
*
* @param array
*
*/
protected $col_values;
/**
*
* The columns to be returned.
*
* @var array
*
*/
protected $returning = array();
/**
*
* Does the query have any columns in it?
*
* @return bool
*
*/
public function hasCols()
{
return (bool) $this->col_values;
}
/**
*
* Sets one column value placeholder; if an optional second parameter is
* passed, that value is bound to the placeholder.
*
* @param string $col The column name.
*
* @return $this
*
*/
protected function addCol($col)
{
$key = $this->quoter->quoteName($col);
$this->col_values[$key] = ":$col";
$args = func_get_args();
if (count($args) > 1) {
$this->bindValue($col, $args[1]);
}
return $this;
}
/**
*
* Sets multiple column value placeholders. If an element is a key-value
* pair, the key is treated as the column name and the value is bound to
* that column.
*
* @param array $cols A list of column names, optionally as key-value
* pairs where the key is a column name and the value is a bind value for
* that column.
*
* @return $this
*
*/
protected function addCols(array $cols)
{
foreach ($cols as $key => $val) {
if (is_int($key)) {
// integer key means the value is the column name
$this->addCol($val);
} else {
// the key is the column name and the value is a value to
// be bound to that column
$this->addCol($key, $val);
}
}
return $this;
}
/**
*
* Sets a column value directly; the value will not be escaped, although
* fully-qualified identifiers in the value will be quoted.
*
* @param string $col The column name.
*
* @param string $value The column value expression.
*
* @return $this
*
*/
protected function setCol($col, $value)
{
if ($value === null) {
$value = 'NULL';
}
$key = $this->quoter->quoteName($col);
$value = $this->quoter->quoteNamesIn($value);
$this->col_values[$key] = $value;
return $this;
}
/**
*
* Adds returning columns to the query.
*
* Multiple calls to returning() will append to the list of columns, not
* overwrite the previous columns.
*
* @param array $cols The column(s) to add to the query.
*
* @return $this
*
*/
protected function addReturning(array $cols)
{
foreach ($cols as $col) {
$this->returning[] = $this->quoter->quoteNamesIn($col);
}
return $this;
}
/**
*
* Builds the `RETURNING` clause of the statement.
*
* @return string
*
*/
protected function buildReturning()
{
if (! $this->returning) {
return ''; // not applicable
}
return PHP_EOL . 'RETURNING' . $this->indentCsv($this->returning);
}
}
+510
View File
@@ -0,0 +1,510 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery;
use Aura\SqlQuery\Common\LimitInterface;
use Aura\SqlQuery\Common\LimitOffsetInterface;
use Aura\SqlQuery\Common\SubselectInterface;
/**
*
* Abstract query object.
*
* @package Aura.SqlQuery
*
*/
abstract class AbstractQuery
{
/**
*
* Data to be bound to the query.
*
* @var array
*
*/
protected $bind_values = array();
/**
*
* The list of WHERE conditions.
*
* @var array
*
*/
protected $where = array();
/**
*
* ORDER BY these columns.
*
* @var array
*
*/
protected $order_by = array();
/**
*
* The number of rows to select
*
* @var int
*
*/
protected $limit = 0;
/**
*
* Return rows after this offset.
*
* @var int
*
*/
protected $offset = 0;
/**
*
* The list of flags.
*
* @var array
*
*/
protected $flags = array();
/**
*
* A helper for quoting identifier names.
*
* @var Quoter
*
*/
protected $quoter;
/**
*
* Prefix to use on placeholders for "sequential" bound values; used for
* deconfliction when merging bound values from sub-selects, etc.
*
* @var mixed
*
*/
protected $seq_bind_prefix = '';
/**
*
* Constructor.
*
* @param Quoter $quoter A helper for quoting identifier names.
*
* @param string $seq_bind_prefix A prefix for rewritten sequential-binding
* placeholders (@see getSeqPlaceholder()).
*
*/
public function __construct(Quoter $quoter, $seq_bind_prefix = '')
{
$this->quoter = $quoter;
$this->seq_bind_prefix = $seq_bind_prefix;
}
/**
*
* Returns the prefix for rewritten sequential-binding placeholders
* (@see getSeqPlaceholder()).
*
* @return string
*
*/
public function getSeqBindPrefix()
{
return $this->seq_bind_prefix;
}
/**
*
* Returns this query object as an SQL statement string.
*
* @return string
*
*/
public function __toString()
{
return $this->getStatement();
}
/**
*
* Returns this query object as an SQL statement string.
*
* @return string
*
*/
public function getStatement()
{
return $this->build();
}
/**
*
* Builds this query object into a string.
*
* @return string
*
*/
abstract protected function build();
/**
*
* Returns the prefix to use when quoting identifier names.
*
* @return string
*
*/
public function getQuoteNamePrefix()
{
return $this->quoter->getQuoteNamePrefix();
}
/**
*
* Returns the suffix to use when quoting identifier names.
*
* @return string
*
*/
public function getQuoteNameSuffix()
{
return $this->quoter->getQuoteNameSuffix();
}
/**
*
* Returns an array as an indented comma-separated values string.
*
* @param array $list The values to convert.
*
* @return string
*
*/
protected function indentCsv(array $list)
{
return PHP_EOL . ' '
. implode(',' . PHP_EOL . ' ', $list);
}
/**
*
* Returns an array as an indented string.
*
* @param array $list The values to convert.
*
* @return string
*
*/
protected function indent(array $list)
{
return PHP_EOL . ' '
. implode(PHP_EOL . ' ', $list);
}
/**
*
* Binds multiple values to placeholders; merges with existing values.
*
* @param array $bind_values Values to bind to placeholders.
*
* @return $this
*
*/
public function bindValues(array $bind_values)
{
// array_merge() renumbers integer keys, which is bad for
// question-mark placeholders
foreach ($bind_values as $key => $val) {
$this->bindValue($key, $val);
}
return $this;
}
/**
*
* Binds a single value to the query.
*
* @param string $name The placeholder name or number.
*
* @param mixed $value The value to bind to the placeholder.
*
* @return $this
*
*/
public function bindValue($name, $value)
{
$this->bind_values[$name] = $value;
return $this;
}
/**
*
* Gets the values to bind to placeholders.
*
* @return array
*
*/
public function getBindValues()
{
return $this->bind_values;
}
/**
*
* Reset all values bound to named placeholders.
*
* @return $this
*
*/
public function resetBindValues()
{
$this->bind_values = array();
return $this;
}
/**
*
* Builds the flags as a space-separated string.
*
* @return string
*
*/
protected function buildFlags()
{
if (! $this->flags) {
return ''; // not applicable
}
return ' ' . implode(' ', array_keys($this->flags));
}
/**
*
* Sets or unsets specified flag.
*
* @param string $flag Flag to set or unset
*
* @param bool $enable Flag status - enabled or not (default true)
*
* @return null
*
*/
protected function setFlag($flag, $enable = true)
{
if ($enable) {
$this->flags[$flag] = true;
} else {
unset($this->flags[$flag]);
}
}
/**
*
* Reset all query flags.
*
* @return $this
*
*/
public function resetFlags()
{
$this->flags = array();
return $this;
}
/**
*
* Adds a WHERE condition to the query by AND or OR. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $andor Add the condition using this operator, typically
* 'AND' or 'OR'.
*
* @param array $args Arguments for adding the condition.
*
* @return $this
*
*/
protected function addWhere($andor, $args)
{
$this->addClauseCondWithBind('where', $andor, $args);
return $this;
}
/**
*
* Adds conditions and binds values to a clause.
*
* @param string $clause The clause to work with, typically 'where' or
* 'having'.
*
* @param string $andor Add the condition using this operator, typically
* 'AND' or 'OR'.
*
* @param array $args Arguments for adding the condition.
*
* @return null
*
*/
protected function addClauseCondWithBind($clause, $andor, $args)
{
// remove the condition from the args and quote names in it
$cond = array_shift($args);
$cond = $this->rebuildCondAndBindValues($cond, $args);
// add condition to clause; $this->where
$clause =& $this->$clause;
if ($clause) {
$clause[] = "$andor $cond";
} else {
$clause[] = $cond;
}
}
/**
*
* Rebuilds a condition string, replacing sequential placeholders with
* named placeholders, and binding the sequential values to the named
* placeholders.
*
* @param string $cond The condition with sequential placeholders.
*
* @param array $bind_values The values to bind to the sequential
* placeholders under their named versions.
*
* @return string The rebuilt condition string.
*
*/
protected function rebuildCondAndBindValues($cond, array $bind_values)
{
$cond = $this->quoter->quoteNamesIn($cond);
// bind values against ?-mark placeholders, but because PDO is finicky
// about the numbering of sequential placeholders, convert each ?-mark
// to a named placeholder
$parts = preg_split('/(\?)/', $cond, null, PREG_SPLIT_DELIM_CAPTURE);
foreach ($parts as $key => $val) {
if ($val != '?') {
continue;
}
$bind_value = array_shift($bind_values);
if ($bind_value instanceof SubselectInterface) {
$parts[$key] = $bind_value->getStatement();
$this->bind_values = array_merge(
$this->bind_values,
$bind_value->getBindValues()
);
continue;
}
$placeholder = $this->getSeqPlaceholder();
$parts[$key] = ':' . $placeholder;
$this->bind_values[$placeholder] = $bind_value;
}
$cond = implode('', $parts);
return $cond;
}
/**
*
* Gets the current sequential placeholder name.
*
* @return string
*
*/
protected function getSeqPlaceholder()
{
$i = count($this->bind_values) + 1;
return $this->seq_bind_prefix . "_{$i}_";
}
/**
*
* Builds the `WHERE` clause of the statement.
*
* @return string
*
*/
protected function buildWhere()
{
if (! $this->where) {
return ''; // not applicable
}
return PHP_EOL . 'WHERE' . $this->indent($this->where);
}
/**
*
* Adds a column order to the query.
*
* @param array $spec The columns and direction to order by.
*
* @return $this
*
*/
protected function addOrderBy(array $spec)
{
foreach ($spec as $col) {
$this->order_by[] = $this->quoter->quoteNamesIn($col);
}
return $this;
}
/**
*
* Builds the `ORDER BY ...` clause of the statement.
*
* @return string
*
*/
protected function buildOrderBy()
{
if (! $this->order_by) {
return ''; // not applicable
}
return PHP_EOL . 'ORDER BY' . $this->indentCsv($this->order_by);
}
/**
*
* Builds the `LIMIT ... OFFSET` clause of the statement.
*
* Note that this will allow OFFSET values with a LIMIT.
*
* @return string
*
*/
protected function buildLimit()
{
$clause = '';
$limit = $this instanceof LimitInterface && $this->limit;
$offset = $this instanceof LimitOffsetInterface && $this->offset;
if ($limit) {
$clause .= "LIMIT {$this->limit}";
}
if ($offset) {
$clause .= " OFFSET {$this->offset}";
}
if ($clause) {
$clause = PHP_EOL . trim($clause);
}
return $clause;
}
}
+113
View File
@@ -0,0 +1,113 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
use Aura\SqlQuery\AbstractDmlQuery;
/**
*
* An object for DELETE queries.
*
* @package Aura.SqlQuery
*
*/
class Delete extends AbstractDmlQuery implements DeleteInterface
{
/**
*
* The table to delete from.
*
* @var string
*
*/
protected $from;
/**
*
* Sets the table to delete from.
*
* @param string $table The table to delete from.
*
* @return $this
*
*/
public function from($table)
{
$this->from = $this->quoter->quoteName($table);
return $this;
}
/**
*
* Builds this query object into a string.
*
* @return string
*
*/
protected function build()
{
return 'DELETE'
. $this->buildFlags()
. $this->buildFrom()
. $this->buildWhere()
. $this->buildOrderBy()
. $this->buildLimit()
. $this->buildReturning();
}
/**
*
* Builds the FROM clause.
*
* @return string
*
*/
protected function buildFrom()
{
return " FROM {$this->from}";
}
/**
*
* Adds a WHERE condition to the query by AND. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to bind to placeholders
*
* @return $this
*
*/
public function where($cond)
{
$this->addWhere('AND', func_get_args());
return $this;
}
/**
*
* Adds a WHERE condition to the query by OR. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to bind to placeholders
*
* @return $this
*
* @see where()
*
*/
public function orWhere($cond)
{
$this->addWhere('OR', func_get_args());
return $this;
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
use Aura\SqlQuery\QueryInterface;
/**
*
* An interface for DELETE queries.
*
* @package Aura.SqlQuery
*
*/
interface DeleteInterface extends QueryInterface, WhereInterface
{
/**
*
* Sets the table to delete from.
*
* @param string $from The table to delete from.
*
* @return $this
*
*/
public function from($from);
}
+374
View File
@@ -0,0 +1,374 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
use Aura\SqlQuery\AbstractDmlQuery;
use Aura\SqlQuery\Exception;
/**
*
* An object for INSERT queries.
*
* @package Aura.SqlQuery
*
*/
class Insert extends AbstractDmlQuery implements InsertInterface
{
/**
*
* The table to insert into.
*
* @var string
*
*/
protected $into;
/**
*
* A map of fully-qualified `table.column` names to last-insert-id names.
* This is used to look up the right last-insert-id name for a given table
* and column. Generally useful only for extended tables in Posgres.
*
* @var array
*
*/
protected $last_insert_id_names;
/**
*
* The current row-number we are adding column values for. This comes into
* play only with bulk inserts.
*
* @var int
*
*/
protected $row = 0;
/**
*
* A collection of `$col_values` for previous rows in bulk inserts.
*
* @var array
*
*/
protected $col_values_bulk = array();
/**
*
* A collection of `$bind_values` for previous rows in bulk inserts.
*
* @var array
*
*/
protected $bind_values_bulk = array();
/**
*
* The order in which columns will be bulk-inserted; this is taken from the
* very first inserted row.
*
* @var array
*
*/
protected $col_order = array();
/**
*
* Sets the map of fully-qualified `table.column` names to last-insert-id
* names. Generally useful only for extended tables in Posgres.
*
* @param array $last_insert_id_names The list of ID names.
*
*/
public function setLastInsertIdNames(array $last_insert_id_names)
{
$this->last_insert_id_names = $last_insert_id_names;
}
/**
*
* Sets the table to insert into.
*
* @param string $into The table to insert into.
*
* @return $this
*
*/
public function into($into)
{
// don't quote yet, we might need it for getLastInsertIdName()
$this->into = $into;
return $this;
}
/**
*
* Builds this query object into a string.
*
* @return string
*
*/
protected function build()
{
return 'INSERT'
. $this->buildFlags()
. $this->buildInto()
. $this->buildValuesForInsert()
. $this->buildReturning();
}
/**
*
* Builds the INTO clause.
*
* @return string
*
*/
protected function buildInto()
{
return " INTO " . $this->quoter->quoteName($this->into);
}
/**
*
* Returns the proper name for passing to `PDO::lastInsertId()`.
*
* @param string $col The last insert ID column.
*
* @return mixed Normally null, since most drivers do not need a name;
* alternatively, a string from `$last_insert_id_names`.
*
*/
public function getLastInsertIdName($col)
{
$key = $this->into . '.' . $col;
if (isset($this->last_insert_id_names[$key])) {
return $this->last_insert_id_names[$key];
}
}
/**
*
* Sets one column value placeholder; if an optional second parameter is
* passed, that value is bound to the placeholder.
*
* @param string $col The column name.
*
* @param mixed,... $val Optional: a value to bind to the placeholder.
*
* @return $this
*
*/
public function col($col)
{
return call_user_func_array(array($this, 'addCol'), func_get_args());
}
/**
*
* Sets multiple column value placeholders. If an element is a key-value
* pair, the key is treated as the column name and the value is bound to
* that column.
*
* @param array $cols A list of column names, optionally as key-value
* pairs where the key is a column name and the value is a bind value for
* that column.
*
* @return $this
*
*/
public function cols(array $cols)
{
return $this->addCols($cols);
}
/**
*
* Sets a column value directly; the value will not be escaped, although
* fully-qualified identifiers in the value will be quoted.
*
* @param string $col The column name.
*
* @param string $value The column value expression.
*
* @return $this
*
*/
public function set($col, $value)
{
return $this->setCol($col, $value);
}
/**
*
* Gets the values to bind to placeholders.
*
* @return array
*
*/
public function getBindValues()
{
return array_merge(parent::getBindValues(), $this->bind_values_bulk);
}
/**
*
* Adds multiple rows for bulk insert.
*
* @param array $rows An array of rows, where each element is an array of
* column key-value pairs. The values are bound to placeholders.
*
* @return $this
*
*/
public function addRows(array $rows)
{
foreach ($rows as $cols) {
$this->addRow($cols);
}
if ($this->row > 1) {
$this->finishRow();
}
return $this;
}
/**
*
* Add one row for bulk insert; increments the row counter and optionally
* adds columns to the new row.
*
* When adding the first row, the counter is not incremented.
*
* After calling `addRow()`, you can further call `col()`, `cols()`, and
* `set()` to work with the newly-added row. Calling `addRow()` again will
* finish off the current row and start a new one.
*
* @param array $cols An array of column key-value pairs; the values are
* bound to placeholders.
*
* @return $this
*
*/
public function addRow(array $cols = array())
{
if (! $this->col_values) {
return $this->cols($cols);
}
if (! $this->col_order) {
$this->col_order = array_keys($this->col_values);
}
$this->finishRow();
$this->row ++;
$this->cols($cols);
return $this;
}
/**
*
* Finishes off the current row in a bulk insert, collecting the bulk
* values and resetting for the next row.
*
* @return null
*
*/
protected function finishRow()
{
if (! $this->col_values) {
return;
}
foreach ($this->col_order as $col) {
$this->finishCol($col);
}
$this->col_values = array();
$this->bind_values = array();
}
/**
*
* Finishes off a single column of the current row in a bulk insert.
*
* @param string $col The column to finish off.
*
* @return null
*
* @throws Exception on named column missing from row.
*
*/
protected function finishCol($col)
{
if (! array_key_exists($col, $this->col_values)) {
throw new Exception("Column $col missing from row {$this->row}.");
}
// get the current col_value
$value = $this->col_values[$col];
// is it *not* a placeholder?
if (substr($value, 0, 1) != ':') {
// copy the value as-is
$this->col_values_bulk[$this->row][$col] = $value;
return;
}
// retain col_values in bulk with the row number appended
$this->col_values_bulk[$this->row][$col] = "{$value}_{$this->row}";
// the existing placeholder name without : or row number
$name = substr($value, 1);
// retain bind_value in bulk with new placeholder
if (array_key_exists($name, $this->bind_values)) {
$this->bind_values_bulk["{$name}_{$this->row}"] = $this->bind_values[$name];
}
}
/**
*
* Builds the inserted columns and values of the statement.
*
* @return string
*
*/
protected function buildValuesForInsert()
{
if ($this->row) {
return $this->buildValuesForBulkInsert();
}
return ' ('
. $this->indentCsv(array_keys($this->col_values))
. PHP_EOL . ') VALUES ('
. $this->indentCsv(array_values($this->col_values))
. PHP_EOL . ')';
}
/**
*
* Builds the bulk-inserted columns and values of the statement.
*
* @return string
*
*/
protected function buildValuesForBulkInsert()
{
$this->finishRow();
$cols = " (" . implode(', ', $this->col_order) . ")";
$vals = array();
foreach ($this->col_values_bulk as $row_values) {
$vals[] = " (" . implode(', ', $row_values) . ")";
}
return PHP_EOL . $cols . PHP_EOL
. "VALUES" . PHP_EOL
. implode("," . PHP_EOL, $vals);
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
use Aura\SqlQuery\QueryInterface;
/**
*
* An interface for INSERT queries.
*
* @package Aura.SqlQuery
*
*/
interface InsertInterface extends QueryInterface, ValuesInterface
{
/**
*
* Sets the table to insert into.
*
* @param string $into The table to insert into.
*
* @return $this
*
*/
public function into($into);
}
+30
View File
@@ -0,0 +1,30 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
/**
*
* An interface for LIMIT clauses.
*
* @package Aura.SqlQuery
*
*/
interface LimitInterface
{
/**
*
* Sets a limit count on the query.
*
* @param int $limit The number of rows to select.
*
* @return $this
*
*/
public function limit($limit);
}
@@ -0,0 +1,30 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
/**
*
* An interface for LIMIT...OFFSET clauses.
*
* @package Aura.SqlQuery
*
*/
interface LimitOffsetInterface extends LimitInterface
{
/**
*
* Sets a limit offset on the query.
*
* @param int $offset Start returning after this many rows.
*
* @return $this
*
*/
public function offset($offset);
}
+30
View File
@@ -0,0 +1,30 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
/**
*
* An interface for ORDER BY clauses.
*
* @package Aura.SqlQuery
*
*/
interface OrderByInterface
{
/**
*
* Adds a column order to the query.
*
* @param array $spec The columns and direction to order by.
*
* @return $this
*
*/
public function orderBy(array $spec);
}
+33
View File
@@ -0,0 +1,33 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
/**
*
* An interface for RETURNING clauses.
*
* @package Aura.SqlQuery
*
*/
interface ReturningInterface
{
/**
*
* Adds returning columns to the query.
*
* Multiple calls to returning() will append to the list of columns, not
* overwrite the previous columns.
*
* @param array $cols The column(s) to add to the query.
*
* @return $this
*
*/
public function returning(array $cols);
}
File diff suppressed because it is too large Load Diff
+233
View File
@@ -0,0 +1,233 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
use Aura\SqlQuery\QueryInterface;
/**
*
* An interface for SELECT queries.
*
* @package Aura.SqlQuery
*
*/
interface SelectInterface extends QueryInterface, WhereInterface, OrderByInterface, LimitOffsetInterface
{
/**
*
* Sets the number of rows per page.
*
* @param int $paging The number of rows to page at.
*
* @return $this
*
*/
public function setPaging($paging);
/**
*
* Gets the number of rows per page.
*
* @return int The number of rows per page.
*
*/
public function getPaging();
/**
*
* Makes the select FOR UPDATE (or not).
*
* @param bool $enable Whether or not the SELECT is FOR UPDATE (default
* true).
*
* @return $this
*
*/
public function forUpdate($enable = true);
/**
*
* Makes the select DISTINCT (or not).
*
* @param bool $enable Whether or not the SELECT is DISTINCT (default
* true).
*
* @return $this
*
*/
public function distinct($enable = true);
/**
*
* Adds columns to the query.
*
* Multiple calls to cols() will append to the list of columns, not
* overwrite the previous columns.
*
* @param array $cols The column(s) to add to the query.
*
* @return $this
*
*/
public function cols(array $cols);
/**
*
* Adds a FROM element to the query; quotes the table name automatically.
*
* @param string $spec The table specification; "foo" or "foo AS bar".
*
* @return $this
*
*/
public function from($spec);
/**
*
* Adds a raw unquoted FROM element to the query; useful for adding FROM
* elements that are functions.
*
* @param string $spec The table specification, e.g. "function_name()".
*
* @return $this
*
*/
public function fromRaw($spec);
/**
*
* Adds an aliased sub-select to the query.
*
* @param string|Select $spec If a Select object, use as the sub-select;
* if a string, the sub-select string.
*
* @param string $name The alias name for the sub-select.
*
* @return $this
*
*/
public function fromSubSelect($spec, $name);
/**
*
* Adds a JOIN table and columns to the query.
*
* @param string $join The join type: inner, left, natural, etc.
*
* @param string $spec The table specification; "foo" or "foo AS bar".
*
* @param string $cond Join on this condition.
*
* @return $this
*
*/
public function join($join, $spec, $cond = null);
/**
*
* Adds a JOIN to an aliased subselect and columns to the query.
*
* @param string $join The join type: inner, left, natural, etc.
*
* @param string|Select $spec If a Select
* object, use as the sub-select; if a string, the sub-select
* command string.
*
* @param string $name The alias name for the sub-select.
*
* @param string $cond Join on this condition.
*
* @return $this
*
*/
public function joinSubSelect($join, $spec, $name, $cond = null);
/**
*
* Adds grouping to the query.
*
* @param array $spec The column(s) to group by.
*
* @return $this
*
*/
public function groupBy(array $spec);
/**
*
* Adds a HAVING condition to the query by AND; if a value is passed as
* the second param, it will be quoted and replaced into the condition
* wherever a question-mark appears.
*
* Array values are quoted and comma-separated.
*
* {{code: php
* // simplest but non-secure
* $select->having("COUNT(id) = $count");
*
* // secure
* $select->having('COUNT(id) = ?', $count);
*
* // equivalent security with named binding
* $select->having('COUNT(id) = :count');
* $select->bind('count', $count);
* }}
*
* @param string $cond The HAVING condition.
*
* @return $this
*
*/
public function having($cond);
/**
*
* Adds a HAVING condition to the query by AND; otherwise identical to
* `having()`.
*
* @param string $cond The HAVING condition.
*
* @return $this
*
* @see having()
*
*/
public function orHaving($cond);
/**
*
* Sets the limit and count by page number.
*
* @param int $page Limit results to this page number.
*
* @return $this
*
*/
public function page($page);
/**
*
* Takes the current select properties and retains them, then sets
* UNION for the next set of properties.
*
* @return $this
*
*/
public function union();
/**
*
* Takes the current select properties and retains them, then sets
* UNION ALL for the next set of properties.
*
* @return $this
*
*/
public function unionAll();
}
+39
View File
@@ -0,0 +1,39 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
/**
*
* Interface to get a statement string so we can bind sub-select values.
*
* @package Aura.SqlQuery
*
* @see AbstractQuery::rebuildCondAndBindValues()
*
*/
interface SubselectInterface
{
/**
*
* Returns this query object as an SQL statement string.
*
* @return string
*
*/
public function getStatement();
/**
*
* Gets the values to bind to placeholders.
*
* @return array
*
*/
public function getBindValues();
}
+180
View File
@@ -0,0 +1,180 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
use Aura\SqlQuery\AbstractDmlQuery;
/**
*
* An object for UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
class Update extends AbstractDmlQuery implements UpdateInterface
{
/**
*
* The table to update.
*
* @var string
*
*/
protected $table;
/**
*
* Sets the table to update.
*
* @param string $table The table to update.
*
* @return $this
*
*/
public function table($table)
{
$this->table = $this->quoter->quoteName($table);
return $this;
}
/**
*
* Builds this query object into a string.
*
* @return string
*
*/
protected function build()
{
return 'UPDATE'
. $this->buildFlags()
. $this->buildTable()
. $this->buildValuesForUpdate()
. $this->buildWhere()
. $this->buildOrderBy()
. $this->buildLimit()
. $this->buildReturning();
}
/**
*
* Builds the table clause.
*
* @return null
*
*/
protected function buildTable()
{
return " {$this->table}";
}
/**
*
* Adds a WHERE condition to the query by AND. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to bind to placeholders
*
* @return $this
*
*/
public function where($cond)
{
$this->addWhere('AND', func_get_args());
return $this;
}
/**
*
* Adds a WHERE condition to the query by OR. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$bind arguments to bind to placeholders
*
* @return $this
*
* @see where()
*
*/
public function orWhere($cond)
{
$this->addWhere('OR', func_get_args());
return $this;
}
/**
*
* Sets one column value placeholder; if an optional second parameter is
* passed, that value is bound to the placeholder.
*
* @param string $col The column name.
*
* @return $this
*
*/
public function col($col)
{
return call_user_func_array(array($this, 'addCol'), func_get_args());
}
/**
*
* Sets multiple column value placeholders. If an element is a key-value
* pair, the key is treated as the column name and the value is bound to
* that column.
*
* @param array $cols A list of column names, optionally as key-value
* pairs where the key is a column name and the value is a bind value for
* that column.
*
* @return $this
*
*/
public function cols(array $cols)
{
return $this->addCols($cols);
}
/**
*
* Sets a column value directly; the value will not be escaped, although
* fully-qualified identifiers in the value will be quoted.
*
* @param string $col The column name.
*
* @param string $value The column value expression.
*
* @return $this
*
*/
public function set($col, $value)
{
return $this->setCol($col, $value);
}
/**
*
* Builds the updated columns and values of the statement.
*
* @return string
*
*/
protected function buildValuesForUpdate()
{
$values = array();
foreach ($this->col_values as $col => $value) {
$values[] = "{$col} = {$value}";
}
return PHP_EOL . 'SET' . $this->indentCsv($values);
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
use Aura\SqlQuery\QueryInterface;
/**
*
* An interface for UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
interface UpdateInterface extends QueryInterface, WhereInterface, ValuesInterface
{
/**
*
* Sets the table to update.
*
* @param string $table The table to update.
*
* @return $this
*
*/
public function table($table);
}
+60
View File
@@ -0,0 +1,60 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
/**
*
* An interface for setting column values.
*
* @package Aura.SqlQuery
*
*/
interface ValuesInterface
{
/**
*
* Sets one column value placeholder; if an optional second parameter is
* passed, that value is bound to the placeholder.
*
* @param string $col The column name.
*
* @return $this
*
*/
public function col($col);
/**
*
* Sets multiple column value placeholders. If an element is a key-value
* pair, the key is treated as the column name and the value is bound to
* that column.
*
* @param array $cols A list of column names, optionally as key-value
* pairs where the key is a column name and the value is a bind value for
* that column.
*
* @return $this
*
*/
public function cols(array $cols);
/**
*
* Sets a column value directly; the value will not be escaped, although
* fully-qualified identifiers in the value will be quoted.
*
* @param string $col The column name.
*
* @param string $value The column value expression.
*
* @return $this
*
*/
public function set($col, $value);
}
+49
View File
@@ -0,0 +1,49 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Common;
/**
*
* An interface for WHERE clauses.
*
* @package Aura.SqlQuery
*
*/
interface WhereInterface
{
/**
*
* Adds a WHERE condition to the query by AND. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$params arguments to be bound to placeholders
*
* @return $this
*
*/
public function where($cond);
/**
*
* Adds a WHERE condition to the query by OR. If the condition has
* ?-placeholders, additional arguments to the method will be bound to
* those placeholders sequentially.
*
* @param string $cond The WHERE condition.
* @param mixed ...$params arguments to be bound to placeholders
*
* @return $this
*
* @see where()
*
*/
public function orWhere($cond);
}
+20
View File
@@ -0,0 +1,20 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery;
/**
*
* Generic package-level exception.
*
* @package Aura.SqlQuery
*
*/
class Exception extends \Exception
{
}
+107
View File
@@ -0,0 +1,107 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Mysql;
use Aura\SqlQuery\Common;
/**
*
* An object for MySQL UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
class Delete extends Common\Delete implements Common\OrderByInterface, Common\LimitInterface
{
/**
*
* Adds or removes LOW_PRIORITY flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function lowPriority($enable = true)
{
$this->setFlag('LOW_PRIORITY', $enable);
return $this;
}
/**
*
* Adds or removes IGNORE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function ignore($enable = true)
{
$this->setFlag('IGNORE', $enable);
return $this;
}
/**
*
* Adds or removes QUICK flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function quick($enable = true)
{
$this->setFlag('QUICK', $enable);
return $this;
}
/**
*
* Sets a limit count on the query.
*
* @param int $limit The number of rows to select.
*
* @return $this
*
*/
public function limit($limit)
{
$this->limit = (int) $limit;
return $this;
}
/**
*
* Returns the LIMIT value.
*
* @return int
*
*/
public function getLimit()
{
return $this->limit;
}
/**
*
* Adds a column order to the query.
*
* @param array $spec The columns and direction to order by.
*
* @return $this
*
*/
public function orderBy(array $spec)
{
return $this->addOrderBy($spec);
}
}
+208
View File
@@ -0,0 +1,208 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Mysql;
use Aura\SqlQuery\Common;
/**
*
* An object for MySQL INSERT queries.
*
* @package Aura.SqlQuery
*
*/
class Insert extends Common\Insert
{
/**
*
* Column values for ON DUPLICATE KEY UPDATE section of query; the key is
* the column name and the value is the column value.
*
* @param array
*
*/
protected $col_on_update_values;
/**
*
* Adds or removes HIGH_PRIORITY flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function highPriority($enable = true)
{
$this->setFlag('HIGH_PRIORITY', $enable);
return $this;
}
/**
*
* Adds or removes LOW_PRIORITY flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function lowPriority($enable = true)
{
$this->setFlag('LOW_PRIORITY', $enable);
return $this;
}
/**
*
* Adds or removes IGNORE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function ignore($enable = true)
{
$this->setFlag('IGNORE', $enable);
return $this;
}
/**
*
* Adds or removes DELAYED flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function delayed($enable = true)
{
$this->setFlag('DELAYED', $enable);
return $this;
}
/**
*
* Sets one column value placeholder in ON DUPLICATE KEY UPDATE section;
* if an optional second parameter is passed, that value is bound to the
* placeholder.
*
* @param string $col The column name.
*
* @param mixed,... $val Optional: a value to bind to the placeholder.
*
* @return $this
*
*/
public function onDuplicateKeyUpdateCol($col)
{
$key = $this->quoter->quoteName($col);
$bind = $col . '__on_duplicate_key';
$this->col_on_update_values[$key] = ":$bind";
$args = func_get_args();
if (count($args) > 1) {
$this->bindValue($bind, $args[1]);
}
return $this;
}
/**
*
* Sets multiple column value placeholders in ON DUPLICATE KEY UPDATE
* section. If an element is a key-value pair, the key is treated as the
* column name and the value is bound to that column.
*
* @param array $cols A list of column names, optionally as key-value
* pairs where the key is a column name and the value is a bind value for
* that column.
*
* @return $this
*
*/
public function onDuplicateKeyUpdateCols(array $cols)
{
foreach ($cols as $key => $val) {
if (is_int($key)) {
// integer key means the value is the column name
$this->onDuplicateKeyUpdateCol($val);
} else {
// the key is the column name and the value is a value to
// be bound to that column
$this->onDuplicateKeyUpdateCol($key, $val);
}
}
return $this;
}
/**
*
* Sets a column value directly in ON DUPLICATE KEY UPDATE section; the
* value will not be escaped, although fully-qualified identifiers in the
* value will be quoted.
*
* @param string $col The column name.
*
* @param string $value The column value expression.
*
* @return $this
*
*/
public function onDuplicateKeyUpdate($col, $value)
{
if ($value === null) {
$value = 'NULL';
}
$key = $this->quoter->quoteName($col);
$value = $this->quoter->quoteNamesIn($value);
$this->col_on_update_values[$key] = $value;
return $this;
}
/**
*
* Builds this query object into a string.
*
* @return string
*
*/
protected function build()
{
return 'INSERT'
. $this->buildFlags()
. $this->buildInto()
. $this->buildValuesForInsert()
. $this->buildValuesForUpdateOnDuplicateKey()
. $this->buildReturning();
}
/**
*
* Builds the UPDATE ON DUPLICATE KEY part of the statement.
*
* @return string
*
*/
protected function buildValuesForUpdateOnDuplicateKey()
{
if (! $this->col_on_update_values) {
return ''; // not applicable
}
$values = array();
foreach ($this->col_on_update_values as $key => $row) {
$values[] = $this->indent(array($key . ' = ' . $row));
}
return ' ON DUPLICATE KEY UPDATE'
. implode (',', $values);
}
}
+141
View File
@@ -0,0 +1,141 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Mysql;
use Aura\SqlQuery\Common;
/**
*
* An object for MySQL SELECT queries.
*
* @package Aura.SqlQuery
*
*/
class Select extends Common\Select
{
/**
*
* Adds or removes SQL_CALC_FOUND_ROWS flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function calcFoundRows($enable = true)
{
$this->setFlag('SQL_CALC_FOUND_ROWS', $enable);
return $this;
}
/**
*
* Adds or removes SQL_CACHE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function cache($enable = true)
{
$this->setFlag('SQL_CACHE', $enable);
return $this;
}
/**
*
* Adds or removes SQL_NO_CACHE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function noCache($enable = true)
{
$this->setFlag('SQL_NO_CACHE', $enable);
return $this;
}
/**
*
* Adds or removes STRAIGHT_JOIN flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function straightJoin($enable = true)
{
$this->setFlag('STRAIGHT_JOIN', $enable);
return $this;
}
/**
*
* Adds or removes HIGH_PRIORITY flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function highPriority($enable = true)
{
$this->setFlag('HIGH_PRIORITY', $enable);
return $this;
}
/**
*
* Adds or removes SQL_SMALL_RESULT flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function smallResult($enable = true)
{
$this->setFlag('SQL_SMALL_RESULT', $enable);
return $this;
}
/**
*
* Adds or removes SQL_BIG_RESULT flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function bigResult($enable = true)
{
$this->setFlag('SQL_BIG_RESULT', $enable);
return $this;
}
/**
*
* Adds or removes SQL_BUFFER_RESULT flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function bufferResult($enable = true)
{
$this->setFlag('SQL_BUFFER_RESULT', $enable);
return $this;
}
}
+92
View File
@@ -0,0 +1,92 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Mysql;
use Aura\SqlQuery\Common;
/**
*
* An object for MySQL UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
class Update extends Common\Update implements Common\OrderByInterface, Common\LimitInterface
{
/**
*
* Adds or removes LOW_PRIORITY flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function lowPriority($enable = true)
{
$this->setFlag('LOW_PRIORITY', $enable);
return $this;
}
/**
*
* Adds or removes IGNORE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function ignore($enable = true)
{
$this->setFlag('IGNORE', $enable);
return $this;
}
/**
*
* Sets a limit count on the query.
*
* @param int $limit The number of rows to select.
*
* @return $this
*
*/
public function limit($limit)
{
$this->limit = (int) $limit;
return $this;
}
/**
*
* Returns the LIMIT value.
*
* @return int
*
*/
public function getLimit()
{
return $this->limit;
}
/**
*
* Adds a column order to the query.
*
* @param array $spec The columns and direction to order by.
*
* @return $this
*
*/
public function orderBy(array $spec)
{
return $this->addOrderBy($spec);
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Pgsql;
use Aura\SqlQuery\Common;
/**
*
* An object for PgSQL UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
class Delete extends Common\Delete implements Common\ReturningInterface
{
/**
*
* Adds returning columns to the query.
*
* Multiple calls to returning() will append to the list of columns, not
* overwrite the previous columns.
*
* @param array $cols The column(s) to add to the query.
*
* @return $this
*
*/
public function returning(array $cols)
{
return $this->addReturning($cols);
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Pgsql;
use Aura\SqlQuery\Common;
/**
*
* An object for PgSQL INSERT queries.
*
* @package Aura.SqlQuery
*
*/
class Insert extends Common\Insert implements Common\ReturningInterface
{
/**
*
* Returns the proper name for passing to `PDO::lastInsertId()`.
*
* @param string $col The last insert ID column.
*
* @return string The sequence name "{$into_table}_{$col}_seq", or the
* value from `$last_insert_id_names`.
*
*/
public function getLastInsertIdName($col)
{
$name = parent::getLastInsertIdName($col);
if (! $name) {
$name = "{$this->into}_{$col}_seq";
}
return $name;
}
/**
*
* Adds returning columns to the query.
*
* Multiple calls to returning() will append to the list of columns, not
* overwrite the previous columns.
*
* @param array $cols The column(s) to add to the query.
*
* @return $this
*
*/
public function returning(array $cols)
{
return $this->addReturning($cols);
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Pgsql;
use Aura\SqlQuery\Common;
/**
*
* An object for PgSQL SELECT queries.
*
* @package Aura.SqlQuery
*
*/
class Select extends Common\Select
{
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Pgsql;
use Aura\SqlQuery\Common;
/**
*
* An object for PgSQL UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
class Update extends Common\Update implements Common\ReturningInterface
{
/**
*
* Adds returning columns to the query.
*
* Multiple calls to returning() will append to the list of columns, not
* overwrite the previous columns.
*
* @param array $cols The column(s) to add to the query.
*
* @return $this
*
*/
public function returning(array $cols)
{
return $this->addReturning($cols);
}
}
+248
View File
@@ -0,0 +1,248 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery;
/**
*
* Creates query statement objects.
*
* @package Aura.SqlQuery
*
*/
class QueryFactory
{
const COMMON = 'common';
/**
*
* What database are we building for?
*
* @param string
*
*/
protected $db;
/**
*
* Build "common" query objects regardless of database type?
*
* @param bool
*
*/
protected $common = false;
/**
*
* The quote prefix/suffix to use for each type.
*
* @param array
*
*/
protected $quotes = array(
'Common' => array('"', '"'),
'Mysql' => array('`', '`'),
'Pgsql' => array('"', '"'),
'Sqlite' => array('"', '"'),
'Sqlsrv' => array('[', ']'),
);
/**
*
* The quote name prefix extracted from `$quotes`.
*
* @var string
*
*/
protected $quote_name_prefix;
/**
*
* The quote name suffix extracted from `$quotes`.
*
* @var string
*
*/
protected $quote_name_suffix;
/**
*
* A map of `table.col` names to last-insert-id names.
*
* @var array
*
*/
protected $last_insert_id_names = array();
/**
*
* A Quoter for identifiers.
*
* @param Quoter
*
*/
protected $quoter;
/**
*
* A count of Query instances, used for determining $seq_bind_prefix.
*
* @var int
*
*/
protected $instance_count = 0;
/**
*
* Constructor.
*
* @param string $db The database type.
*
* @param string $common Pass the constant self::COMMON to force common
* query objects instead of db-specific ones.
*
*/
public function __construct(
$db,
$common = null
) {
$this->db = ucfirst(strtolower($db));
$this->common = ($common === self::COMMON);
$this->quote_name_prefix = $this->quotes[$this->db][0];
$this->quote_name_suffix = $this->quotes[$this->db][1];
}
/**
*
* Sets the last-insert-id names to be used for Insert queries..
*
* @param array $last_insert_id_names A map of `table.col` names to
* last-insert-id names.
*
* @return null
*
*/
public function setLastInsertIdNames(array $last_insert_id_names)
{
$this->last_insert_id_names = $last_insert_id_names;
}
/**
*
* Returns a new SELECT object.
*
* @return Common\SelectInterface
*
*/
public function newSelect()
{
return $this->newInstance('Select');
}
/**
*
* Returns a new INSERT object.
*
* @return Common\InsertInterface
*
*/
public function newInsert()
{
$insert = $this->newInstance('Insert');
$insert->setLastInsertIdNames($this->last_insert_id_names);
return $insert;
}
/**
*
* Returns a new UPDATE object.
*
* @return Common\UpdateInterface
*
*/
public function newUpdate()
{
return $this->newInstance('Update');
}
/**
*
* Returns a new DELETE object.
*
* @return Common\DeleteInterface
*
*/
public function newDelete()
{
return $this->newInstance('Delete');
}
/**
*
* Returns a new query object.
*
* @param string $query The query object type.
*
* @return AbstractQuery
*
*/
protected function newInstance($query)
{
if ($this->common) {
$class = "Aura\SqlQuery\Common";
} else {
$class = "Aura\SqlQuery\\{$this->db}";
}
$class .= "\\{$query}";
return new $class(
$this->getQuoter(),
$this->newSeqBindPrefix()
);
}
/**
*
* Returns the Quoter object for queries; creates one if needed.
*
* @return Quoter
*
*/
protected function getQuoter()
{
if (! $this->quoter) {
$this->quoter = new Quoter(
$this->quote_name_prefix,
$this->quote_name_suffix
);
}
return $this->quoter;
}
/**
*
* Returns a new sequential-placeholder prefix for a query object.
*
* We need these to deconflict between bound values in subselect queries.
*
* @return string
*
*/
protected function newSeqBindPrefix()
{
$seq_bind_prefix = '';
if ($this->instance_count) {
$seq_bind_prefix = '_' . $this->instance_count;
}
$this->instance_count ++;
return $seq_bind_prefix;
}
}
+85
View File
@@ -0,0 +1,85 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery;
/**
*
* Interface for query objects.
*
* @package Aura.SqlQuery
*
* @method string getStatement() Returns the query statement as a string;
* missing from the interface but present in the implementations.
*
* @todo Add getStatement() to the interface in 3.x, since adding it in 2.x
* would be a BC break.
*
*/
interface QueryInterface
{
/**
*
* Builds this query object into a string.
*
* @return string
*
*/
public function __toString();
/**
*
* Returns the prefix to use when quoting identifier names.
*
* @return string
*
*/
public function getQuoteNamePrefix();
/**
*
* Returns the suffix to use when quoting identifier names.
*
* @return string
*
*/
public function getQuoteNameSuffix();
/**
*
* Adds values to bind into the query; merges with existing values.
*
* @param array $bind_values Values to bind to the query.
*
* @return $this
*
*/
public function bindValues(array $bind_values);
/**
*
* Binds a single value to the query.
*
* @param string $name The placeholder name or number.
*
* @param mixed $value The value to bind to the placeholder.
*
* @return $this
*
*/
public function bindValue($name, $value);
/**
*
* Gets the values to bind into the query.
*
* @return array
*
*/
public function getBindValues();
}
+297
View File
@@ -0,0 +1,297 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery;
/**
*
* A quoting mechanism for identifier names (not values).
*
* @package Aura.SqlQuery
*
*/
class Quoter
{
/**
*
* The prefix to use when quoting identifier names.
*
* @var string
*
*/
protected $quote_name_prefix = '"';
/**
*
* The suffix to use when quoting identifier names.
*
* @var string
*
*/
protected $quote_name_suffix = '"';
/**
*
* Constructor.
*
* @param string $quote_name_prefix The prefix to use when quoting
* identifier names.
*
* @param string $quote_name_suffix The suffix to use when quoting
* identifier names.
*
*/
public function __construct($quote_name_prefix, $quote_name_suffix)
{
$this->quote_name_prefix = $quote_name_prefix;
$this->quote_name_suffix = $quote_name_suffix;
}
/**
*
* Returns the prefix to use when quoting identifier names.
*
* @return string
*
*/
public function getQuoteNamePrefix()
{
return $this->quote_name_prefix;
}
/**
*
* Returns the suffix to use when quoting identifier names.
*
* @return string
*
*/
public function getQuoteNameSuffix()
{
return $this->quote_name_suffix;
}
/**
*
* Quotes a single identifier name (table, table alias, table column,
* index, sequence).
*
* If the name contains `' AS '`, this method will separately quote the
* parts before and after the `' AS '`.
*
* If the name contains a space, this method will separately quote the
* parts before and after the space.
*
* If the name contains a dot, this method will separately quote the
* parts before and after the dot.
*
* @param string $spec The identifier name to quote.
*
* @return string|array The quoted identifier name.
*
* @see replaceName()
*
* @see quoteNameWithSeparator()
*
*/
public function quoteName($spec)
{
$spec = trim($spec);
$seps = array(' AS ', ' ', '.');
foreach ($seps as $sep) {
$pos = strripos($spec, $sep);
if ($pos) {
return $this->quoteNameWithSeparator($spec, $sep, $pos);
}
}
return $this->replaceName($spec);
}
/**
*
* Quotes an identifier that has a separator.
*
* @param string $spec The identifier name to quote.
*
* @param string $sep The separator, typically a dot or space.
*
* @param int $pos The position of the separator.
*
* @return string The quoted identifier name.
*
*/
protected function quoteNameWithSeparator($spec, $sep, $pos)
{
$len = strlen($sep);
$part1 = $this->quoteName(substr($spec, 0, $pos));
$part2 = $this->replaceName(substr($spec, $pos + $len));
return "{$part1}{$sep}{$part2}";
}
/**
*
* Quotes all fully-qualified identifier names ("table.col") in a string,
* typically an SQL snippet for a SELECT clause.
*
* Does not quote identifier names that are string literals (i.e., inside
* single or double quotes).
*
* Looks for a trailing ' AS alias' and quotes the alias as well.
*
* @param string $text The string in which to quote fully-qualified
* identifier names to quote.
*
* @return string|array The string with names quoted in it.
*
* @see replaceNamesIn()
*
*/
public function quoteNamesIn($text)
{
$list = $this->getListForQuoteNamesIn($text);
$last = count($list) - 1;
$text = null;
foreach ($list as $key => $val) {
// skip elements 2, 5, 8, 11, etc. as artifacts of the back-
// referenced split; these are the trailing/ending quote
// portions, and already included in the previous element.
// this is the same as skipping every third element from zero.
if (($key+1) % 3) {
$text .= $this->quoteNamesInLoop($val, $key == $last);
}
}
return $text;
}
/**
*
* Returns a list of candidate elements for quoting.
*
* @param string $text The text to split into quoting candidates.
*
* @return array
*
*/
protected function getListForQuoteNamesIn($text)
{
// look for ', ", \', or \" in the string.
// match closing quotes against the same number of opening quotes.
$apos = "'";
$quot = '"';
return preg_split(
"/(($apos+|$quot+|\\$apos+|\\$quot+).*?\\2)/",
$text,
-1,
PREG_SPLIT_DELIM_CAPTURE
);
}
/**
*
* The in-loop functionality for quoting identifier names.
*
* @param string $val The name to be quoted.
*
* @param bool $is_last Is this the last loop?
*
* @return string The quoted name.
*
*/
protected function quoteNamesInLoop($val, $is_last)
{
if ($is_last) {
return $this->replaceNamesAndAliasIn($val);
}
return $this->replaceNamesIn($val);
}
/**
*
* Replaces the names and alias in a string.
*
* @param string $val The name to be quoted.
*
* @return string The quoted name.
*
*/
protected function replaceNamesAndAliasIn($val)
{
$quoted = $this->replaceNamesIn($val);
$pos = strripos($quoted, ' AS ');
if ($pos) {
$alias = $this->replaceName(substr($quoted, $pos + 4));
$quoted = substr($quoted, 0, $pos) . " AS $alias";
}
return $quoted;
}
/**
*
* Quotes an identifier name (table, index, etc); ignores empty values and
* values of '*'.
*
* @param string $name The identifier name to quote.
*
* @return string The quoted identifier name.
*
* @see quoteName()
*
*/
protected function replaceName($name)
{
$name = trim($name);
if ($name == '*') {
return $name;
}
return $this->quote_name_prefix
. $name
. $this->quote_name_suffix;
}
/**
*
* Quotes all fully-qualified identifier names ("table.col") in a string.
*
* @param string $text The string in which to quote fully-qualified
* identifier names to quote.
*
* @return string|array The string with names quoted in it.
*
* @see quoteNamesIn()
*
*/
protected function replaceNamesIn($text)
{
$is_string_literal = strpos($text, "'") !== false
|| strpos($text, '"') !== false;
if ($is_string_literal) {
return $text;
}
$word = "[a-z_][a-z0-9_]*";
$find = "/(\\b)($word)\\.($word)(\\b)/i";
$repl = '$1'
. $this->quote_name_prefix
. '$2'
. $this->quote_name_suffix
. '.'
. $this->quote_name_prefix
. '$3'
. $this->quote_name_suffix
. '$4'
;
$text = preg_replace($find, $repl, $text);
return $text;
}
}
+89
View File
@@ -0,0 +1,89 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlite;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlite DELETE queries.
*
* @package Aura.SqlQuery
*
*/
class Delete extends Common\Delete implements Common\OrderByInterface, Common\LimitOffsetInterface
{
/**
*
* Sets a limit count on the query.
*
* @param int $limit The number of rows to select.
*
* @return $this
*
*/
public function limit($limit)
{
$this->limit = (int) $limit;
return $this;
}
/**
*
* Returns the LIMIT value.
*
* @return int
*
*/
public function getLimit()
{
return $this->limit;
}
/**
*
* Sets a limit offset on the query.
*
* @param int $offset Start returning after this many rows.
*
* @return $this
*
*/
public function offset($offset)
{
$this->offset = (int) $offset;
return $this;
}
/**
*
* Returns the OFFSET value.
*
* @return int
*
*/
public function getOffset()
{
return $this->offset;
}
/**
*
* Adds a column order to the query.
*
* @param array $spec The columns and direction to order by.
*
* @return $this
*
*/
public function orderBy(array $spec)
{
return $this->addOrderBy($spec);
}
}
+96
View File
@@ -0,0 +1,96 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlite;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlite INSERT queries.
*
* @package Aura.SqlQuery
*
*/
class Insert extends Common\Insert
{
/**
*
* Adds or removes OR ABORT flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orAbort($enable = true)
{
$this->setFlag('OR ABORT', $enable);
return $this;
}
/**
*
* Adds or removes OR FAIL flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orFail($enable = true)
{
$this->setFlag('OR FAIL', $enable);
return $this;
}
/**
*
* Adds or removes OR IGNORE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orIgnore($enable = true)
{
$this->setFlag('OR IGNORE', $enable);
return $this;
}
/**
*
* Adds or removes OR REPLACE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orReplace($enable = true)
{
$this->setFlag('OR REPLACE', $enable);
return $this;
}
/**
*
* Adds or removes OR ROLLBACK flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orRollback($enable = true)
{
$this->setFlag('OR ROLLBACK', $enable);
return $this;
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlite;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlite SELECT queries.
*
* @package Aura.SqlQuery
*
*/
class Select extends Common\Select
{
}
+164
View File
@@ -0,0 +1,164 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlite;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlite UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
class Update extends Common\Update implements Common\OrderByInterface, Common\LimitOffsetInterface
{
/**
*
* Adds or removes OR ABORT flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orAbort($enable = true)
{
$this->setFlag('OR ABORT', $enable);
return $this;
}
/**
*
* Adds or removes OR FAIL flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orFail($enable = true)
{
$this->setFlag('OR FAIL', $enable);
return $this;
}
/**
*
* Adds or removes OR IGNORE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orIgnore($enable = true)
{
$this->setFlag('OR IGNORE', $enable);
return $this;
}
/**
*
* Adds or removes OR REPLACE flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orReplace($enable = true)
{
$this->setFlag('OR REPLACE', $enable);
return $this;
}
/**
*
* Adds or removes OR ROLLBACK flag.
*
* @param bool $enable Set or unset flag (default true).
*
* @return $this
*
*/
public function orRollback($enable = true)
{
$this->setFlag('OR ROLLBACK', $enable);
return $this;
}
/**
*
* Sets a limit count on the query.
*
* @param int $limit The number of rows to select.
*
* @return $this
*
*/
public function limit($limit)
{
$this->limit = (int) $limit;
return $this;
}
/**
*
* Returns the LIMIT value.
*
* @return int
*
*/
public function getLimit()
{
return $this->limit;
}
/**
*
* Sets a limit offset on the query.
*
* @param int $offset Start returning after this many rows.
*
* @return $this
*
*/
public function offset($offset)
{
$this->offset = (int) $offset;
return $this;
}
/**
*
* Returns the OFFSET value.
*
* @return int
*
*/
public function getOffset()
{
return $this->offset;
}
/**
*
* Adds a column order to the query.
*
* @param array $spec The columns and direction to order by.
*
* @return $this
*
*/
public function orderBy(array $spec)
{
return $this->addOrderBy($spec);
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlsrv;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlsrv DELETE queries.
*
* @package Aura.SqlQuery
*
*/
class Delete extends Common\Delete
{
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlsrv;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlsrv INSERT queries.
*
* @package Aura.SqlQuery
*
*/
class Insert extends Common\Insert
{
}
+77
View File
@@ -0,0 +1,77 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlsrv;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlsrv SELECT queries.
*
* @package Aura.SqlQuery
*
*/
class Select extends Common\Select
{
/**
*
* Builds this query object into a string.
*
* @return string
*
*/
protected function build()
{
return $this->applyLimit(parent::build());
}
/**
*
* Override so that LIMIT equivalent will be applied by applyLimit().
*
* @see build()
*
* @see applyLimit()
*
*/
protected function buildLimit()
{
return '';
}
/**
*
* Modify the statement applying limit/offset equivalent portions to it.
*
* @param string $stm SQL statement
* @return string SQL statement with limit/offset applied
*
*/
protected function applyLimit($stm)
{
if (! $this->limit && ! $this->offset) {
return $stm; // no limit or offset
}
// limit but no offset?
if ($this->limit && ! $this->offset) {
// use TOP in place
return preg_replace(
'/^(SELECT( DISTINCT)?)/',
"$1 TOP {$this->limit}",
$stm
);
}
// both limit and offset. must have an ORDER clause to work; OFFSET is
// a sub-clause of the ORDER clause. cannot use FETCH without OFFSET.
return $stm . PHP_EOL . "OFFSET {$this->offset} ROWS "
. "FETCH NEXT {$this->limit} ROWS ONLY";
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
*
* This file is part of Aura for PHP.
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\SqlQuery\Sqlsrv;
use Aura\SqlQuery\Common;
/**
*
* An object for Sqlsrv UPDATE queries.
*
* @package Aura.SqlQuery
*
*/
class Update extends Common\Update
{
}