/** * Creates a criteria object from a method name and a value as * a criterion. * * @param string $methodName * @param mixed $criterion * @return stdClass * @throws PIECE_ORM_ERROR_UNEXPECTED_VALUE */ function &_createCriteria($methodName, $criterion) { if (preg_match('/By(.+)$/', $methodName, $matches)) { $criteria =& new stdClass(); $criteria->{Piece_ORM_Inflector::lowercaseFirstLetter($matches[1])} = $criterion; return $criteria; } else { Piece_ORM_Error::push(PIECE_ORM_ERROR_UNEXPECTED_VALUE, "An unexpected value detected. {$methodName}() can only receive object or null. Or the method name does not contain the appropriate field name."); $return = null; return $return; } }
/** * Creates a Piece_ORM_Config object from a configuration file or * a cache. * * @param string $configDirectory * @param string $cacheDirectory * @return Piece_ORM_Config * @static */ function &factory($configDirectory = null, $cacheDirectory = null) { if (is_null($configDirectory)) { $config =& new Piece_ORM_Config(); return $config; } if (!file_exists($configDirectory)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, "The configuration directory [ {$configDirectory} ] not found."); $return = null; return $return; } $configFile = "{$configDirectory}/piece-orm-config.yaml"; if (!file_exists($configFile)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, "The configuration file [ {$configFile} ] not found."); $return = null; return $return; } if (!is_readable($configFile)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_READABLE, "The configuration file [ {$configFile} ] is not readable."); $return = null; return $return; } if (is_null($cacheDirectory)) { return Piece_ORM_Config_Factory::_createConfigurationFromFile($configFile); } if (!file_exists($cacheDirectory)) { trigger_error("The cache directory [ {$cacheDirectory} ] is not found.", E_USER_WARNING); return Piece_ORM_Config_Factory::_createConfigurationFromFile($configFile); } if (!is_readable($cacheDirectory) || !is_writable($cacheDirectory)) { trigger_error("The cache directory [ {$cacheDirectory} ] is not readable or writable.", E_USER_WARNING); return Piece_ORM_Config_Factory::_createConfigurationFromFile($configFile); } return Piece_ORM_Config_Factory::_getConfiguration($configFile, $cacheDirectory); }
/** * Removes associated objects from a table. * * @param array $relationship * @throws PIECE_ORM_ERROR_INVALID_CONFIGURATION */ function delete($relationship) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, "This operation does not supported for the relationship type [ {$relationship['type']} ]. Please check your configuration."); }
/** * Executes a query. * * @param string $query * @param MDB2_Statement_Common $sth * @return MDB2_Result_Common|integer * @throws PIECE_ORM_ERROR_CANNOT_INVOKE * @throws PIECE_ORM_ERROR_UNEXPECTED_VALUE * @throws PIECE_ORM_ERROR_CONSTRAINT */ function &execute($query, $sth) { $dbh =& $this->_mapper->getConnection(); PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); if (!$this->_isManip) { $result =& $dbh->query($query); } else { if (is_null($sth)) { $result = $dbh->exec($query); } else { if (!is_subclass_of($sth, 'MDB2_Statement_Common')) { PEAR::staticPopErrorHandling(); Piece_ORM_Error::push(PIECE_ORM_ERROR_UNEXPECTED_VALUE, 'An unexpected value detected. executeQuery() with a prepared statement can only receive a MDB2_Statement_Common object.'); $return = null; return $return; } $result = $sth->execute(); } } PEAR::staticPopErrorHandling(); $this->_mapper->setLastQuery($dbh->last_query); if (MDB2::isError($result)) { if ($result->getCode() == MDB2_ERROR_CONSTRAINT) { $code = PIECE_ORM_ERROR_CONSTRAINT; } else { $code = PIECE_ORM_ERROR_CANNOT_INVOKE; } Piece_ORM_Error::pushPEARError($result, $code, "Failed to invoke MDB2_Driver_{$dbh->phptype}::query() for any reasons."); $return = null; return $return; } return $result; }
/** * Normalizes a relationship definition. * * @return array * @throws PIECE_ORM_ERROR_INVALID_CONFIGURATION * @throws PIECE_ORM_ERROR_NOT_FOUND */ function normalize() { if (!array_key_exists('table', $this->_relationship)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'The element [ table ] is required to generate a relationship property declaration.'); return; } if (!array_key_exists('mappedAs', $this->_relationship)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'The element [ mappedAs ] is required to generate a relationship property declaration.'); return; } $this->_relationshipMetadata =& Piece_ORM_Metadata_Factory::factory($this->_relationship['table']); if (Piece_ORM_Error::hasErrors()) { return; } if ($this->_checkHavingSinglePrimaryKey()) { if (!$this->_relationshipMetadata->getPrimaryKey()) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, 'A single primary key field is required in the table [ ' . $this->_relationshipMetadata->getTableName(true) . ' ].'); return; } } if (!array_key_exists('column', $this->_relationship)) { if (!$this->_normalizeColumn()) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'A single primary key field is required, if the element [ column ] in the element [ relationship ] omit.'); return; } } if (!$this->_relationshipMetadata->hasField($this->_relationship['column'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, "The field [ {$this->_relationship['column']} ] not found in the table [ " . $this->_relationshipMetadata->getTableName(true) . ' ].'); return; } if (!array_key_exists('referencedColumn', $this->_relationship)) { if (!$this->_normalizeReferencedColumn()) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'A single primary key field is required, if the element [ referencedColumn ] in the element [ relationship ] omit.'); return; } } if ($this->_referencedColumnRequired && !$this->_metadata->hasField($this->_relationship['referencedColumn'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, "The field [ {$this->_relationship['referencedColumn']} ] not found in the table [ " . $this->_metadata->getTableName(true) . ' ].'); return; } if (!array_key_exists('orderBy', $this->_relationship)) { $this->_relationship['orderBy'] = null; } $this->_normalizeOrderBy(); $this->_normalizeThrough(); if (Piece_ORM_Error::hasErrors()) { return; } return $this->_relationship; }
/** * Adds a PEAR error to the stack for the package. * * @param PEAR_Error $error * @param integer $code * @param string $message * @param string $level * @param array $params * @param array $backtrace */ function pushPEARError($error, $code, $message = false, $level = 'exception', $params = array(), $backtrace = false) { $time = explode(' ', microtime()); $time = $time[1] + $time[0]; if (!$backtrace) { $backtrace = debug_backtrace(); } Piece_ORM_Error::push($code, $message, 'exception', $params, array('code' => $error->getCode(), 'message' => $error->getMessage(), 'params' => array('userinfo' => $error->getUserInfo(), 'debuginfo' => $error->getDebugInfo()), 'package' => 'PEAR', 'level' => 'exception', 'time' => $time), $backtrace); }
/** * Loads a mapper class based on the given information. * * @param string $mapperID * @param string $mapperName * @throws PIECE_ORM_ERROR_INVALID_OPERATION * @throws PIECE_ORM_ERROR_NOT_FOUND * @throws PIECE_ORM_ERROR_NOT_READABLE */ function _load($mapperID, $mapperName) { if (Piece_ORM_Mapper_Factory::_loaded($mapperID)) { return; } if (is_null($GLOBALS['PIECE_ORM_Mapper_ConfigDirectory'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_OPERATION, 'The configuration directory must be specified.'); return; } if (!file_exists($GLOBALS['PIECE_ORM_Mapper_ConfigDirectory'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, "The configuration directory [ {$GLOBALS['PIECE_ORM_Mapper_ConfigDirectory']} ] not found."); return; } if (is_null($GLOBALS['PIECE_ORM_Mapper_CacheDirectory'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_OPERATION, 'The cache directory must be specified.'); return; } if (!file_exists($GLOBALS['PIECE_ORM_Mapper_CacheDirectory'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, "The cache directory [ {$GLOBALS['PIECE_ORM_Mapper_CacheDirectory']} ] not found."); return; } if (!is_readable($GLOBALS['PIECE_ORM_Mapper_CacheDirectory']) || !is_writable($GLOBALS['PIECE_ORM_Mapper_CacheDirectory'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_READABLE, "The cache directory [ {$GLOBALS['PIECE_ORM_Mapper_CacheDirectory']} ] is not readable or writable."); return; } $configFile = "{$GLOBALS['PIECE_ORM_Mapper_ConfigDirectory']}/{$mapperName}.yaml"; if (!file_exists($configFile)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, "The configuration file [ {$configFile} ] not found."); return; } if (!is_readable($configFile)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_READABLE, "The configuration file [ {$configFile} ] is not readable."); return; } $mapperSource = Piece_ORM_Mapper_Factory::_getMapperSource($mapperID, $mapperName, $configFile); if (Piece_ORM_Error::hasErrors()) { return; } eval($mapperSource); if (!Piece_ORM_Mapper_Factory::_loaded($mapperID)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, "The mapper [ {$mapperName} ] not found."); } }
/** * Normalizes "through" definition. * * @throws PIECE_ORM_ERROR_INVALID_CONFIGURATION */ function _normalizeThrough() { if (!array_key_exists('through', $this->_relationship)) { $this->_relationship['through'] = array(); } if (!array_key_exists('table', $this->_relationship['through'])) { $throughTableName1 = $this->_metadata->getTableName(true) . "_{$this->_relationship['table']}"; $throughTableName2 = "{$this->_relationship['table']}_" . $this->_metadata->getTableName(true); foreach (array($throughTableName1, $throughTableName2) as $throughTableName) { Piece_ORM_Error::disableCallback(); $throughMetadata =& Piece_ORM_Metadata_Factory::factory($throughTableName); Piece_ORM_Error::enableCallback(); if (Piece_ORM_Error::hasErrors()) { $error = Piece_ORM_Error::pop(); if ($error['code'] != PIECE_ORM_ERROR_NOT_FOUND) { Piece_ORM_Error::push($error['code'], $error['message'], 'exception', array(), $error); return; } continue; } $this->_relationship['through']['table'] = $throughTableName; break; } if (!$throughMetadata) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, "One of [ {$throughTableName1} ] or [ {$throughTableName2} ] must exists in the database, if the element [ table ] in the element [ through ] omit."); return; } } $throughMetadata =& Piece_ORM_Metadata_Factory::factory($this->_relationship['through']['table']); if (Piece_ORM_Error::hasErrors()) { return; } if (!array_key_exists('column', $this->_relationship['through'])) { if ($primaryKey = $this->_metadata->getPrimaryKey()) { $this->_relationship['through']['column'] = $this->_metadata->getTableName(true) . "_{$primaryKey}"; } else { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'A single primary key field is required, if the element [ column ] in the element [ through ] omit.'); return; } } if (!$throughMetadata->hasField($this->_relationship['through']['column'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, "The field [ {$this->_relationship['through']['column']} ] not found in the table [ " . $throughMetadata->getTableName(true) . ' ].'); return; } if (!array_key_exists('referencedColumn', $this->_relationship['through'])) { if ($primaryKey = $this->_metadata->getPrimaryKey()) { $this->_relationship['through']['referencedColumn'] = $primaryKey; } else { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'A single primary key field is required, if the element [ referencedColumn ] in the element [ through ] omit.'); return; } } if (!$this->_metadata->hasField($this->_relationship['through']['referencedColumn'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, "The field [ {$this->_relationship['through']['referencedColumn']} ] not found in the table [ " . $this->_metadata->getTableName(true) . ' ].'); return; } if (!array_key_exists('inverseColumn', $this->_relationship['through'])) { if ($primaryKey = $this->_relationshipMetadata->getPrimaryKey()) { $this->_relationship['through']['inverseColumn'] = $this->_relationshipMetadata->getTableName(true) . "_{$primaryKey}"; } else { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'A single primary key field is required, if the element [ column ] in the element [ through ] omit.'); return; } } if (!$throughMetadata->hasField($this->_relationship['through']['inverseColumn'])) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, "The field [ {$this->_relationship['through']['inverseColumn']} ] not found in the table [ " . $throughMetadata->getTableName(true) . ' ].'); return; } }
/** * Adds a findOneXXX method and its query to the mapper source. * * @param string $methodName * @param string $query * @param string $orderBy * @throws PIECE_ORM_ERROR_INVALID_CONFIGURATION */ function _addFindOne($methodName, $query, $orderBy) { if (!$query) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_CONFIGURATION, 'The element [ query ] or its value is required to generate a findOne method declaration.'); return; } $propertyName = strtolower($methodName); $this->_propertyDefinitions['query'][$propertyName] = $this->_generateQueryPropertyDeclaration($propertyName, $query); $this->_propertyDefinitions['orderBy'][$propertyName] = $this->_generateOrderByPropertyDeclaration($propertyName, $orderBy); $this->_methodDefinitions[strtolower($methodName)] = "\n function {$methodName}(\$criteria = null)\n {\n return \$this->_findOne('{$methodName}', \$criteria);\n }"; }
/** * Removes an object from a table. * * @param string $methodName * @return integer * @throws PIECE_ORM_ERROR_UNEXPECTED_VALUE */ function delete($methodName) { if (!is_object($this->_subject)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_UNEXPECTED_VALUE, "An unexpected value detected. {$methodName}() cannot receive non-object."); return; } if ($this->_metadata->hasPrimaryKey() && !$this->_validatePrimaryValues()) { Piece_ORM_Error::push(PIECE_ORM_ERROR_UNEXPECTED_VALUE, "An unexpected value detected. Correct values are required for the primary keys to invoke {$methodName}()."); return; } foreach ($this->_relationships as $relationship) { $this->_associatedObjectPersisters[$relationship['type']]->delete($relationship); if (Piece_ORM_Error::hasErrors()) { return; } } return $this->_mapper->executeQueryWithCriteria($methodName, $this->_subject, true); }
/** * Loads the LOB data of this field. * * @return string * @throws PIECE_ORM_ERROR_CANNOT_INVOKE * @throws PIECE_ORM_ERROR_UNEXPECTED_VALUE */ function load() { PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $datatype =& $this->_dbh->loadModule('Datatype'); PEAR::staticPopErrorHandling(); if (MDB2::isError($datatype)) { Piece_ORM_Error::pushPEARError($datatype, PIECE_ORM_ERROR_CANNOT_INVOKE, 'Failed to invoke $dbh->loadModule() for any reasons.'); return; } PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $lob = $datatype->convertResult($this->_value, $this->_metadata->getDatatype($this->_fieldName)); PEAR::staticPopErrorHandling(); if (MDB2::isError($lob)) { Piece_ORM_Error::pushPEARError($lob, PIECE_ORM_ERROR_CANNOT_INVOKE, 'Failed to invoke $datatype->convertResult() for any reasons.'); return; } if (!is_resource($lob)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_UNEXPECTED_VALUE, 'An unexpected value detected. $datatype->convertResult() should return a resource.'); return; } $data = ''; while (!feof($lob)) { $data .= fread($lob, 8192); } $datatype->destroyLOB($lob); return $data; }
/** * Sets a database as the current database. * * @param string $database * @throws PIECE_ORM_ERROR_NOT_FOUND */ function setDatabase($database) { if (!$this->_config->checkDatabase($database)) { Piece_ORM_Error::push(PIECE_ORM_ERROR_NOT_FOUND, "The given database [ {$database} ] not found in the current configuration."); return; } $this->_database = $database; $directorySuffix = $this->_config->getDirectorySuffix($this->_database); if (is_null($directorySuffix) || !strlen($directorySuffix)) { Piece_ORM_Mapper_Factory::setConfigDirectory($this->_mapperConfigDirectory); } else { Piece_ORM_Mapper_Factory::setConfigDirectory("{$this->_mapperConfigDirectory}/{$directorySuffix}"); } }
/** * Creates an object from the metadata. * * @param string $mapperName * @return stdClass * @throws PIECE_ORM_ERROR_INVALID_OPERATION */ function &createObject($mapperName) { if (!$GLOBALS['PIECE_ORM_Configured']) { Piece_ORM_Error::push(PIECE_ORM_ERROR_INVALID_OPERATION, __FUNCTION__ . ' method must be called after calling configure().'); $return = null; return $return; } $mapper =& Piece_ORM_Mapper_Factory::factory($mapperName); if (Piece_ORM_Error::hasErrors()) { $return = null; return $return; } return $mapper->createObject(); }