本文整理汇总了PHP中Drupal\Core\Database\Connection::startTransaction方法的典型用法代码示例。如果您正苦于以下问题:PHP Connection::startTransaction方法的具体用法?PHP Connection::startTransaction怎么用?PHP Connection::startTransaction使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类Drupal\Core\Database\Connection
的用法示例。
在下文中一共展示了Connection::startTransaction方法的12个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的PHP代码示例。
示例1: doSave
/**
* Saves a link without clearing caches.
*
* @param array $link
* A definition, according to $definitionFields, for a
* \Drupal\Core\Menu\MenuLinkInterface plugin.
*
* @return array
* The menu names affected by the save operation. This will be one menu
* name if the link is saved to the sane menu, or two if it is saved to a
* new menu.
*
* @throws \Exception
* Thrown if the storage back-end does not exist and could not be created.
* @throws \Drupal\Component\Plugin\Exception\PluginException
* Thrown if the definition is invalid, for example, if the specified parent
* would cause the links children to be moved to greater than the maximum
* depth.
*/
protected function doSave(array $link)
{
$original = $this->loadFull($link['id']);
// @todo Should we just return here if the link values match the original
// values completely?
// https://www.drupal.org/node/2302137
$affected_menus = array();
$transaction = $this->connection->startTransaction();
try {
if ($original) {
$link['mlid'] = $original['mlid'];
$link['has_children'] = $original['has_children'];
$affected_menus[$original['menu_name']] = $original['menu_name'];
} else {
// Generate a new mlid.
$options = array('return' => Database::RETURN_INSERT_ID) + $this->options;
$link['mlid'] = $this->connection->insert($this->table, $options)->fields(array('id' => $link['id'], 'menu_name' => $link['menu_name']))->execute();
}
$fields = $this->preSave($link, $original);
// We may be moving the link to a new menu.
$affected_menus[$fields['menu_name']] = $fields['menu_name'];
$query = $this->connection->update($this->table, $this->options);
$query->condition('mlid', $link['mlid']);
$query->fields($fields)->execute();
if ($original) {
$this->updateParentalStatus($original);
}
$this->updateParentalStatus($link);
} catch (\Exception $e) {
$transaction->rollback();
throw $e;
}
return $affected_menus;
}
示例2: setMultiple
/**
* {@inheritdoc}
*/
public function setMultiple(array $items)
{
// Use a transaction so that the database can write the changes in a single
// commit.
$transaction = $this->connection->startTransaction();
try {
// Delete all items first so we can do one insert. Rather than multiple
// merge queries.
$this->deleteMultiple(array_keys($items));
$query = $this->connection->insert($this->bin)->fields(array('cid', 'data', 'expire', 'created', 'serialized', 'tags', 'checksum'));
foreach ($items as $cid => $item) {
$item += array('expire' => CacheBackendInterface::CACHE_PERMANENT, 'tags' => array());
Cache::validateTags($item['tags']);
$item['tags'] = array_unique($item['tags']);
// Sort the cache tags so that they are stored consistently in the DB.
sort($item['tags']);
$fields = array('cid' => $cid, 'expire' => $item['expire'], 'created' => round(microtime(TRUE), 3), 'tags' => implode(' ', $item['tags']), 'checksum' => $this->checksumProvider->getCurrentChecksum($item['tags']));
if (!is_string($item['data'])) {
$fields['data'] = serialize($item['data']);
$fields['serialized'] = 1;
} else {
$fields['data'] = $item['data'];
$fields['serialized'] = 0;
}
$query->values($fields);
}
$query->execute();
} catch (\Exception $e) {
$transaction->rollback();
// @todo Log something here or just re throw?
throw $e;
}
}
示例3: dump
/**
* Dumps a set of routes to the router table in the database.
*
* Available options:
* - provider: The route grouping that is being dumped. All existing
* routes with this provider will be deleted on dump.
* - base_class: The base class name.
*
* @param array $options
* An array of options.
*/
public function dump(array $options = array())
{
// Convert all of the routes into database records.
// Accumulate the menu masks on top of any we found before.
$masks = array_flip($this->state->get('routing.menu_masks.' . $this->tableName, array()));
// Delete any old records first, then insert the new ones. That avoids
// stale data. The transaction makes it atomic to avoid unstable router
// states due to random failures.
$transaction = $this->connection->startTransaction();
try {
// We don't use truncate, because it is not guaranteed to be transaction
// safe.
try {
$this->connection->delete($this->tableName)->execute();
} catch (\Exception $e) {
$this->ensureTableExists();
}
// Split the routes into chunks to avoid big INSERT queries.
$route_chunks = array_chunk($this->routes->all(), 50, TRUE);
foreach ($route_chunks as $routes) {
$insert = $this->connection->insert($this->tableName)->fields(array('name', 'fit', 'path', 'pattern_outline', 'number_parts', 'route'));
$names = array();
foreach ($routes as $name => $route) {
/** @var \Symfony\Component\Routing\Route $route */
$route->setOption('compiler_class', '\\Drupal\\Core\\Routing\\RouteCompiler');
/** @var \Drupal\Core\Routing\CompiledRoute $compiled */
$compiled = $route->compile();
// The fit value is a binary number which has 1 at every fixed path
// position and 0 where there is a wildcard. We keep track of all such
// patterns that exist so that we can minimize the number of path
// patterns we need to check in the RouteProvider.
$masks[$compiled->getFit()] = 1;
$names[] = $name;
$values = array('name' => $name, 'fit' => $compiled->getFit(), 'path' => $route->getPath(), 'pattern_outline' => $compiled->getPatternOutline(), 'number_parts' => $compiled->getNumParts(), 'route' => serialize($route));
$insert->values($values);
}
// Insert all new routes.
$insert->execute();
}
} catch (\Exception $e) {
$transaction->rollback();
watchdog_exception('Routing', $e);
throw $e;
}
// Sort the masks so they are in order of descending fit.
$masks = array_keys($masks);
rsort($masks);
$this->state->set('routing.menu_masks.' . $this->tableName, $masks);
$this->routes = NULL;
}
示例4: save
/**
* {@inheritdoc}
*/
public function save(EntityInterface $entity)
{
$transaction = $this->database->startTransaction();
try {
$return = parent::save($entity);
// Ignore replica server temporarily.
db_ignore_replica();
return $return;
} catch (\Exception $e) {
$transaction->rollback();
watchdog_exception($this->entityTypeId, $e);
throw new EntityStorageException($e->getMessage(), $e->getCode(), $e);
}
}
示例5: setMultiple
/**
* {@inheritdoc}
*/
public function setMultiple(array $items)
{
$deleted_tags =& drupal_static('Drupal\\Core\\Cache\\DatabaseBackend::deletedTags', array());
$invalidated_tags =& drupal_static('Drupal\\Core\\Cache\\DatabaseBackend::invalidatedTags', array());
// Use a transaction so that the database can write the changes in a single
// commit.
$transaction = $this->connection->startTransaction();
try {
// Delete all items first so we can do one insert. Rather than multiple
// merge queries.
$this->deleteMultiple(array_keys($items));
$query = $this->connection->insert($this->bin)->fields(array('cid', 'data', 'expire', 'created', 'serialized', 'tags', 'checksum_invalidations', 'checksum_deletions'));
foreach ($items as $cid => $item) {
$item += array('expire' => CacheBackendInterface::CACHE_PERMANENT, 'tags' => array());
Cache::validateTags($item['tags']);
$item['tags'] = array_unique($item['tags']);
// Sort the cache tags so that they are stored consistently in the DB.
sort($item['tags']);
// Remove tags that were already deleted or invalidated during this
// request from the static caches so that another deletion or
// invalidation can occur.
foreach ($item['tags'] as $tag) {
if (isset($deleted_tags[$tag])) {
unset($deleted_tags[$tag]);
}
if (isset($invalidated_tags[$tag])) {
unset($invalidated_tags[$tag]);
}
}
$checksum = $this->checksumTags($item['tags']);
$fields = array('cid' => $cid, 'expire' => $item['expire'], 'created' => round(microtime(TRUE), 3), 'tags' => implode(' ', $item['tags']), 'checksum_invalidations' => $checksum['invalidations'], 'checksum_deletions' => $checksum['deletions']);
if (!is_string($item['data'])) {
$fields['data'] = serialize($item['data']);
$fields['serialized'] = 1;
} else {
$fields['data'] = $item['data'];
$fields['serialized'] = 0;
}
$query->values($fields);
}
$query->execute();
} catch (\Exception $e) {
$transaction->rollback();
// @todo Log something here or just re throw?
throw $e;
}
}
示例6: setMultiple
/**
* {@inheritdoc}
*/
public function setMultiple(array $items)
{
$values = array();
foreach ($items as $cid => $item) {
$item += array('expire' => CacheBackendInterface::CACHE_PERMANENT, 'tags' => array());
Cache::validateTags($item['tags']);
$item['tags'] = array_unique($item['tags']);
// Sort the cache tags so that they are stored consistently in the DB.
sort($item['tags']);
$fields = array('cid' => $cid, 'expire' => $item['expire'], 'created' => round(microtime(TRUE), 3), 'tags' => implode(' ', $item['tags']), 'checksum' => $this->checksumProvider->getCurrentChecksum($item['tags']));
if (!is_string($item['data'])) {
$fields['data'] = serialize($item['data']);
$fields['serialized'] = 1;
} else {
$fields['data'] = $item['data'];
$fields['serialized'] = 0;
}
$values[] = $fields;
}
// Use a transaction so that the database can write the changes in a single
// commit. The transaction is started after calculating the tag checksums
// since that can create a table and this causes an exception when using
// PostgreSQL.
$transaction = $this->connection->startTransaction();
try {
// Delete all items first so we can do one insert. Rather than multiple
// merge queries.
$this->deleteMultiple(array_keys($items));
$query = $this->connection->insert($this->bin)->fields(array('cid', 'expire', 'created', 'tags', 'checksum', 'data', 'serialized'));
foreach ($values as $fields) {
// Only pass the values since the order of $fields matches the order of
// the insert fields. This is a performance optimization to avoid
// unnecessary loops within the method.
$query->values(array_values($fields));
}
$query->execute();
} catch (\Exception $e) {
$transaction->rollback();
// @todo Log something here or just re throw?
throw $e;
}
}
示例7: updateSharedTableSchema
/**
* Updates the schema for a field stored in a shared table.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
* The storage definition of the field being updated.
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $original
* The original storage definition; i.e., the definition before the update.
*
* @throws \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException
* Thrown when the update to the field is forbidden.
* @throws \Exception
* Rethrown exception if the table recreation fails.
*/
protected function updateSharedTableSchema(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original)
{
if (!$this->storage->countFieldData($original, TRUE)) {
if ($this->database->supportsTransactionalDDL()) {
// If the database supports transactional DDL, we can go ahead and rely
// on it. If not, we will have to rollback manually if something fails.
$transaction = $this->database->startTransaction();
}
try {
// Since there is no data we may be switching from a dedicated table
// to a schema table schema, hence we should use the proper API.
$this->performFieldSchemaOperation('delete', $original);
$this->performFieldSchemaOperation('create', $storage_definition);
} catch (\Exception $e) {
if ($this->database->supportsTransactionalDDL()) {
$transaction->rollback();
} else {
// Recreate original schema.
$this->createSharedTableSchema($original);
}
throw $e;
}
} else {
if ($this->hasColumnChanges($storage_definition, $original)) {
throw new FieldStorageDefinitionUpdateForbiddenException('The SQL storage cannot change the schema for an existing field (' . $storage_definition->getName() . ' in ' . $storage_definition->getTargetEntityTypeId() . ' entity) with data.');
}
$updated_field_name = $storage_definition->getName();
$table_mapping = $this->storage->getTableMapping();
$column_names = $table_mapping->getColumnNames($updated_field_name);
$schema_handler = $this->database->schema();
// Iterate over the mapped table to find the ones that host the deleted
// field schema.
$original_schema = $this->loadFieldSchemaData($original);
$schema = array();
foreach ($table_mapping->getTableNames() as $table_name) {
foreach ($table_mapping->getFieldNames($table_name) as $field_name) {
if ($field_name == $updated_field_name) {
$schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names);
// Handle NOT NULL constraints.
foreach ($schema[$table_name]['fields'] as $column_name => $specifier) {
$not_null = !empty($specifier['not null']);
$original_not_null = !empty($original_schema[$table_name]['fields'][$column_name]['not null']);
if ($not_null !== $original_not_null) {
if ($not_null && $this->hasNullFieldPropertyData($table_name, $column_name)) {
throw new EntityStorageException("The {$column_name} column cannot have NOT NULL constraints as it holds NULL values.");
}
$column_schema = $original_schema[$table_name]['fields'][$column_name];
$column_schema['not null'] = $not_null;
$schema_handler->changeField($table_name, $field_name, $field_name, $column_schema);
}
}
// Drop original indexes and unique keys.
if (!empty($original_schema[$table_name]['indexes'])) {
foreach ($original_schema[$table_name]['indexes'] as $name => $specifier) {
$schema_handler->dropIndex($table_name, $name);
}
}
if (!empty($original_schema[$table_name]['unique keys'])) {
foreach ($original_schema[$table_name]['unique keys'] as $name => $specifier) {
$schema_handler->dropUniqueKey($table_name, $name);
}
}
// Create new indexes and unique keys.
if (!empty($schema[$table_name]['indexes'])) {
foreach ($schema[$table_name]['indexes'] as $name => $specifier) {
// Check if the index exists because it might already have been
// created as part of the earlier entity type update event.
$this->addIndex($table_name, $name, $specifier, $schema[$table_name]);
}
}
if (!empty($schema[$table_name]['unique keys'])) {
foreach ($schema[$table_name]['unique keys'] as $name => $specifier) {
$schema_handler->addUniqueKey($table_name, $name, $specifier);
}
}
// After deleting the field schema skip to the next table.
break;
}
}
}
$this->saveFieldSchemaData($storage_definition, $schema);
}
}
示例8: onFieldStorageDefinitionUpdate
/**
* {@inheritdoc}
*/
public function onFieldStorageDefinitionUpdate(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original)
{
if (!$storage_definition->hasData()) {
// There is no data. Re-create the tables completely.
if ($this->database->supportsTransactionalDDL()) {
// If the database supports transactional DDL, we can go ahead and rely
// on it. If not, we will have to rollback manually if something fails.
$transaction = $this->database->startTransaction();
}
try {
$original_schema = $this->_fieldSqlSchema($original);
foreach ($original_schema as $name => $table) {
$this->database->schema()->dropTable($name, $table);
}
$schema = $this->_fieldSqlSchema($storage_definition);
foreach ($schema as $name => $table) {
$this->database->schema()->createTable($name, $table);
}
} catch (\Exception $e) {
if ($this->database->supportsTransactionalDDL()) {
$transaction->rollback();
} else {
// Recreate tables.
$original_schema = $this->_fieldSqlSchema($original);
foreach ($original_schema as $name => $table) {
if (!$this->database->schema()->tableExists($name)) {
$this->database->schema()->createTable($name, $table);
}
}
}
throw $e;
}
} else {
if ($storage_definition->getColumns() != $original->getColumns()) {
throw new FieldStorageDefinitionUpdateForbiddenException("The SQL storage cannot change the schema for an existing field with data.");
}
// There is data, so there are no column changes. Drop all the prior
// indexes and create all the new ones, except for all the priors that
// exist unchanged.
$table = static::_fieldTableName($original);
$revision_table = static::_fieldRevisionTableName($original);
$schema = $storage_definition->getSchema();
$original_schema = $original->getSchema();
foreach ($original_schema['indexes'] as $name => $columns) {
if (!isset($schema['indexes'][$name]) || $columns != $schema['indexes'][$name]) {
$real_name = static::_fieldIndexName($storage_definition, $name);
$this->database->schema()->dropIndex($table, $real_name);
$this->database->schema()->dropIndex($revision_table, $real_name);
}
}
$table = static::_fieldTableName($storage_definition);
$revision_table = static::_fieldRevisionTableName($storage_definition);
foreach ($schema['indexes'] as $name => $columns) {
if (!isset($original_schema['indexes'][$name]) || $columns != $original_schema['indexes'][$name]) {
$real_name = static::_fieldIndexName($storage_definition, $name);
$real_columns = array();
foreach ($columns as $column_name) {
// Indexes can be specified as either a column name or an array with
// column name and length. Allow for either case.
if (is_array($column_name)) {
$real_columns[] = array(static::_fieldColumnName($storage_definition, $column_name[0]), $column_name[1]);
} else {
$real_columns[] = static::_fieldColumnName($storage_definition, $column_name);
}
}
$this->database->schema()->addIndex($table, $real_name, $real_columns);
$this->database->schema()->addIndex($revision_table, $real_name, $real_columns);
}
}
}
}
示例9: save
/**
* {@inheritdoc}
*/
public function save(EntityInterface $entity)
{
$transaction = $this->database->startTransaction();
try {
// Sync the changes made in the fields array to the internal values array.
$entity->updateOriginalValues();
$return = parent::save($entity);
// Ignore replica server temporarily.
db_ignore_replica();
return $return;
} catch (\Exception $e) {
$transaction->rollback();
watchdog_exception($this->entityTypeId, $e);
throw new EntityStorageException($e->getMessage(), $e->getCode(), $e);
}
}
示例10: updateSharedTableSchema
/**
* Updates the schema for a field stored in a shared table.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
* The storage definition of the field being updated.
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $original
* The original storage definition; i.e., the definition before the update.
*
* @throws \Drupal\Core\Entity\Exception\FieldStorageDefinitionUpdateForbiddenException
* Thrown when the update to the field is forbidden.
* @throws \Exception
* Rethrown exception if the table recreation fails.
*/
protected function updateSharedTableSchema(FieldStorageDefinitionInterface $storage_definition, FieldStorageDefinitionInterface $original)
{
if (!$this->storage->countFieldData($original, TRUE)) {
if ($this->database->supportsTransactionalDDL()) {
// If the database supports transactional DDL, we can go ahead and rely
// on it. If not, we will have to rollback manually if something fails.
$transaction = $this->database->startTransaction();
}
try {
// Since there is no data we may be switching from a dedicated table
// to a schema table schema, hence we should use the proper API.
$this->performFieldSchemaOperation('delete', $original);
$this->performFieldSchemaOperation('create', $storage_definition);
} catch (\Exception $e) {
if ($this->database->supportsTransactionalDDL()) {
$transaction->rollback();
} else {
// Recreate original schema.
$this->createSharedTableSchema($original);
}
throw $e;
}
} else {
if ($storage_definition->getColumns() != $original->getColumns()) {
throw new FieldStorageDefinitionUpdateForbiddenException("The SQL storage cannot change the schema for an existing field with data.");
}
$updated_field_name = $storage_definition->getName();
$table_mapping = $this->storage->getTableMapping();
$column_names = $table_mapping->getColumnNames($updated_field_name);
$schema_handler = $this->database->schema();
// Iterate over the mapped table to find the ones that host the deleted
// field schema.
$original_schema = $this->loadFieldSchemaData($original);
$schema = array();
foreach ($table_mapping->getTableNames() as $table_name) {
foreach ($table_mapping->getFieldNames($table_name) as $field_name) {
if ($field_name == $updated_field_name) {
$schema[$table_name] = $this->getSharedTableFieldSchema($storage_definition, $table_name, $column_names);
// Drop original indexes and unique keys.
if (!empty($original_schema[$table_name]['indexes'])) {
foreach ($original_schema[$table_name]['indexes'] as $name => $specifier) {
$schema_handler->dropIndex($table_name, $name);
}
}
if (!empty($original_schema[$table_name]['unique keys'])) {
foreach ($original_schema[$table_name]['unique keys'] as $name => $specifier) {
$schema_handler->dropUniqueKey($table_name, $name);
}
}
// Create new indexes and unique keys.
if (!empty($schema[$table_name]['indexes'])) {
foreach ($schema[$table_name]['indexes'] as $name => $specifier) {
$schema_handler->addIndex($table_name, $name, $specifier);
}
}
if (!empty($schema[$table_name]['unique keys'])) {
foreach ($schema[$table_name]['unique keys'] as $name => $specifier) {
$schema_handler->addUniqueKey($table_name, $name, $specifier);
}
}
// After deleting the field schema skip to the next table.
break;
}
}
}
$this->saveFieldSchemaData($storage_definition, $schema);
}
}
示例11: indexItem
/**
* Indexes a single item on the specified index.
*
* Used as a helper method in indexItems().
*
* @param \Drupal\search_api\IndexInterface $index
* The index for which the item is being indexed.
* @param string $id
* The item's ID.
* @param \Drupal\search_api\Item\ItemInterface $item
* The item to index.
*
* @throws \Exception
* Any encountered database (or other) exceptions are passed on, out of this
* method.
*/
protected function indexItem(IndexInterface $index, $id, ItemInterface $item) {
$fields = $this->getFieldInfo($index);
$fields_updated = FALSE;
$field_errors = array();
$db_info = $this->getIndexDbInfo($index);
$denormalized_table = $db_info['index_table'];
$txn = $this->database->startTransaction('search_api_indexing');
$text_table = $denormalized_table . '_text';
try {
$inserts = array();
$text_inserts = array();
foreach ($item->getFields() as $name => $field) {
$denormalized_value = NULL;
// Sometimes index changes are not triggering the update hooks
// correctly. Therefore, to avoid DB errors, we re-check the tables
// here before indexing.
if (empty($fields[$name]['table']) && !$fields_updated) {
unset($db_info['field_tables'][$name]);
$this->fieldsUpdated($index);
$fields_updated = TRUE;
$fields = $db_info['field_tables'];
}
if (empty($fields[$name]['table']) && empty($field_errors[$name])) {
// Log an error, but only once per field. Since a superfluous field is
// not too serious, we just index the rest of the item normally.
$field_errors[$name] = TRUE;
$this->getLogger()->warning("Unknown field @field: please check (and re-save) the index's fields settings.", array('@field' => $name));
continue;
}
$table = $fields[$name]['table'];
$boost = $fields[$name]['boost'];
$this->database->delete($table)
->condition('item_id', $id)
->execute();
$this->database->delete($denormalized_table)
->condition('item_id', $id)
->execute();
$type = $field->getType();
$value = array();
foreach ($field->getValues() as $field_value) {
$converted_value = $this->convert($field_value, $type, $field->getOriginalType(), $index);
// Don't add NULL values to the return array. Also, adding an empty
// array is, of course, a waste of time.
if (isset($converted_value) && $converted_value !== array()) {
$value = array_merge($value, is_array($converted_value) ? $converted_value : array($converted_value));
}
}
if (Utility::isTextType($type, array('text', 'tokenized_text'))) {
$words = array();
// Store the first 30 characters of the string as the denormalized
// value.
$field_value = $value;
$denormalized_value = '';
do {
$denormalized_value .= array_shift($field_value)['value'] . ' ';
} while (strlen($denormalized_value) < 30);
$denormalized_value = Unicode::truncateBytes(trim($denormalized_value), 30);
foreach ($value as $token) {
// Taken from core search to reflect less importance of words later
// in the text.
// Focus is a decaying value in terms of the amount of unique words
// up to this point. From 100 words and more, it decays, to e.g. 0.5
// at 500 words and 0.3 at 1000 words.
$focus = min(1, .01 + 3.5 / (2 + count($words) * .015));
$value = $token['value'];
if (is_numeric($value)) {
$value = ltrim($value, '-0');
}
elseif (Unicode::strlen($value) < $this->configuration['min_chars']) {
continue;
}
$value = Unicode::strtolower($value);
$token['score'] = $token['score'] * $focus;
if (!isset($words[$value])) {
$words[$value] = $token;
//.........这里部分代码省略.........
示例12: indexItem
/**
* Indexes a single item on the specified index.
*
* Used as a helper method in indexItems().
*
* @param \Drupal\search_api\IndexInterface $index
* The index for which the item is being indexed.
* @param \Drupal\search_api\Item\ItemInterface $item
* The item to index.
*
* @throws \Exception
* Any encountered database (or other) exceptions are passed on, out of this
* method.
*/
protected function indexItem(IndexInterface $index, ItemInterface $item)
{
$fields = $this->getFieldInfo($index);
$fields_updated = FALSE;
$field_errors = array();
$db_info = $this->getIndexDbInfo($index);
$denormalized_table = $db_info['index_table'];
$item_id = $item->getId();
$transaction = $this->database->startTransaction('search_api_db_indexing');
try {
// Remove the item from the denormalized table.
$this->database->delete($denormalized_table)->condition('item_id', $item_id)->execute();
$denormalized_values = array();
$text_inserts = array();
foreach ($item->getFields() as $field_id => $field) {
// Sometimes index changes are not triggering the update hooks
// correctly. Therefore, to avoid DB errors, we re-check the tables
// here before indexing.
if (empty($fields[$field_id]['table']) && !$fields_updated) {
unset($db_info['field_tables'][$field_id]);
$this->fieldsUpdated($index);
$fields_updated = TRUE;
$fields = $db_info['field_tables'];
}
if (empty($fields[$field_id]['table']) && empty($field_errors[$field_id])) {
// Log an error, but only once per field. Since a superfluous field is
// not too serious, we just index the rest of the item normally.
$field_errors[$field_id] = TRUE;
$this->getLogger()->warning("Unknown field @field: please check (and re-save) the index's fields settings.", array('@field' => $field_id));
continue;
}
$field_info = $fields[$field_id];
$table = $field_info['table'];
$column = $field_info['column'];
$this->database->delete($table)->condition('item_id', $item_id)->execute();
$type = $field->getType();
$values = array();
foreach ($field->getValues() as $field_value) {
$converted_value = $this->convert($field_value, $type, $field->getOriginalType(), $index);
// Don't add NULL values to the return array. Also, adding an empty
// array is, of course, a waste of time.
if (isset($converted_value) && $converted_value !== array()) {
$values = array_merge($values, is_array($converted_value) ? $converted_value : array($converted_value));
}
}
if (!$values) {
// SQLite sometimes has problems letting columns not present in an
// INSERT statement default to NULL, so we set NULL values for the
// denormalized table explicitly.
$denormalized_values[$column] = NULL;
continue;
}
// If the field contains more than one value, we remember that the field
// can be multi-valued.
if (count($values) > 1) {
$db_info['field_tables'][$field_id]['multi-valued'] = TRUE;
}
if (Utility::isTextType($type, array('text', 'tokenized_text'))) {
// Remember the text table the first time we encounter it.
if (!isset($text_table)) {
$text_table = $table;
}
$unique_tokens = array();
$denormalized_value = '';
foreach ($values as $token) {
$word = $token['value'];
$score = $token['score'];
// Store the first 30 characters of the string as the denormalized
// value.
if (strlen($denormalized_value) < 30) {
$denormalized_value .= $word . ' ';
}
// Skip words that are too short, except for numbers.
if (is_numeric($word)) {
$word = ltrim($word, '-0');
} elseif (Unicode::strlen($word) < $this->configuration['min_chars']) {
continue;
}
// Taken from core search to reflect less importance of words later
// in the text.
// Focus is a decaying value in terms of the amount of unique words
// up to this point. From 100 words and more, it decays, to e.g. 0.5
// at 500 words and 0.3 at 1000 words.
$score *= min(1, 0.01 + 3.5 / (2 + count($unique_tokens) * 0.015));
// Only insert each canonical base form of a word once.
$word_base_form = $this->dbmsCompatibility->preprocessIndexValue($word);
//.........这里部分代码省略.........