X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fgabordemooij%2Fredbean%2FRedBeanPHP%2FQueryWriter%2FAQueryWriter.php;fp=vendor%2Fgabordemooij%2Fredbean%2FRedBeanPHP%2FQueryWriter%2FAQueryWriter.php;h=0000000000000000000000000000000000000000;hp=155ccf3c32f52998b13a0efaf2b049abf1321de4;hb=9917807b03b64faf00f6a1f29dcb6eafc454efa5;hpb=aea91e65e895364e460983b890e295aa5d5540a5 diff --git a/vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/AQueryWriter.php b/vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/AQueryWriter.php deleted file mode 100755 index 155ccf3c3..000000000 --- a/vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/AQueryWriter.php +++ /dev/null @@ -1,1185 +0,0 @@ - $value ) self::$renames[$key] = $value; - - return; - } - - self::$renames[$from] = $to; - } - - /** - * Globally available service method for RedBeanPHP. - * Converts a camel cased string to a snake cased string. - * - * @param string $camel camelCased string to converty to snake case - * - * @return string - */ - public static function camelsSnake( $camel ) - { - return strtolower( preg_replace( '/(?<=[a-z])([A-Z])|([A-Z])(?=[a-z])/', '_$1$2', $camel ) ); - } - - /** - * Clears renames. - * - * @return void - */ - public static function clearRenames() - { - self::$renames = array(); - } - - /** - * Toggles 'Narrow Field Mode'. - * In Narrow Field mode the queryRecord method will - * narrow its selection field to - * - * SELECT {table}.* - * - * instead of - * - * SELECT * - * - * This is a better way of querying because it allows - * more flexibility (for instance joins). However if you need - * the wide selector for backward compatibility; use this method - * to turn OFF Narrow Field Mode by passing FALSE. - * - * @param boolean $narrowField TRUE = Narrow Field FALSE = Wide Field - * - * @return void - */ - public static function setNarrowFieldMode( $narrowField ) - { - self::$flagNarrowFieldMode = (boolean) $narrowField; - } - - /** - * Sets SQL filters. - * This is a lowlevel method to set the SQL filter array. - * The format of this array is: - * - * - * array( - * '' => array( - * '' => array( - * '' => '' - * ) - * ) - * ) - * - * - * Example: - * - * - * array( - * QueryWriter::C_SQLFILTER_READ => array( - * 'book' => array( - * 'title' => ' LOWER(book.title) ' - * ) - * ) - * - * - * Note that you can use constants instead of magical chars - * as keys for the uppermost array. - * This is a lowlevel method. For a more friendly method - * please take a look at the facade: R::bindFunc(). - * - * @param array list of filters to set - * - * @return void - */ - public static function setSQLFilters( $sqlFilters, $safeMode = false ) - { - self::$flagSQLFilterSafeMode = (boolean) $safeMode; - self::$sqlFilters = $sqlFilters; - } - - /** - * Returns current SQL Filters. - * This method returns the raw SQL filter array. - * This is a lowlevel method. For a more friendly method - * please take a look at the facade: R::bindFunc(). - * - * @return array - */ - public static function getSQLFilters() - { - return self::$sqlFilters; - } - - /** - * Returns a cache key for the cache values passed. - * This method returns a fingerprint string to be used as a key to store - * data in the writer cache. - * - * @param array $keyValues key-value to generate key for - * - * @return string - */ - private function getCacheKey( $keyValues ) - { - return json_encode( $keyValues ); - } - - /** - * Returns the values associated with the provided cache tag and key. - * - * @param string $cacheTag cache tag to use for lookup - * @param string $key key to use for lookup - * - * @return mixed - */ - private function getCached( $cacheTag, $key ) - { - $sql = $this->adapter->getSQL(); - - if ($this->updateCache()) { - if ( isset( $this->cache[$cacheTag][$key] ) ) { - return $this->cache[$cacheTag][$key]; - } - } - - return NULL; - } - - /** - * Checks if the previous query had a keep-cache tag. - * If so, the cache will persist, otherwise the cache will be flushed. - * - * Returns TRUE if the cache will remain and FALSE if a flush has - * been performed. - * - * @return boolean - */ - private function updateCache() - { - $sql = $this->adapter->getSQL(); - if ( strpos( $sql, '-- keep-cache' ) !== strlen( $sql ) - 13 ) { - // If SQL has been taken place outside of this method then something else then - // a select query might have happened! (or instruct to keep cache) - $this->cache = array(); - return FALSE; - } - return TRUE; - } - - /** - * Stores data from the writer in the cache under a specific key and cache tag. - * A cache tag is used to make sure the cache remains consistent. In most cases the cache tag - * will be the bean type, this makes sure queries associated with a certain reference type will - * never contain conflicting data. - * Why not use the cache tag as a key? Well - * we need to make sure the cache contents fits the key (and key is based on the cache values). - * Otherwise it would be possible to store two different result sets under the same key (the cache tag). - * - * In previous versions you could only store one key-entry, I have changed this to - * improve caching efficiency (issue #400). - * - * @param string $cacheTag cache tag (secondary key) - * @param string $key key to store values under - * @param array $values content to be stored - * - * @return void - */ - private function putResultInCache( $cacheTag, $key, $values ) - { - if ( isset( $this->cache[$cacheTag] ) ) { - if ( count( $this->cache[$cacheTag] ) > $this->maxCacheSizePerType ) array_shift( $this->cache[$cacheTag] ); - } else { - $this->cache[$cacheTag] = array(); - } - - $this->cache[$cacheTag][$key] = $values; - } - - /** - * Creates an SQL snippet from a list of conditions of format: - * - * - * array( - * key => array( - * value1, value2, value3 .... - * ) - * ) - * - * - * @param array $conditions list of conditions - * @param array $bindings parameter bindings for SQL snippet - * @param string $addSql additional SQL snippet to append to result - * - * @return string - */ - private function makeSQLFromConditions( $conditions, &$bindings, $addSql = '' ) - { - reset( $bindings ); - $firstKey = key( $bindings ); - $paramTypeIsNum = ( is_numeric( $firstKey ) ); - $counter = 0; - - $sqlConditions = array(); - foreach ( $conditions as $column => $values ) { - if ( !count( $values ) ) continue; - - $sql = $this->esc( $column ); - $sql .= ' IN ( '; - - if ( !is_array( $values ) ) $values = array( $values ); - - if ( $paramTypeIsNum ) { - $sql .= implode( ',', array_fill( 0, count( $values ), '?' ) ) . ' ) '; - - array_unshift($sqlConditions, $sql); - - foreach ( $values as $k => $v ) { - $values[$k] = strval( $v ); - - array_unshift( $bindings, $v ); - } - } else { - - $slots = array(); - - foreach( $values as $k => $v ) { - $slot = ':slot'.$counter++; - $slots[] = $slot; - $bindings[$slot] = strval( $v ); - } - - $sql .= implode( ',', $slots ).' ) '; - $sqlConditions[] = $sql; - } - } - - $sql = ''; - if ( is_array( $sqlConditions ) && count( $sqlConditions ) > 0 ) { - $sql = implode( ' AND ', $sqlConditions ); - $sql = " WHERE ( $sql ) "; - - if ( $addSql ) $sql .= $addSql; - } elseif ( $addSql ) { - $sql = $addSql; - } - - return $sql; - } - - /** - * Returns the table names and column names for a relational query. - * - * @param string $sourceType type of the source bean - * @param string $destType type of the bean you want to obtain using the relation - * @param boolean $noQuote TRUE if you want to omit quotes - * - * @return array - */ - private function getRelationalTablesAndColumns( $sourceType, $destType, $noQuote = FALSE ) - { - $linkTable = $this->esc( $this->getAssocTable( array( $sourceType, $destType ) ), $noQuote ); - $sourceCol = $this->esc( $sourceType . '_id', $noQuote ); - - if ( $sourceType === $destType ) { - $destCol = $this->esc( $destType . '2_id', $noQuote ); - } else { - $destCol = $this->esc( $destType . '_id', $noQuote ); - } - - $sourceTable = $this->esc( $sourceType, $noQuote ); - $destTable = $this->esc( $destType, $noQuote ); - - return array( $sourceTable, $destTable, $linkTable, $sourceCol, $destCol ); - } - - /** - * Given a type and a property name this method - * returns the foreign key map section associated with this pair. - * - * @param string $type name of the type - * @param string $property name of the property - * - * @return array|NULL - */ - protected function getForeignKeyForTypeProperty( $type, $property ) - { - $property = $this->esc( $property, TRUE ); - - try { - $map = $this->getKeyMapForType( $type ); - } catch ( SQLException $e ) { - return NULL; - } - - foreach( $map as $key ) { - if ( $key['from'] === $property ) return $key; - } - return NULL; - } - - /** - * Returns the foreign key map (FKM) for a type. - * A foreign key map describes the foreign keys in a table. - * A FKM always has the same structure: - * - * - * array( - * 'name' => - * 'from' => - * 'table' => - * 'to' => (most of the time 'id') - * 'on_update' => - * 'on_delete' => - * ) - * - * - * @note the keys in the result array are FKDLs, i.e. descriptive unique - * keys per source table. Also see: AQueryWriter::makeFKLabel for details. - * - * @param string $type the bean type you wish to obtain a key map of - * - * @return array - */ - protected function getKeyMapForType( $type ) - { - return array(); - } - - /** - * This method makes a key for a foreign key description array. - * This key is a readable string unique for every source table. - * This uniform key is called the FKDL Foreign Key Description Label. - * Note that the source table is not part of the FKDL because - * this key is supposed to be 'per source table'. If you wish to - * include a source table, prefix the key with 'on_table__'. - * - * @param string $from the column of the key in the source table - * @param string $type the type (table) where the key points to - * @param string $to the target column of the foreign key (mostly just 'id') - * - * @return string - */ - protected function makeFKLabel($from, $type, $to) - { - return "from_{$from}_to_table_{$type}_col_{$to}"; - } - - /** - * Returns an SQL Filter snippet for reading. - * - * @param string $type type of bean - * - * @return string - */ - protected function getSQLFilterSnippet( $type ) - { - $existingCols = array(); - if (self::$flagSQLFilterSafeMode) { - $existingCols = $this->getColumns( $type ); - } - - $sqlFilters = array(); - if ( isset( self::$sqlFilters[QueryWriter::C_SQLFILTER_READ][$type] ) ) { - foreach( self::$sqlFilters[QueryWriter::C_SQLFILTER_READ][$type] as $property => $sqlFilter ) { - if ( !self::$flagSQLFilterSafeMode || isset( $existingCols[$property] ) ) { - $sqlFilters[] = $sqlFilter.' AS '.$property.' '; - } - } - } - $sqlFilterStr = ( count($sqlFilters) ) ? ( ','.implode( ',', $sqlFilters ) ) : ''; - return $sqlFilterStr; - } - - /** - * Generates a list of parameters (slots) for an SQL snippet. - * This method calculates the correct number of slots to insert in the - * SQL snippet and determines the correct type of slot. If the bindings - * array contains named parameters this method will return named ones and - * update the keys in the value list accordingly (that's why we use the &). - * - * If you pass an offset the bindings will be re-added to the value list. - * Some databases cant handle duplicate parameter names in queries. - * - * @param array &$valueList list of values to generate slots for (gets modified if needed) - * @param array $otherBindings list of additional bindings - * @param integer $offset start counter at... - * - * @return string - */ - protected function getParametersForInClause( &$valueList, $otherBindings, $offset = 0 ) - { - if ( is_array( $otherBindings ) && count( $otherBindings ) > 0 ) { - reset( $otherBindings ); - - $key = key( $otherBindings ); - - if ( !is_numeric($key) ) { - $filler = array(); - $newList = (!$offset) ? array() : $valueList; - $counter = $offset; - - foreach( $valueList as $value ) { - $slot = ':slot' . ( $counter++ ); - $filler[] = $slot; - $newList[$slot] = $value; - } - - // Change the keys! - $valueList = $newList; - - return implode( ',', $filler ); - } - } - - return implode( ',', array_fill( 0, count( $valueList ), '?' ) ); - } - - /** - * Adds a data type to the list of data types. - * Use this method to add a new column type definition to the writer. - * Used for UUID support. - * - * @param integer $dataTypeID magic number constant assigned to this data type - * @param string $SQLDefinition SQL column definition (i.e. INT(11)) - * - * @return self - */ - protected function addDataType( $dataTypeID, $SQLDefinition ) - { - $this->typeno_sqltype[ $dataTypeID ] = $SQLDefinition; - $this->sqltype_typeno[ $SQLDefinition ] = $dataTypeID; - return $this; - } - - /** - * Returns the sql that should follow an insert statement. - * - * @param string $table name - * - * @return string - */ - protected function getInsertSuffix( $table ) - { - return ''; - } - - /** - * Checks whether a value starts with zeros. In this case - * the value should probably be stored using a text datatype instead of a - * numerical type in order to preserve the zeros. - * - * @param string $value value to be checked. - * - * @return boolean - */ - protected function startsWithZeros( $value ) - { - $value = strval( $value ); - - if ( strlen( $value ) > 1 && strpos( $value, '0' ) === 0 && strpos( $value, '0.' ) !== 0 ) { - return TRUE; - } else { - return FALSE; - } - } - - /** - * Inserts a record into the database using a series of insert columns - * and corresponding insertvalues. Returns the insert id. - * - * @param string $table table to perform query on - * @param array $insertcolumns columns to be inserted - * @param array $insertvalues values to be inserted - * - * @return integer - */ - protected function insertRecord( $type, $insertcolumns, $insertvalues ) - { - $default = $this->defaultValue; - $suffix = $this->getInsertSuffix( $type ); - $table = $this->esc( $type ); - - if ( count( $insertvalues ) > 0 && is_array( $insertvalues[0] ) && count( $insertvalues[0] ) > 0 ) { - - $insertSlots = array(); - foreach ( $insertcolumns as $k => $v ) { - $insertcolumns[$k] = $this->esc( $v ); - - if (isset(self::$sqlFilters['w'][$type][$v])) { - $insertSlots[] = self::$sqlFilters['w'][$type][$v]; - } else { - $insertSlots[] = '?'; - } - } - - $insertSQL = "INSERT INTO $table ( id, " . implode( ',', $insertcolumns ) . " ) VALUES - ( $default, " . implode( ',', $insertSlots ) . " ) $suffix"; - - $ids = array(); - foreach ( $insertvalues as $i => $insertvalue ) { - $ids[] = $this->adapter->getCell( $insertSQL, $insertvalue, $i ); - } - - $result = count( $ids ) === 1 ? array_pop( $ids ) : $ids; - } else { - $result = $this->adapter->getCell( "INSERT INTO $table (id) VALUES($default) $suffix" ); - } - - if ( $suffix ) return $result; - - $last_id = $this->adapter->getInsertID(); - - return $last_id; - } - - /** - * Checks table name or column name. - * - * @param string $table table string - * - * @return string - */ - protected function check( $struct ) - { - if ( !is_string( $struct ) || !preg_match( '/^[a-zA-Z0-9_]+$/', $struct ) ) { - throw new RedException( 'Identifier does not conform to RedBeanPHP security policies.' ); - } - - return $struct; - } - - /** - * Checks whether the specified type (i.e. table) already exists in the database. - * Not part of the Object Database interface! - * - * @param string $table table name - * - * @return boolean - */ - public function tableExists( $table ) - { - $tables = $this->getTables(); - - return in_array( $table, $tables ); - } - - /** - * @see QueryWriter::glueSQLCondition - */ - public function glueSQLCondition( $sql, $glue = NULL ) - { - static $snippetCache = array(); - - if ( trim( $sql ) === '' ) { - return $sql; - } - - $key = $glue . '|' . $sql; - - if ( isset( $snippetCache[$key] ) ) { - return $snippetCache[$key]; - } - - $lsql = ltrim( $sql ); - - if ( preg_match( '/^(INNER|LEFT|RIGHT|JOIN|AND|OR|WHERE|ORDER|GROUP|HAVING|LIMIT|OFFSET)\s+/i', $lsql ) ) { - if ( $glue === QueryWriter::C_GLUE_WHERE && stripos( $lsql, 'AND' ) === 0 ) { - $snippetCache[$key] = ' WHERE ' . substr( $lsql, 3 ); - } else { - $snippetCache[$key] = $sql; - } - } else { - $snippetCache[$key] = ( ( $glue === QueryWriter::C_GLUE_AND ) ? ' AND ' : ' WHERE ') . $sql; - } - - return $snippetCache[$key]; - } - - /** - * @see QueryWriter::glueLimitOne - */ - public function glueLimitOne( $sql = '') - { - return ( strpos( strtoupper( $sql ), 'LIMIT' ) === FALSE ) ? ( $sql . ' LIMIT 1 ' ) : $sql; - } - - /** - * @see QueryWriter::esc - */ - public function esc( $dbStructure, $dontQuote = FALSE ) - { - $this->check( $dbStructure ); - - return ( $dontQuote ) ? $dbStructure : $this->quoteCharacter . $dbStructure . $this->quoteCharacter; - } - - /** - * @see QueryWriter::addColumn - */ - public function addColumn( $type, $column, $field ) - { - $table = $type; - $type = $field; - $table = $this->esc( $table ); - $column = $this->esc( $column ); - - $type = ( isset( $this->typeno_sqltype[$type] ) ) ? $this->typeno_sqltype[$type] : ''; - - $this->adapter->exec( "ALTER TABLE $table ADD $column $type " ); - } - - /** - * @see QueryWriter::updateRecord - */ - public function updateRecord( $type, $updatevalues, $id = NULL ) - { - $table = $type; - - if ( !$id ) { - $insertcolumns = $insertvalues = array(); - - foreach ( $updatevalues as $pair ) { - $insertcolumns[] = $pair['property']; - $insertvalues[] = $pair['value']; - } - - //Otherwise psql returns string while MySQL/SQLite return numeric causing problems with additions (array_diff) - return (string) $this->insertRecord( $table, $insertcolumns, array( $insertvalues ) ); - } - - if ( $id && !count( $updatevalues ) ) { - return $id; - } - - $table = $this->esc( $table ); - $sql = "UPDATE $table SET "; - - $p = $v = array(); - - foreach ( $updatevalues as $uv ) { - - if ( isset( self::$sqlFilters['w'][$type][$uv['property']] ) ) { - $p[] = " {$this->esc( $uv["property"] )} = ". self::$sqlFilters['w'][$type][$uv['property']]; - } else { - $p[] = " {$this->esc( $uv["property"] )} = ? "; - } - - $v[] = $uv['value']; - } - - $sql .= implode( ',', $p ) . ' WHERE id = ? '; - - $v[] = $id; - - $this->adapter->exec( $sql, $v ); - - return $id; - } - - /** - * @see QueryWriter::writeJoin - */ - public function writeJoin( $type, $targetType, $leftRight = 'LEFT' ) - { - if ( $leftRight !== 'LEFT' && $leftRight !== 'RIGHT' && $leftRight !== 'INNER' ) - throw new RedException( 'Invalid JOIN.' ); - - $table = $this->esc( $type ); - $targetTable = $this->esc( $targetType ); - $field = $this->esc( $targetType, TRUE ); - return " {$leftRight} JOIN {$targetTable} ON {$targetTable}.id = {$table}.{$field}_id "; - } - - /** - * @see QueryWriter::queryRecord - */ - public function queryRecord( $type, $conditions = array(), $addSql = NULL, $bindings = array() ) - { - $addSql = $this->glueSQLCondition( $addSql, ( count($conditions) > 0) ? QueryWriter::C_GLUE_AND : NULL ); - - $key = NULL; - if ( $this->flagUseCache ) { - $key = $this->getCacheKey( array( $conditions, $addSql, $bindings, 'select' ) ); - - if ( $cached = $this->getCached( $type, $key ) ) { - return $cached; - } - } - - $table = $this->esc( $type ); - - $sqlFilterStr = ''; - if ( count( self::$sqlFilters ) ) { - $sqlFilterStr = $this->getSQLFilterSnippet( $type ); - } - - $sql = $this->makeSQLFromConditions( $conditions, $bindings, $addSql ); - - $fieldSelection = ( self::$flagNarrowFieldMode ) ? "{$table}.*" : '*'; - $sql = "SELECT {$fieldSelection} {$sqlFilterStr} FROM {$table} {$sql} -- keep-cache"; - - $rows = $this->adapter->get( $sql, $bindings ); - - if ( $this->flagUseCache && $key ) { - $this->putResultInCache( $type, $key, $rows ); - } - - return $rows; - } - - /** - * @see QueryWriter::queryRecordWithCursor - */ - public function queryRecordWithCursor( $type, $addSql = NULL, $bindings = array() ) - { - $sql = $this->glueSQLCondition( $addSql, NULL ); - $table = $this->esc( $type ); - $sql = "SELECT {$table}.* FROM {$table} {$sql}"; - return $this->adapter->getCursor( $sql, $bindings ); - } - - /** - * @see QueryWriter::queryRecordRelated - */ - public function queryRecordRelated( $sourceType, $destType, $linkIDs, $addSql = '', $bindings = array() ) - { - $addSql = $this->glueSQLCondition( $addSql, QueryWriter::C_GLUE_WHERE ); - - list( $sourceTable, $destTable, $linkTable, $sourceCol, $destCol ) = $this->getRelationalTablesAndColumns( $sourceType, $destType ); - - $key = $this->getCacheKey( array( $sourceType, $destType, implode( ',', $linkIDs ), $addSql, $bindings ) ); - - if ( $this->flagUseCache && $cached = $this->getCached( $destType, $key ) ) { - return $cached; - } - - $inClause = $this->getParametersForInClause( $linkIDs, $bindings ); - - $sqlFilterStr = ''; - if ( count( self::$sqlFilters ) ) { - $sqlFilterStr = $this->getSQLFilterSnippet( $destType ); - } - - if ( $sourceType === $destType ) { - $inClause2 = $this->getParametersForInClause( $linkIDs, $bindings, count( $bindings ) ); //for some databases - $sql = " - SELECT - {$destTable}.* {$sqlFilterStr} , - COALESCE( - NULLIF({$linkTable}.{$sourceCol}, {$destTable}.id), - NULLIF({$linkTable}.{$destCol}, {$destTable}.id)) AS linked_by - FROM {$linkTable} - INNER JOIN {$destTable} ON - ( {$destTable}.id = {$linkTable}.{$destCol} AND {$linkTable}.{$sourceCol} IN ($inClause) ) OR - ( {$destTable}.id = {$linkTable}.{$sourceCol} AND {$linkTable}.{$destCol} IN ($inClause2) ) - {$addSql} - -- keep-cache"; - - $linkIDs = array_merge( $linkIDs, $linkIDs ); - } else { - $sql = " - SELECT - {$destTable}.* {$sqlFilterStr}, - {$linkTable}.{$sourceCol} AS linked_by - FROM {$linkTable} - INNER JOIN {$destTable} ON - ( {$destTable}.id = {$linkTable}.{$destCol} AND {$linkTable}.{$sourceCol} IN ($inClause) ) - {$addSql} - -- keep-cache"; - } - - $bindings = array_merge( $linkIDs, $bindings ); - - $rows = $this->adapter->get( $sql, $bindings ); - - $this->putResultInCache( $destType, $key, $rows ); - - return $rows; - } - - /** - * @see QueryWriter::queryRecordLink - */ - public function queryRecordLink( $sourceType, $destType, $sourceID, $destID ) - { - list( $sourceTable, $destTable, $linkTable, $sourceCol, $destCol ) = $this->getRelationalTablesAndColumns( $sourceType, $destType ); - - $key = $this->getCacheKey( array( $sourceType, $destType, $sourceID, $destID ) ); - - if ( $this->flagUseCache && $cached = $this->getCached( $linkTable, $key ) ) { - return $cached; - } - - $sqlFilterStr = ''; - if ( count( self::$sqlFilters ) ) { - $sqlFilterStr = $this->getSQLFilterSnippet( $destType ); - } - - if ( $sourceTable === $destTable ) { - $sql = "SELECT {$linkTable}.* {$sqlFilterStr} FROM {$linkTable} - WHERE ( {$sourceCol} = ? AND {$destCol} = ? ) OR - ( {$destCol} = ? AND {$sourceCol} = ? ) -- keep-cache"; - $row = $this->adapter->getRow( $sql, array( $sourceID, $destID, $sourceID, $destID ) ); - } else { - $sql = "SELECT {$linkTable}.* {$sqlFilterStr} FROM {$linkTable} - WHERE {$sourceCol} = ? AND {$destCol} = ? -- keep-cache"; - $row = $this->adapter->getRow( $sql, array( $sourceID, $destID ) ); - } - - $this->putResultInCache( $linkTable, $key, $row ); - - return $row; - } - - /** - * @see QueryWriter::queryTagged - */ - public function queryTagged( $type, $tagList, $all = FALSE, $addSql = '', $bindings = array() ) - { - $assocType = $this->getAssocTable( array( $type, 'tag' ) ); - $assocTable = $this->esc( $assocType ); - $assocField = $type . '_id'; - $table = $this->esc( $type ); - $slots = implode( ',', array_fill( 0, count( $tagList ), '?' ) ); - $score = ( $all ) ? count( $tagList ) : 1; - - $sql = " - SELECT {$table}.*, count({$table}.id) FROM {$table} - INNER JOIN {$assocTable} ON {$assocField} = {$table}.id - INNER JOIN tag ON {$assocTable}.tag_id = tag.id - WHERE tag.title IN ({$slots}) - GROUP BY {$table}.id - HAVING count({$table}.id) >= ? - {$addSql} - "; - - $bindings = array_merge( $tagList, array( $score ), $bindings ); - $rows = $this->adapter->get( $sql, $bindings ); - return $rows; - } - - /** - * @see QueryWriter::queryRecordCount - */ - public function queryRecordCount( $type, $conditions = array(), $addSql = NULL, $bindings = array() ) - { - $addSql = $this->glueSQLCondition( $addSql ); - - $table = $this->esc( $type ); - - $this->updateCache(); //check if cache chain has been broken - - $sql = $this->makeSQLFromConditions( $conditions, $bindings, $addSql ); - $sql = "SELECT COUNT(*) FROM {$table} {$sql} -- keep-cache"; - - return (int) $this->adapter->getCell( $sql, $bindings ); - } - - /** - * @see QueryWriter::queryRecordCountRelated - */ - public function queryRecordCountRelated( $sourceType, $destType, $linkID, $addSql = '', $bindings = array() ) - { - list( $sourceTable, $destTable, $linkTable, $sourceCol, $destCol ) = $this->getRelationalTablesAndColumns( $sourceType, $destType ); - - $this->updateCache(); //check if cache chain has been broken - - if ( $sourceType === $destType ) { - $sql = " - SELECT COUNT(*) FROM {$linkTable} - INNER JOIN {$destTable} ON - ( {$destTable}.id = {$linkTable}.{$destCol} AND {$linkTable}.{$sourceCol} = ? ) OR - ( {$destTable}.id = {$linkTable}.{$sourceCol} AND {$linkTable}.{$destCol} = ? ) - {$addSql} - -- keep-cache"; - - $bindings = array_merge( array( $linkID, $linkID ), $bindings ); - } else { - $sql = " - SELECT COUNT(*) FROM {$linkTable} - INNER JOIN {$destTable} ON - ( {$destTable}.id = {$linkTable}.{$destCol} AND {$linkTable}.{$sourceCol} = ? ) - {$addSql} - -- keep-cache"; - - $bindings = array_merge( array( $linkID ), $bindings ); - } - - return (int) $this->adapter->getCell( $sql, $bindings ); - } - - /** - * @see QueryWriter::deleteRecord - */ - public function deleteRecord( $type, $conditions = array(), $addSql = NULL, $bindings = array() ) - { - $addSql = $this->glueSQLCondition( $addSql ); - - $table = $this->esc( $type ); - - $sql = $this->makeSQLFromConditions( $conditions, $bindings, $addSql ); - $sql = "DELETE FROM {$table} {$sql}"; - - $this->adapter->exec( $sql, $bindings ); - } - - /** - * @see QueryWriter::deleteRelations - */ - public function deleteRelations( $sourceType, $destType, $sourceID ) - { - list( $sourceTable, $destTable, $linkTable, $sourceCol, $destCol ) = $this->getRelationalTablesAndColumns( $sourceType, $destType ); - - if ( $sourceTable === $destTable ) { - $sql = "DELETE FROM {$linkTable} - WHERE ( {$sourceCol} = ? ) OR - ( {$destCol} = ? ) - "; - - $this->adapter->exec( $sql, array( $sourceID, $sourceID ) ); - } else { - $sql = "DELETE FROM {$linkTable} - WHERE {$sourceCol} = ? "; - - $this->adapter->exec( $sql, array( $sourceID ) ); - } - } - - /** - * @see QueryWriter::widenColumn - */ - public function widenColumn( $type, $property, $dataType ) - { - if ( !isset($this->typeno_sqltype[$dataType]) ) return FALSE; - - $table = $this->esc( $type ); - $column = $this->esc( $property ); - - $newType = $this->typeno_sqltype[$dataType]; - - $this->adapter->exec( "ALTER TABLE $table CHANGE $column $column $newType " ); - - return TRUE; - } - - /** - * @see QueryWriter::wipe - */ - public function wipe( $type ) - { - $table = $this->esc( $type ); - - $this->adapter->exec( "TRUNCATE $table " ); - } - - /** - * @see QueryWriter::renameAssocTable - */ - public function renameAssocTable( $from, $to = NULL ) - { - self::renameAssociation( $from, $to ); - } - - /** - * @see QueryWriter::getAssocTable - */ - public function getAssocTable( $types ) - { - return self::getAssocTableFormat( $types ); - } - - /** - * Turns caching on or off. Default: off. - * If caching is turned on retrieval queries fired after eachother will - * use a result row cache. - * - * @param boolean - * - * @return void - */ - public function setUseCache( $yesNo ) - { - $this->flushCache(); - - $this->flagUseCache = (bool) $yesNo; - } - - /** - * Flushes the Query Writer Cache. - * Clears the internal query cache array and returns its overall - * size. - * - * @return integer - */ - public function flushCache( $newMaxCacheSizePerType = NULL ) - { - if ( !is_null( $newMaxCacheSizePerType ) && $newMaxCacheSizePerType > 0 ) { - $this->maxCacheSizePerType = $newMaxCacheSizePerType; - } - $count = count( $this->cache, COUNT_RECURSIVE ); - $this->cache = array(); - return $count; - } - - /** - * @deprecated Use esc() instead. - * - * @param string $column column to be escaped - * @param boolean $noQuotes omit quotes - * - * @return string - */ - public function safeColumn( $column, $noQuotes = FALSE ) - { - return $this->esc( $column, $noQuotes ); - } - - /** - * @deprecated Use esc() instead. - * - * @param string $table table to be escaped - * @param boolean $noQuotes omit quotes - * - * @return string - */ - public function safeTable( $table, $noQuotes = FALSE ) - { - return $this->esc( $table, $noQuotes ); - } - - /** - * @see QueryWriter::inferFetchType - */ - public function inferFetchType( $type, $property ) - { - $type = $this->esc( $type, TRUE ); - $field = $this->esc( $property, TRUE ) . '_id'; - $keys = $this->getKeyMapForType( $type ); - - foreach( $keys as $key ) { - if ( - $key['from'] === $field - ) return $key['table']; - } - return NULL; - } - - /** - * @see QueryWriter::addUniqueConstraint - */ - public function addUniqueIndex( $type, $properties ) - { - return $this->addUniqueConstraint( $type, $properties ); - } -}