You are here

public function Comment::preSave in Drupal 8

Same name and namespace in other branches
  1. 9 core/modules/comment/src/Entity/Comment.php \Drupal\comment\Entity\Comment::preSave()

Acts on an entity before the presave hook is invoked.

Used before the entity is saved and before invoking the presave hook. Note that in case of translatable content entities this callback is only fired on their current translation. It is up to the developer to iterate over all translations if needed. This is different from its counterpart in the Field API, FieldItemListInterface::preSave(), which is fired on all field translations automatically. @todo Adjust existing implementations and the documentation according to https://www.drupal.org/node/2577609 to have a consistent API.

Parameters

\Drupal\Core\Entity\EntityStorageInterface $storage: The entity storage object.

Throws

\Exception When there is a problem that should prevent saving the entity.

Overrides ContentEntityBase::preSave

See also

\Drupal\Core\Field\FieldItemListInterface::preSave()

File

core/modules/comment/src/Entity/Comment.php, line 87

Class

Comment
Defines the comment entity class.

Namespace

Drupal\comment\Entity

Code

public function preSave(EntityStorageInterface $storage) {
  parent::preSave($storage);
  if ($this
    ->isNew()) {

    // Add the comment to database. This next section builds the thread field.
    // @see \Drupal\comment\CommentViewBuilder::buildComponents()
    $thread = $this
      ->getThread();
    if (empty($thread)) {
      if ($this->threadLock) {

        // Thread lock was not released after being set previously.
        // This suggests there's a bug in code using this class.
        throw new \LogicException('preSave() is called again without calling postSave() or releaseThreadLock()');
      }
      if (!$this
        ->hasParentComment()) {

        // This is a comment with no parent comment (depth 0): we start
        // by retrieving the maximum thread level.
        $max = $storage
          ->getMaxThread($this);

        // Strip the "/" from the end of the thread.
        $max = rtrim($max, '/');

        // We need to get the value at the correct depth.
        $parts = explode('.', $max);
        $n = Number::alphadecimalToInt($parts[0]);
        $prefix = '';
      }
      else {

        // This is a comment with a parent comment, so increase the part of
        // the thread value at the proper depth.
        // Get the parent comment:
        $parent = $this
          ->getParentComment();

        // Strip the "/" from the end of the parent thread.
        $parent
          ->setThread((string) rtrim((string) $parent
          ->getThread(), '/'));
        $prefix = $parent
          ->getThread() . '.';

        // Get the max value in *this* thread.
        $max = $storage
          ->getMaxThreadPerThread($this);
        if ($max == '') {

          // First child of this parent. As the other two cases do an
          // increment of the thread number before creating the thread
          // string set this to -1 so it requires an increment too.
          $n = -1;
        }
        else {

          // Strip the "/" at the end of the thread.
          $max = rtrim($max, '/');

          // Get the value at the correct depth.
          $parts = explode('.', $max);
          $parent_depth = count(explode('.', $parent
            ->getThread()));
          $n = Number::alphadecimalToInt($parts[$parent_depth]);
        }
      }

      // Finally, build the thread field for this new comment. To avoid
      // race conditions, get a lock on the thread. If another process already
      // has the lock, just move to the next integer.
      do {
        $thread = $prefix . Number::intToAlphadecimal(++$n) . '/';
        $lock_name = "comment:{$this->getCommentedEntityId()}:{$thread}";
      } while (!\Drupal::lock()
        ->acquire($lock_name));
      $this->threadLock = $lock_name;
    }
    $this
      ->setThread($thread);
  }

  // The entity fields for name and mail have no meaning if the user is not
  // Anonymous. Set them to NULL to make it clearer that they are not used.
  // For anonymous users see \Drupal\comment\CommentForm::form() for mail,
  // and \Drupal\comment\CommentForm::buildEntity() for name setting.
  if (!$this
    ->getOwner()
    ->isAnonymous()) {
    $this
      ->set('name', NULL);
    $this
      ->set('mail', NULL);
  }
}