mirror of
https://gitlab.com/hashborgir/d2tools.git
synced 2025-04-27 14:55:38 +00:00
597 lines
16 KiB
PHP
597 lines
16 KiB
PHP
<?php
|
|
|
|
namespace RedBeanPHP;
|
|
|
|
use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
|
|
use RedBeanPHP\QueryWriter as QueryWriter;
|
|
use RedBeanPHP\BeanHelper as BeanHelper;
|
|
use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
|
|
use RedBeanPHP\Repository as Repository;
|
|
use RedBeanPHP\Repository\Fluid as FluidRepo;
|
|
use RedBeanPHP\Repository\Frozen as FrozenRepo;
|
|
|
|
/**
|
|
* RedBean Object Oriented DataBase.
|
|
*
|
|
* The RedBean OODB Class is the main class of RedBeanPHP.
|
|
* It takes OODBBean objects and stores them to and loads them from the
|
|
* database as well as providing other CRUD functions. This class acts as a
|
|
* object database.
|
|
*
|
|
* @file RedBeanPHP/OODB.php
|
|
* @author Gabor de Mooij and the RedBeanPHP community
|
|
* @license BSD/GPLv2
|
|
*
|
|
* @copyright
|
|
* copyright (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community
|
|
* This source file is subject to the BSD/GPLv2 License that is bundled
|
|
* with this source code in the file license.txt.
|
|
*/
|
|
class OODB extends Observable
|
|
{
|
|
/**
|
|
* @var array
|
|
*/
|
|
private static $sqlFilters = array();
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $chillList = array();
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $stash = NULL;
|
|
|
|
/*
|
|
* @var integer
|
|
*/
|
|
protected $nesting = 0;
|
|
|
|
/**
|
|
* @var DBAdapter
|
|
*/
|
|
protected $writer;
|
|
|
|
/**
|
|
* @var boolean
|
|
*/
|
|
protected $isFrozen = FALSE;
|
|
|
|
/**
|
|
* @var FacadeBeanHelper
|
|
*/
|
|
protected $beanhelper = NULL;
|
|
|
|
/**
|
|
* @var AssociationManager
|
|
*/
|
|
protected $assocManager = NULL;
|
|
|
|
/**
|
|
* @var Repository
|
|
*/
|
|
protected $repository = NULL;
|
|
|
|
/**
|
|
* @var FrozenRepo
|
|
*/
|
|
protected $frozenRepository = NULL;
|
|
|
|
/**
|
|
* @var FluidRepo
|
|
*/
|
|
protected $fluidRepository = NULL;
|
|
|
|
/**
|
|
* @var boolean
|
|
*/
|
|
protected static $autoClearHistoryAfterStore = FALSE;
|
|
|
|
/**
|
|
* If set to TRUE, this method will call clearHistory every time
|
|
* the bean gets stored.
|
|
*
|
|
* @param boolean $autoClear auto clear option
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function autoClearHistoryAfterStore( $autoClear = TRUE )
|
|
{
|
|
self::$autoClearHistoryAfterStore = (boolean) $autoClear;
|
|
}
|
|
|
|
/**
|
|
* Unboxes a bean from a FUSE model if needed and checks whether the bean is
|
|
* an instance of OODBBean.
|
|
*
|
|
* @param OODBBean $bean bean you wish to unbox
|
|
*
|
|
* @return OODBBean
|
|
*/
|
|
protected function unboxIfNeeded( $bean )
|
|
{
|
|
if ( $bean instanceof SimpleModel ) {
|
|
$bean = $bean->unbox();
|
|
}
|
|
if ( !( $bean instanceof OODBBean ) ) {
|
|
throw new RedException( 'OODB Store requires a bean, got: ' . gettype( $bean ) );
|
|
}
|
|
|
|
return $bean;
|
|
}
|
|
|
|
/**
|
|
* Constructor, requires a query writer.
|
|
* Most of the time, you do not need to use this constructor,
|
|
* since the facade takes care of constructing and wiring the
|
|
* RedBeanPHP core objects. However if you would like to
|
|
* assemble an OODB instance yourself, this is how it works:
|
|
*
|
|
* Usage:
|
|
*
|
|
* <code>
|
|
* $database = new RPDO( $dsn, $user, $pass );
|
|
* $adapter = new DBAdapter( $database );
|
|
* $writer = new PostgresWriter( $adapter );
|
|
* $oodb = new OODB( $writer, FALSE );
|
|
* $bean = $oodb->dispense( 'bean' );
|
|
* $bean->name = 'coffeeBean';
|
|
* $id = $oodb->store( $bean );
|
|
* $bean = $oodb->load( 'bean', $id );
|
|
* </code>
|
|
*
|
|
* The example above creates the 3 RedBeanPHP core objects:
|
|
* the Adapter, the Query Writer and the OODB instance and
|
|
* wires them together. The example also demonstrates some of
|
|
* the methods that can be used with OODB, as you see, they
|
|
* closely resemble their facade counterparts.
|
|
*
|
|
* The wiring process: create an RPDO instance using your database
|
|
* connection parameters. Create a database adapter from the RPDO
|
|
* object and pass that to the constructor of the writer. Next,
|
|
* create an OODB instance from the writer. Now you have an OODB
|
|
* object.
|
|
*
|
|
* @param QueryWriter $writer writer
|
|
* @param array|boolean $frozen mode of operation: TRUE (frozen), FALSE (default, fluid) or ARRAY (chilled)
|
|
*/
|
|
public function __construct( QueryWriter $writer, $frozen = FALSE )
|
|
{
|
|
if ( $writer instanceof QueryWriter ) {
|
|
$this->writer = $writer;
|
|
}
|
|
|
|
$this->freeze( $frozen );
|
|
}
|
|
|
|
/**
|
|
* Toggles fluid or frozen mode. In fluid mode the database
|
|
* structure is adjusted to accomodate your objects. In frozen mode
|
|
* this is not the case.
|
|
*
|
|
* You can also pass an array containing a selection of frozen types.
|
|
* Let's call this chilly mode, it's just like fluid mode except that
|
|
* certain types (i.e. tables) aren't touched.
|
|
*
|
|
* @param boolean|array $toggle TRUE if you want to use OODB instance in frozen mode
|
|
*
|
|
* @return void
|
|
*/
|
|
public function freeze( $toggle )
|
|
{
|
|
if ( is_array( $toggle ) ) {
|
|
$this->chillList = $toggle;
|
|
$this->isFrozen = FALSE;
|
|
} else {
|
|
$this->isFrozen = (boolean) $toggle;
|
|
}
|
|
|
|
if ( $this->isFrozen ) {
|
|
if ( !$this->frozenRepository ) {
|
|
$this->frozenRepository = new FrozenRepo( $this, $this->writer );
|
|
}
|
|
|
|
$this->repository = $this->frozenRepository;
|
|
|
|
} else {
|
|
if ( !$this->fluidRepository ) {
|
|
$this->fluidRepository = new FluidRepo( $this, $this->writer );
|
|
}
|
|
|
|
$this->repository = $this->fluidRepository;
|
|
}
|
|
|
|
if ( count( self::$sqlFilters ) ) {
|
|
AQueryWriter::setSQLFilters( self::$sqlFilters, ( !$this->isFrozen ) );
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the current mode of operation of RedBean.
|
|
* In fluid mode the database
|
|
* structure is adjusted to accomodate your objects.
|
|
* In frozen mode
|
|
* this is not the case.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isFrozen()
|
|
{
|
|
return (bool) $this->isFrozen;
|
|
}
|
|
|
|
/**
|
|
* Determines whether a type is in the chill list.
|
|
* If a type is 'chilled' it's frozen, so its schema cannot be
|
|
* changed anymore. However other bean types may still be modified.
|
|
* This method is a convenience method for other objects to check if
|
|
* the schema of a certain type is locked for modification.
|
|
*
|
|
* @param string $type the type you wish to check
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isChilled( $type )
|
|
{
|
|
return (boolean) ( in_array( $type, $this->chillList ) );
|
|
}
|
|
|
|
/**
|
|
* Dispenses a new bean (a OODBBean Bean Object)
|
|
* of the specified type. Always
|
|
* use this function to get an empty bean object. Never
|
|
* instantiate a OODBBean yourself because it needs
|
|
* to be configured before you can use it with RedBean. This
|
|
* function applies the appropriate initialization /
|
|
* configuration for you.
|
|
*
|
|
* @param string $type type of bean you want to dispense
|
|
* @param string $number number of beans you would like to get
|
|
* @param boolean $alwaysReturnArray if TRUE always returns the result as an array
|
|
*
|
|
* @return OODBBean
|
|
*/
|
|
public function dispense( $type, $number = 1, $alwaysReturnArray = FALSE )
|
|
{
|
|
if ( $number < 1 ) {
|
|
if ( $alwaysReturnArray ) return array();
|
|
return NULL;
|
|
}
|
|
|
|
return $this->repository->dispense( $type, $number, $alwaysReturnArray );
|
|
}
|
|
|
|
/**
|
|
* Sets bean helper to be given to beans.
|
|
* Bean helpers assist beans in getting a reference to a toolbox.
|
|
*
|
|
* @param BeanHelper $beanhelper helper
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setBeanHelper( BeanHelper $beanhelper )
|
|
{
|
|
$this->beanhelper = $beanhelper;
|
|
}
|
|
|
|
/**
|
|
* Returns the current bean helper.
|
|
* Bean helpers assist beans in getting a reference to a toolbox.
|
|
*
|
|
* @return BeanHelper
|
|
*/
|
|
public function getBeanHelper()
|
|
{
|
|
return $this->beanhelper;
|
|
}
|
|
|
|
/**
|
|
* Checks whether a OODBBean bean is valid.
|
|
* If the type is not valid or the ID is not valid it will
|
|
* throw an exception: Security.
|
|
*
|
|
* @param OODBBean $bean the bean that needs to be checked
|
|
*
|
|
* @return void
|
|
*/
|
|
public function check( OODBBean $bean )
|
|
{
|
|
$this->repository->check( $bean );
|
|
}
|
|
|
|
/**
|
|
* Searches the database for a bean that matches conditions $conditions and sql $addSQL
|
|
* and returns an array containing all the beans that have been found.
|
|
*
|
|
* Conditions need to take form:
|
|
*
|
|
* <code>
|
|
* array(
|
|
* 'PROPERTY' => array( POSSIBLE VALUES... 'John', 'Steve' )
|
|
* 'PROPERTY' => array( POSSIBLE VALUES... )
|
|
* );
|
|
* </code>
|
|
*
|
|
* All conditions are glued together using the AND-operator, while all value lists
|
|
* are glued using IN-operators thus acting as OR-conditions.
|
|
*
|
|
* Note that you can use property names; the columns will be extracted using the
|
|
* appropriate bean formatter.
|
|
*
|
|
* @param string $type type of beans you are looking for
|
|
* @param array $conditions list of conditions
|
|
* @param string $sql SQL to be used in query
|
|
* @param array $bindings a list of values to bind to query parameters
|
|
*
|
|
* @return array
|
|
*/
|
|
public function find( $type, $conditions = array(), $sql = NULL, $bindings = array() )
|
|
{
|
|
return $this->repository->find( $type, $conditions, $sql, $bindings );
|
|
}
|
|
|
|
/**
|
|
* Same as find() but returns a BeanCollection.
|
|
*
|
|
* @param string $type type of beans you are looking for
|
|
* @param string $sql SQL to be used in query
|
|
* @param array $bindings a list of values to bind to query parameters
|
|
*
|
|
* @return BeanCollection
|
|
*/
|
|
public function findCollection( $type, $sql = NULL, $bindings = array() )
|
|
{
|
|
return $this->repository->findCollection( $type, $sql, $bindings );
|
|
}
|
|
|
|
/**
|
|
* Checks whether the specified table already exists in the database.
|
|
* Not part of the Object Database interface!
|
|
*
|
|
* @deprecated Use AQueryWriter::typeExists() instead.
|
|
*
|
|
* @param string $table table name
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function tableExists( $table )
|
|
{
|
|
return $this->repository->tableExists( $table );
|
|
}
|
|
|
|
/**
|
|
* Stores a bean in the database. This method takes a
|
|
* OODBBean Bean Object $bean and stores it
|
|
* in the database. If the database schema is not compatible
|
|
* with this bean and RedBean runs in fluid mode the schema
|
|
* will be altered to store the bean correctly.
|
|
* If the database schema is not compatible with this bean and
|
|
* RedBean runs in frozen mode it will throw an exception.
|
|
* This function returns the primary key ID of the inserted
|
|
* bean.
|
|
*
|
|
* The return value is an integer if possible. If it is not possible to
|
|
* represent the value as an integer a string will be returned. We use
|
|
* explicit casts instead of functions to preserve performance
|
|
* (0.13 vs 0.28 for 10000 iterations on Core i3).
|
|
*
|
|
* @param OODBBean|SimpleModel $bean bean to store
|
|
*
|
|
* @return integer|string
|
|
*/
|
|
public function store( $bean )
|
|
{
|
|
$bean = $this->unboxIfNeeded( $bean );
|
|
$id = $this->repository->store( $bean );
|
|
if ( self::$autoClearHistoryAfterStore ) {
|
|
$bean->clearHistory();
|
|
}
|
|
return $id;
|
|
}
|
|
|
|
/**
|
|
* Loads a bean from the object database.
|
|
* It searches for a OODBBean Bean Object in the
|
|
* database. It does not matter how this bean has been stored.
|
|
* RedBean uses the primary key ID $id and the string $type
|
|
* to find the bean. The $type specifies what kind of bean you
|
|
* are looking for; this is the same type as used with the
|
|
* dispense() function. If RedBean finds the bean it will return
|
|
* the OODB Bean object; if it cannot find the bean
|
|
* RedBean will return a new bean of type $type and with
|
|
* primary key ID 0. In the latter case it acts basically the
|
|
* same as dispense().
|
|
*
|
|
* Important note:
|
|
* If the bean cannot be found in the database a new bean of
|
|
* the specified type will be generated and returned.
|
|
*
|
|
* @param string $type type of bean you want to load
|
|
* @param integer $id ID of the bean you want to load
|
|
*
|
|
* @return OODBBean
|
|
*/
|
|
public function load( $type, $id )
|
|
{
|
|
return $this->repository->load( $type, $id );
|
|
}
|
|
|
|
/**
|
|
* Removes a bean from the database.
|
|
* This function will remove the specified OODBBean
|
|
* Bean Object from the database.
|
|
*
|
|
* @param OODBBean|SimpleModel $bean bean you want to remove from database
|
|
*
|
|
* @return void
|
|
*/
|
|
public function trash( $bean )
|
|
{
|
|
$bean = $this->unboxIfNeeded( $bean );
|
|
return $this->repository->trash( $bean );
|
|
}
|
|
|
|
/**
|
|
* Returns an array of beans. Pass a type and a series of ids and
|
|
* this method will bring you the corresponding beans.
|
|
*
|
|
* important note: Because this method loads beans using the load()
|
|
* function (but faster) it will return empty beans with ID 0 for
|
|
* every bean that could not be located. The resulting beans will have the
|
|
* passed IDs as their keys.
|
|
*
|
|
* @param string $type type of beans
|
|
* @param array $ids ids to load
|
|
*
|
|
* @return array
|
|
*/
|
|
public function batch( $type, $ids )
|
|
{
|
|
return $this->repository->batch( $type, $ids );
|
|
}
|
|
|
|
/**
|
|
* This is a convenience method; it converts database rows
|
|
* (arrays) into beans. Given a type and a set of rows this method
|
|
* will return an array of beans of the specified type loaded with
|
|
* the data fields provided by the result set from the database.
|
|
*
|
|
* @param string $type type of beans you would like to have
|
|
* @param array $rows rows from the database result
|
|
* @param string $mask mask to apply for meta data
|
|
*
|
|
* @return array
|
|
*/
|
|
public function convertToBeans( $type, $rows, $mask = NULL )
|
|
{
|
|
return $this->repository->convertToBeans( $type, $rows, $mask );
|
|
}
|
|
|
|
/**
|
|
* Counts the number of beans of type $type.
|
|
* This method accepts a second argument to modify the count-query.
|
|
* A third argument can be used to provide bindings for the SQL snippet.
|
|
*
|
|
* @param string $type type of bean we are looking for
|
|
* @param string $addSQL additional SQL snippet
|
|
* @param array $bindings parameters to bind to SQL
|
|
*
|
|
* @return integer
|
|
*/
|
|
public function count( $type, $addSQL = '', $bindings = array() )
|
|
{
|
|
return $this->repository->count( $type, $addSQL, $bindings );
|
|
}
|
|
|
|
/**
|
|
* Trash all beans of a given type. Wipes an entire type of bean.
|
|
*
|
|
* @param string $type type of bean you wish to delete all instances of
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function wipe( $type )
|
|
{
|
|
return $this->repository->wipe( $type );
|
|
}
|
|
|
|
/**
|
|
* Returns an Association Manager for use with OODB.
|
|
* A simple getter function to obtain a reference to the association manager used for
|
|
* storage and more.
|
|
*
|
|
* @return AssociationManager
|
|
*/
|
|
public function getAssociationManager()
|
|
{
|
|
if ( !isset( $this->assocManager ) ) {
|
|
throw new RedException( 'No association manager available.' );
|
|
}
|
|
|
|
return $this->assocManager;
|
|
}
|
|
|
|
/**
|
|
* Sets the association manager instance to be used by this OODB.
|
|
* A simple setter function to set the association manager to be used for storage and
|
|
* more.
|
|
*
|
|
* @param AssociationManager $assocManager sets the association manager to be used
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setAssociationManager( AssociationManager $assocManager )
|
|
{
|
|
$this->assocManager = $assocManager;
|
|
}
|
|
|
|
/**
|
|
* Returns the currently used repository instance.
|
|
* For testing purposes only.
|
|
*
|
|
* @return Repository
|
|
*/
|
|
public function getCurrentRepository()
|
|
{
|
|
return $this->repository;
|
|
}
|
|
|
|
/**
|
|
* Clears all function bindings.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function clearAllFuncBindings()
|
|
{
|
|
self::$sqlFilters = array();
|
|
AQueryWriter::setSQLFilters( self::$sqlFilters, FALSE );
|
|
}
|
|
|
|
/**
|
|
* Binds an SQL function to a column.
|
|
* This method can be used to setup a decode/encode scheme or
|
|
* perform UUID insertion. This method is especially useful for handling
|
|
* MySQL spatial columns, because they need to be processed first using
|
|
* the asText/GeomFromText functions.
|
|
*
|
|
* @param string $mode mode to set function for, i.e. read or write
|
|
* @param string $field field (table.column) to bind SQL function to
|
|
* @param string $function SQL function to bind to field
|
|
* @param boolean $isTemplate TRUE if $function is an SQL string, FALSE for just a function name
|
|
*
|
|
* @return void
|
|
*/
|
|
public function bindFunc( $mode, $field, $function, $isTemplate = FALSE )
|
|
{
|
|
list( $type, $property ) = explode( '.', $field );
|
|
$mode = ($mode === 'write') ? QueryWriter::C_SQLFILTER_WRITE : QueryWriter::C_SQLFILTER_READ;
|
|
|
|
if ( !isset( self::$sqlFilters[$mode] ) ) self::$sqlFilters[$mode] = array();
|
|
if ( !isset( self::$sqlFilters[$mode][$type] ) ) self::$sqlFilters[$mode][$type] = array();
|
|
|
|
if ( is_null( $function ) ) {
|
|
unset( self::$sqlFilters[$mode][$type][$property] );
|
|
} else {
|
|
if ($mode === QueryWriter::C_SQLFILTER_WRITE) {
|
|
if ($isTemplate) {
|
|
$code = sprintf( $function, '?' );
|
|
} else {
|
|
$code = "{$function}(?)";
|
|
}
|
|
self::$sqlFilters[$mode][$type][$property] = $code;
|
|
} else {
|
|
if ($isTemplate) {
|
|
$code = sprintf( $function, $field );
|
|
} else {
|
|
$code = "{$function}({$field})";
|
|
}
|
|
self::$sqlFilters[$mode][$type][$property] = $code;
|
|
}
|
|
}
|
|
AQueryWriter::setSQLFilters( self::$sqlFilters, ( !$this->isFrozen ) );
|
|
}
|
|
}
|