/** * {@inheritdoc} */ public function register($name, $window = 3600, $identifier = NULL) { if (!isset($identifier)) { $identifier = $this->requestStack->getCurrentRequest()->getClientIp(); } $this->connection->insert('flood')->fields(array('event' => $name, 'identifier' => $identifier, 'timestamp' => REQUEST_TIME, 'expiration' => REQUEST_TIME + $window))->execute(); }
/** * {@inheritdoc} */ public function create(ContentEntityInterface $entity, $fields) { $query = $this->database->insert('comment_entity_statistics')->fields(array('entity_id', 'entity_type', 'field_name', 'cid', 'last_comment_timestamp', 'last_comment_name', 'last_comment_uid', 'comment_count')); foreach ($fields as $field_name => $detail) { // Skip fields that entity does not have. if (!$entity->hasField($field_name)) { continue; } // Get the user ID from the entity if it's set, or default to the // currently logged in user. $last_comment_uid = 0; if ($entity instanceof EntityOwnerInterface) { $last_comment_uid = $entity->getOwnerId(); } if (!isset($last_comment_uid)) { // Default to current user when entity does not implement // EntityOwnerInterface or author is not set. $last_comment_uid = $this->currentUser->id(); } // Default to REQUEST_TIME when entity does not have a changed property. $last_comment_timestamp = REQUEST_TIME; if ($entity instanceof EntityChangedInterface) { $last_comment_timestamp = $entity->getChangedTime(); } $query->values(array('entity_id' => $entity->id(), 'entity_type' => $entity->getEntityTypeId(), 'field_name' => $field_name, 'cid' => 0, 'last_comment_timestamp' => $last_comment_timestamp, 'last_comment_name' => NULL, 'last_comment_uid' => $last_comment_uid, 'comment_count' => 0)); } $query->execute(); }
/** * {@inheritdoc} */ public function save($source, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid = NULL) { if ($source[0] !== '/') { throw new \InvalidArgumentException(sprintf('Source path %s has to start with a slash.', $source)); } if ($alias[0] !== '/') { throw new \InvalidArgumentException(sprintf('Alias path %s has to start with a slash.', $alias)); } $fields = array('source' => $source, 'alias' => $alias, 'langcode' => $langcode); // Insert or update the alias. if (empty($pid)) { $query = $this->connection->insert('url_alias')->fields($fields); $pid = $query->execute(); $fields['pid'] = $pid; $operation = 'insert'; } else { // Fetch the current values so that an update hook can identify what // exactly changed. $original = $this->connection->query('SELECT source, alias, langcode FROM {url_alias} WHERE pid = :pid', array(':pid' => $pid))->fetchAssoc(); $fields['pid'] = $pid; $query = $this->connection->update('url_alias')->fields($fields)->condition('pid', $pid); $pid = $query->execute(); $fields['original'] = $original; $operation = 'update'; } if ($pid) { // @todo Switch to using an event for this instead of a hook. $this->moduleHandler->invokeAll('path_' . $operation, array($fields)); Cache::invalidateTags(['route_match']); return $fields; } return FALSE; }
/** * {@inheritdoc} */ public function log($level, $message, array $context = array()) { // Remove any backtraces since they may contain an unserializable variable. unset($context['backtrace']); // Convert PSR3-style messages to SafeMarkup::format() style, so they can be // translated too in runtime. $message_placeholders = $this->parser->parseMessagePlaceholders($message, $context); try { $this->connection->insert('watchdog')->fields(array('uid' => $context['uid'], 'type' => Unicode::substr($context['channel'], 0, 64), 'message' => $message, 'variables' => serialize($message_placeholders), 'severity' => $level, 'link' => $context['link'], 'location' => $context['request_uri'], 'referer' => $context['referer'], 'hostname' => Unicode::substr($context['ip'], 0, 128), 'timestamp' => $context['timestamp']))->execute(); } catch (\Exception $e) { // When running Drupal on MySQL or MariaDB you can run into several errors // that corrupt the database connection. Some examples for these kind of // errors on the database layer are "1100 - Table 'xyz' was not locked // with LOCK TABLES" and "1153 - Got a packet bigger than // 'max_allowed_packet' bytes". If such an error happens, the MySQL server // invalidates the connection and answers all further requests in this // connection with "2006 - MySQL server had gone away". In that case the // insert statement above results in a database exception. To ensure that // the causal error is written to the log we try once to open a dedicated // connection and write again. if (($e instanceof DatabaseException || $e instanceof \PDOException) && $this->connection->getTarget() != self::DEDICATED_DBLOG_CONNECTION_TARGET) { // Open a dedicated connection for logging. $key = $this->connection->getKey(); $info = Database::getConnectionInfo($key); Database::addConnectionInfo($key, self::DEDICATED_DBLOG_CONNECTION_TARGET, $info['default']); $this->connection = Database::getConnection(self::DEDICATED_DBLOG_CONNECTION_TARGET, $key); // Now try once to log the error again. $this->log($level, $message, $context); } else { throw $e; } } }
/** * {@inheritdoc} */ public function log($level, $message, array $context = array()) { // Remove any backtraces since they may contain an unserializable variable. unset($context['backtrace']); // Convert PSR3-style messages to String::format() style, so they can be // translated too in runtime. $message_placeholders = $this->parser->parseMessagePlaceholders($message, $context); $this->database->insert('watchdog')->fields(array('uid' => $context['uid'], 'type' => substr($context['channel'], 0, 64), 'message' => $message, 'variables' => serialize($message_placeholders), 'severity' => $level, 'link' => substr($context['link'], 0, 255), 'location' => $context['request_uri'], 'referer' => $context['referer'], 'hostname' => substr($context['ip'], 0, 128), 'timestamp' => $context['timestamp']))->execute(); }
/** * {@inheritdoc} */ public function insert($entry) { $return_value = NULL; try { $return_value = $this->connection->insert('dbtng_example')->fields($entry)->execute(); } catch (\Exception $e) { drupal_set_message(t('db_insert failed. Message = %message, query= %query', array('%message' => $e->getMessage(), '%query' => $e->query_string)), 'error'); } return $return_value; }
/** * {@inheritdoc} */ public function save($source, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid = NULL) { if ($source[0] !== '/') { throw new \InvalidArgumentException(sprintf('Source path %s has to start with a slash.', $source)); } if ($alias[0] !== '/') { throw new \InvalidArgumentException(sprintf('Alias path %s has to start with a slash.', $alias)); } $fields = array('source' => $source, 'alias' => $alias, 'langcode' => $langcode); // Insert or update the alias. if (empty($pid)) { $try_again = FALSE; try { $query = $this->connection->insert(static::TABLE)->fields($fields); $pid = $query->execute(); } catch (\Exception $e) { // If there was an exception, try to create the table. if (!($try_again = $this->ensureTableExists())) { // If the exception happened for other reason than the missing table, // propagate the exception. throw $e; } } // Now that the table has been created, try again if necessary. if ($try_again) { $query = $this->connection->insert(static::TABLE)->fields($fields); $pid = $query->execute(); } $fields['pid'] = $pid; $operation = 'insert'; } else { // Fetch the current values so that an update hook can identify what // exactly changed. try { $original = $this->connection->query('SELECT source, alias, langcode FROM {url_alias} WHERE pid = :pid', array(':pid' => $pid))->fetchAssoc(); } catch (\Exception $e) { $this->catchException($e); $original = FALSE; } $fields['pid'] = $pid; $query = $this->connection->update(static::TABLE)->fields($fields)->condition('pid', $pid); $pid = $query->execute(); $fields['original'] = $original; $operation = 'update'; } if ($pid) { // @todo Switch to using an event for this instead of a hook. $this->moduleHandler->invokeAll('path_' . $operation, array($fields)); Cache::invalidateTags(['route_match']); return $fields; } return FALSE; }
/** * {@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; } }
/** * 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; }
/** * {@inheritdoc} */ public function acquire($name, $timeout = 30.0) { // Insure that the timeout is at least 1 ms. $timeout = max($timeout, 0.001); $expire = microtime(TRUE) + $timeout; if (isset($this->locks[$name])) { // Try to extend the expiration of a lock we already acquired. $success = (bool) $this->database->update('semaphore')->fields(array('expire' => $expire))->condition('name', $name)->condition('value', $this->getLockId())->execute(); if (!$success) { // The lock was broken. unset($this->locks[$name]); } return $success; } else { // Optimistically try to acquire the lock, then retry once if it fails. // The first time through the loop cannot be a retry. $retry = FALSE; // We always want to do this code at least once. do { try { $this->database->insert('semaphore')->fields(array('name' => $name, 'value' => $this->getLockId(), 'expire' => $expire))->execute(); // We track all acquired locks in the global variable. $this->locks[$name] = TRUE; // We never need to try again. $retry = FALSE; } catch (IntegrityConstraintViolationException $e) { // Suppress the error. If this is our first pass through the loop, // then $retry is FALSE. In this case, the insert failed because some // other request acquired the lock but did not release it. We decide // whether to retry by checking lockMayBeAvailable(). This will clear // the offending row from the database table in case it has expired. $retry = $retry ? FALSE : $this->lockMayBeAvailable($name); } catch (\Exception $e) { // Create the semaphore table if it does not exist and retry. if ($this->ensureTableExists()) { // Retry only once. $retry = !$retry; } else { throw $e; } } // We only retry in case the first attempt failed, but we then broke // an expired lock. } while ($retry); } return isset($this->locks[$name]); }
/** * Saves a single ID mapping row in the database. * * @param array $map * The row to save. */ protected function saveMap(array $map) { $table = 'migrate_map_sql_idmap_test'; $schema = $this->database->schema(); // If the table already exists, add any columns which are in the map array, // but don't yet exist in the table. Yay, flexibility! if ($schema->tableExists($table)) { foreach (array_keys($map) as $field) { if (!$schema->fieldExists($table, $field)) { $schema->addField($table, $field, ['type' => 'text']); } } } else { $schema->createTable($table, $this->createSchemaFromRow($map)); } $this->database->insert($table)->fields($map)->execute(); }
/** * Index. * @param \Drupal\user\UserInterface $user * @return array * @throws \Exception * @internal param string $uid */ public function index(UserInterface $user) { // See if the user already has an API key. $q = $this->database->select('api_keys', 'a')->fields('a'); $q->condition('a.uid', $user->id()); $user_key_object = $q->execute()->fetchObject(); if (!$user_key_object) { // The user does not have a key. Generate one for them. $user_key = sha1(uniqid()); // Insert it to the database. $this->database->insert('api_keys')->fields(array('uid' => $user->id(), 'user_key' => $user_key))->execute(); } else { $user_key = $user_key_object->user_key; } // Generate the URL which we should use in the CURL explaination. // @todo return ['#theme' => 'api-keys-user-keys', '#api_key' => $user_key, '#post_url' => 'example.com/entity/log', '#base_url' => Url::fromUserInput('/')->setOption('absolute', TRUE), '#markup' => $this->t('URL : !url and key: !key', ['!url' => $post_url, '!key' => $user_key])]; }
/** * Store the Session ID and ticket for single-log-out purposes. * * @param string $session_id * The session ID, to be used to kill the session later. * @param string $ticket * The CAS service ticket to be used as the lookup key. * * @codeCoverageIgnore */ protected function storeLoginSessionData($session_id, $ticket) { if ($this->settings->get('cas.settings')->get('logout.enable_single_logout') === TRUE) { $plainsid = $session_id; } else { $plainsid = ''; } $this->connection->insert('cas_login_data')->fields(array('sid', 'plainsid', 'ticket'), array(Crypt::hashBase64($session_id), $plainsid, $ticket))->execute(); }
/** * Responds to POST requests and saves the new record. * * @param array $record * An associative array of fields to insert into the database. * * @return \Drupal\rest\ModifiedResourceResponse * The HTTP response object. */ public function post($record) { $this->validate($record); $id = $this->dbConnection->insert('example_foo')->fields($record)->execute(); $this->logger->notice('New record has been created.'); $created_record = $this->loadRecord($id); // Return the newly created record in the response body. return new ModifiedResourceResponse($created_record, 201); }
/** * {@inheritdoc} */ public function updateIndex() { // Interpret the cron limit setting as the maximum number of nodes to index // per cron run. $limit = (int)$this->searchSettings->get('index.cron_limit'); $language = \Drupal::languageManager()->getCurrentLanguage()->getId(); $topics = $this->getSids($this->advancedHelp->getTopics()); // If we got interrupted by limit, this will contain the last module // and topic we looked at. $last = \Drupal::state()->get($this->getPluginId() . '.last_cron', ['time' => 0]); $count = 0; foreach ($topics as $module => $module_topics) { // Fast forward if necessary. if (!empty($last['module']) && $last['module'] != $module) { continue; } foreach ($module_topics as $topic => $info) { // Fast forward if necessary. if (!empty($last['topic']) && $last['topic'] != $topic) { continue; } //If we've been looking to catch up, and we have, reset so we // stop fast forwarding. if (!empty($last['module'])) { unset($last['topic']); unset($last['module']); } $file = $this->advancedHelp->getTopicFileName($module, $topic); if ($file && (empty($info['sid']) || filemtime($file) > $last['time'])) { if (empty($info['sid'])) { $info['sid'] = $this->database->insert('advanced_help_index') ->fields([ 'module' => $module, 'topic' => $topic, 'langcode' => $language ]) ->execute(); } } // Update index, using search index "type" equal to the plugin ID. search_index($this->getPluginId(), $info['sid'], $language, file_get_contents($file)); $count++; if ($count >= $limit) { $last['module'] = $module; $last['topic'] = $topic; \Drupal::state()->set($this->getPluginId() . '.last_cron', $last); return; } } } \Drupal::state()->set($this->getPluginId() . '.last_cron', ['time' => time()]); }
/** * {@inheritdoc} */ public function add(ServerInterface $server, $type, IndexInterface $index = NULL, $data = NULL) { $this->database->insert('search_api_task') ->fields(array( 'server_id' => $server->id(), 'type' => $type, 'index_id' => $index ? (is_object($index) ? $index->id() : $index) : NULL, 'data' => isset($data) ? serialize($data) : NULL, )) ->execute(); }
/** * {@inheritdoc} */ public function setSubscription(array &$data) { if (isset($data['lease']) && is_numeric($data['lease'])) { $data['expires'] = (int) REQUEST_TIME + $data['lease']; } else { // @todo Change schema to allow NULL values. $data['lease'] = 0; $data['expires'] = 0; } // Updating an existing subscription. if ($this->hasSubscription($data['id'])) { unset($data['created']); $this->connection->update($this->table)->fields($data)->condition('id', $data['id'])->execute(); return FALSE; } else { $data['secret'] = Crypt::randomStringHashed(55); $data['token'] = Crypt::randomStringHashed(55); $data['created'] = REQUEST_TIME; $this->connection->insert($this->table)->fields($data)->execute(); return TRUE; } }
/** * {@inheritdoc} */ public function save($source, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid = NULL) { $fields = array('source' => $source, 'alias' => $alias, 'langcode' => $langcode); // Insert or update the alias. if (empty($pid)) { $query = $this->connection->insert('url_alias')->fields($fields); $pid = $query->execute(); $fields['pid'] = $pid; $operation = 'insert'; } else { $fields['pid'] = $pid; $query = $this->connection->update('url_alias')->fields($fields)->condition('pid', $pid); $pid = $query->execute(); $operation = 'update'; } if ($pid) { // @todo Switch to using an event for this instead of a hook. $this->moduleHandler->invokeAll('path_' . $operation, array($fields)); return $fields; } return FALSE; }
/** * 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; }
/** * Creates a database record for a string object. * * @param \Drupal\locale\StringInterface $string * The string object. * * @return bool|int * If the operation failed, returns FALSE. * If it succeeded returns the last insert ID of the query, if one exists. * * @throws \Drupal\locale\StringStorageException * If the string is not suitable for this storage, an exception is thrown. */ protected function dbStringInsert($string) { if ($string->isSource()) { $string->setValues(array('context' => '', 'version' => 'none'), FALSE); $fields = $string->getValues(array('source', 'context', 'version')); } elseif ($string->isTranslation()) { $string->setValues(array('customized' => 0), FALSE); $fields = $string->getValues(array('lid', 'language', 'translation', 'customized')); } if (!empty($fields)) { return $this->connection->insert($this->dbStringTable($string), $this->options)->fields($fields)->execute(); } else { throw new StringStorageException('The string cannot be saved: ' . $string->getString()); } }
/** * {@inheritdoc} */ public function createIndex(NodeInterface $node) { $query = $this->database->insert('forum_index')->fields(array('nid', 'title', 'tid', 'sticky', 'created', 'comment_count', 'last_comment_timestamp')); foreach ($node->getTranslationLanguages() as $langcode => $language) { $translation = $node->getTranslation($langcode); foreach ($translation->taxonomy_forums as $item) { $query->values(array('nid' => $node->id(), 'title' => $translation->label(), 'tid' => $item->target_id, 'sticky' => (int) $node->isSticky(), 'created' => $node->getCreatedTime(), 'comment_count' => 0, 'last_comment_timestamp' => $node->getCreatedTime())); } } $query->execute(); // The logic for determining last_comment_count is fairly complex, so // update the index too. if ($node->isNew()) { $this->updateIndex($node); } }
/** * {@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; } }
/** * {@inheritdoc} */ public function saveBookLink(array $link, $new) { // Keep track of Book IDs for cache clear. $affected_bids[$link['bid']] = $link['bid']; $link += $this->getLinkDefaults($link['nid']); if ($new) { // Insert new. $this->connection->insert('book')->fields(array('nid' => $link['nid'], 'bid' => $link['bid'], 'pid' => $link['pid'], 'weight' => $link['weight']) + $this->getBookParents($link, (array) $this->loadBookLink($link['pid'], FALSE)))->execute(); // Update the has_children status of the parent. $this->updateParent($link); } else { $original = $this->loadBookLink($link['nid'], FALSE); // Using the Book ID as the key keeps this unique. $affected_bids[$original['bid']] = $original['bid']; // Handle links that are moving. if ($link['bid'] != $original['bid'] || $link['pid'] != $original['pid']) { // Update the bid for this page and all children. if ($link['pid'] == 0) { $link['depth'] = 1; $parent = array(); } elseif (($parent_link = $this->loadBookLink($link['pid'], FALSE)) && $parent_link['bid'] != $link['bid']) { $link['pid'] = $link['bid']; $parent = $this->loadBookLink($link['pid'], FALSE); $link['depth'] = $parent['depth'] + 1; } else { $parent = $this->loadBookLink($link['pid'], FALSE); $link['depth'] = $parent['depth'] + 1; } $this->setParents($link, $parent); $this->moveChildren($link, $original); // Update the has_children status of the original parent. $this->updateOriginalParent($original); // Update the has_children status of the new parent. $this->updateParent($link); } // Update the weight and pid. $query = $this->connection->update('book'); $query->fields(array('weight' => $link['weight'], 'pid' => $link['pid'], 'bid' => $link['bid'])); $query->condition('nid', $link['nid']); $query->execute(); } foreach ($affected_bids as $bid) { \Drupal::cache('data')->deleteTags(array('bid' => $bid)); } return $link; }
/** * Tests creating and deleting a bundle field if entities exist. * * This tests deletion when there are existing entities, but not existing data * for the field being deleted. * * @see testBundleFieldDeleteWithExistingData() */ public function testBundleFieldCreateDeleteWithExistingEntities() { // Save an entity. $name = $this->randomString(); $storage = $this->entityManager->getStorage('entity_test_update'); $entity = $storage->create(array('name' => $name)); $entity->save(); // Add a bundle field and run the update. Ensure the bundle field's table // is created and the prior saved entity data is still there. $this->addBundleField(); $this->entityDefinitionUpdateManager->applyUpdates(); $schema_handler = $this->database->schema(); $this->assertTrue($schema_handler->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table created for new_bundle_field.'); $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id()); $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field creation.'); // Remove the base field and run the update. Ensure the bundle field's // table is deleted and the prior saved entity data is still there. $this->removeBundleField(); $this->entityDefinitionUpdateManager->applyUpdates(); $this->assertFalse($schema_handler->tableExists('entity_test_update__new_bundle_field'), 'Dedicated table deleted for new_bundle_field.'); $entity = $this->entityManager->getStorage('entity_test_update')->load($entity->id()); $this->assertIdentical($entity->name->value, $name, 'Entity data preserved during field deletion.'); // Test that required columns are created as 'not null'. $this->addBundleField('shape_required'); $this->entityDefinitionUpdateManager->applyUpdates(); $message = 'The new_bundle_field_shape column is not nullable.'; $values = array('bundle' => $entity->bundle(), 'deleted' => 0, 'entity_id' => $entity->id(), 'revision_id' => $entity->id(), 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED, 'delta' => 0, 'new_bundle_field_color' => $this->randomString()); try { // Try to insert a record without providing a value for the 'not null' // column. This should fail. $this->database->insert('entity_test_update__new_bundle_field')->fields($values)->execute(); $this->fail($message); } catch (\RuntimeException $e) { if ($e instanceof DatabaseExceptionWrapper || $e instanceof IntegrityConstraintViolationException) { // Now provide a value for the 'not null' column. This is expected to // succeed. $values['new_bundle_field_shape'] = $this->randomString(); $this->database->insert('entity_test_update__new_bundle_field')->fields($values)->execute(); $this->pass($message); } else { // Keep throwing it. throw $e; } } }
/** * {@inheritdoc} */ public function write(Profile $profile) { $args = ['token' => $profile->getToken(), 'parent' => $profile->getParentToken(), 'data' => base64_encode(serialize($profile->getCollectors())), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), 'url' => $profile->getUrl(), 'time' => $profile->getTime(), 'created_at' => time()]; try { $query = $this->database->select('webprofiler', 'w')->fields('w', ['token']); $query->condition('token', $profile->getToken()); $count = $query->countQuery()->execute()->fetchAssoc(); if ($count['expression']) { $this->database->update('webprofiler')->fields($args)->condition('token', $profile->getToken())->execute(); } else { $this->database->insert('webprofiler')->fields($args)->execute(); } $status = TRUE; } catch (\Exception $e) { $status = FALSE; } return $status; }
/** * {@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; } }
/** * {@inheritdoc} */ public function writeDefault() { $this->database->insert('node_access')->fields(array('nid' => 0, 'realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0))->execute(); }
/** * {@inheritdoc} */ public function add(NodeInterface $node) { $this->db->insert($this->table)->fields(['id' => (string) $node->getName(), 'file' => $node->getFilename()])->execute(); }
/** * {@inheritdoc} */ public function insert($link, $parents) { return $this->connection->insert('book')->fields(array('nid' => $link['nid'], 'bid' => $link['bid'], 'pid' => $link['pid'], 'weight' => $link['weight']) + $parents)->execute(); }
/** * Saves values of fields that use dedicated tables. * * @param \Drupal\Core\Entity\ContentEntityInterface $entity * The entity. * @param bool $update * TRUE if the entity is being updated, FALSE if it is being inserted. * @param string[] $names * (optional) The names of the fields to be stored. Defaults to all the * available fields. */ protected function saveToDedicatedTables(ContentEntityInterface $entity, $update = TRUE, $names = array()) { $vid = $entity->getRevisionId(); $id = $entity->id(); $bundle = $entity->bundle(); $entity_type = $entity->getEntityTypeId(); $default_langcode = $entity->getUntranslated()->language()->getId(); $translation_langcodes = array_keys($entity->getTranslationLanguages()); $table_mapping = $this->getTableMapping(); if (!isset($vid)) { $vid = $id; } $original = !empty($entity->original) ? $entity->original : NULL; // Determine which fields should be actually stored. $definitions = $this->entityManager->getFieldDefinitions($entity_type, $bundle); if ($names) { $definitions = array_intersect_key($definitions, array_flip($names)); } foreach ($definitions as $field_name => $field_definition) { $storage_definition = $field_definition->getFieldStorageDefinition(); if (!$table_mapping->requiresDedicatedTableStorage($storage_definition)) { continue; } // When updating an existing revision, keep the existing records if the // field values did not change. if (!$entity->isNewRevision() && $original && !$this->hasFieldValueChanged($field_definition, $entity, $original)) { continue; } $table_name = $table_mapping->getDedicatedDataTableName($storage_definition); $revision_name = $table_mapping->getDedicatedRevisionTableName($storage_definition); // Delete and insert, rather than update, in case a value was added. if ($update) { // Only overwrite the field's base table if saving the default revision // of an entity. if ($entity->isDefaultRevision()) { $this->database->delete($table_name)->condition('entity_id', $id)->execute(); } if ($this->entityType->isRevisionable()) { $this->database->delete($revision_name)->condition('entity_id', $id)->condition('revision_id', $vid)->execute(); } } // Prepare the multi-insert query. $do_insert = FALSE; $columns = array('entity_id', 'revision_id', 'bundle', 'delta', 'langcode'); foreach ($storage_definition->getColumns() as $column => $attributes) { $columns[] = $table_mapping->getFieldColumnName($storage_definition, $column); } $query = $this->database->insert($table_name)->fields($columns); if ($this->entityType->isRevisionable()) { $revision_query = $this->database->insert($revision_name)->fields($columns); } $langcodes = $field_definition->isTranslatable() ? $translation_langcodes : array($default_langcode); foreach ($langcodes as $langcode) { $delta_count = 0; $items = $entity->getTranslation($langcode)->get($field_name); $items->filterEmptyItems(); foreach ($items as $delta => $item) { // We now know we have something to insert. $do_insert = TRUE; $record = array('entity_id' => $id, 'revision_id' => $vid, 'bundle' => $bundle, 'delta' => $delta, 'langcode' => $langcode); foreach ($storage_definition->getColumns() as $column => $attributes) { $column_name = $table_mapping->getFieldColumnName($storage_definition, $column); // Serialize the value if specified in the column schema. $record[$column_name] = !empty($attributes['serialize']) ? serialize($item->{$column}) : $item->{$column}; } $query->values($record); if ($this->entityType->isRevisionable()) { $revision_query->values($record); } if ($storage_definition->getCardinality() != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED && ++$delta_count == $storage_definition->getCardinality()) { break; } } } // Execute the query if we have values to insert. if ($do_insert) { // Only overwrite the field's base table if saving the default revision // of an entity. if ($entity->isDefaultRevision()) { $query->execute(); } if ($this->entityType->isRevisionable()) { $revision_query->execute(); } } } }