field_completeness-1.0.3/src/FieldCompletenessManager.php

src/FieldCompletenessManager.php
<?php

namespace Drupal\field_completeness;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\field_completeness\FieldCompletenessStorage;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Component\Serialization\PhpSerialize;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\paragraphs\Entity\Paragraph;

/**
 * Defines field completeness manager.
 */
class FieldCompletenessManager {

  /**
   * Entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /**
   * Field completeness storage.
   *
   * @var \Drupal\field_completeness\FieldCompletenessStorage
   */
  public $fieldCompletenessStorage;

  /**
   * Constructs a FieldCompletenessManager object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\language\LanguageManagerInterface $language_manager
   *   The language manager.
   * @param \Drupal\field_completeness\FieldCompletenessStorage $field_completeness_storage
   *   The Field completeness storage.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager, FieldCompletenessStorage $field_completeness_storage) {
    $this->entityTypeManager = $entity_type_manager;
    $this->languageManager = $language_manager;
    $this->fieldCompletenessStorage = $field_completeness_storage;
  }

  /**
   * Determines if a given node type is in the list of types allowed for field completeness.
   *
   * @param string $type
   *   A node type.
   *
   * @return bool
   *   A Boolean TRUE if the node type can be included in field completeness; otherwise, FALSE.
   */
  public function isAllowedContentType($type) {
    if (NULL === $this->getAllowedContentTypes()) {
      return FALSE;
    }
    return in_array($type, $this->getAllowedContentTypes());
  }

  /**
   * Determines new or existing record and update or add in field completeness database table
   *
   * @param \Drupal\Core\Entity\EntityInterface $node
   *
   */
  public function updateOutline(EntityInterface $node) {
    $is_allowed_type = $this->isAllowedContentType($node->bundle());
    if ($is_allowed_type) {
      $lang_code = "";
      $is_existing = FALSE;
      if ($this->languageManager->isMultilingual()) {
        $lang_code = $node->get('langcode')->value;
      }
      $is_existing = $this->fieldCompletenessStorage->select($node->id());
      $fc_data = $this->getNodeData($node, $lang_code);
      $nid = $node->id();
      if (empty($is_existing)) {
        $this->fieldCompletenessStorage->insert($fc_data);
      }
      else {
        if ($this->isModified($node)) {
          $this->fieldCompletenessStorage->update($nid, $fc_data);
        }
      }
    }
  }

  /**
   * insert data into Field completeness table
   * @param \Drupal\Core\Entity\EntityInterface $node
   */
  public function getNodeData(EntityInterface $node, $lang_code) {
    $values = [];
    $values['entity_type'] = $node->bundle();
    $values['entity_id'] = $node->id();
    $values['langcode'] = $lang_code;
    $values['revision_id'] = $this->entityTypeManager->getStorage('node')->getLatestRevisionId($node->id());
    $values['completeness'] = $this->getPhpSerialized($this->getCompleteness($node, 'all'));
    $values['percentage'] = $this->getPercentage($node);
    $values['complete'] = ($values['percentage'] == 100) ? 1 : 0;
    return $values;
  }

  /**
   * Determines included fields and their values
   * @param \Drupal\Core\Entity\EntityInterface $node
   * @param $wrap
   *   'all' - gets all the fields whether its completed or not
   *   'completed' - Gets only completed fields
   *   'incomplete' - Gets only incompleted fields
   */
  public function getCompleteness(EntityInterface $node, $wrap = 'all') {
    $completeness = [];
    $paragraph_fields = [];
    $included_fields = $this->getIncludedFields($node->bundle());
    $nid = $node->id();
    foreach ($included_fields as $included_field) {
      if ($node->hasField($included_field)) {
        if ($wrap == 'all') {
          if ($this->isEntityReferenceRevisions($included_field)) {
            $paragraph_fields = $this->getReferenceRevisionFields($node, $included_field, FALSE);
            if (!empty($paragraph_fields)) {
              foreach ($paragraph_fields as $paragraph_field => $isFilled) {
                $completeness["p_" . $paragraph_field] = $isFilled;
              }
            }
          }
          else {
            //Returns all the fields status
            if (!$node->get($included_field)->isEmpty() && !empty($node->get($included_field)->getString())) {
              $completeness[$included_field] = TRUE;
            }
            else {
              $completeness[$included_field] = FALSE;
            }
          }
        }
        elseif ($wrap == 'completed') {
          if ($this->isEntityReferenceRevisions($included_field)) {
            $paragraph_fields = $this->getReferenceRevisionFields($node, $included_field, FALSE);
            foreach ($paragraph_fields as $paragraph_field => $isFilled) {
              if ($isFilled) {
                $completeness[] = "p_" . $paragraph_field;
              }
            }
          }
          else {
            //Returns completed fields, it will consider 0/FALSE as empty
            if (!$node->get($included_field)->isEmpty() && !empty($node->get($included_field)->getString())) {
              $completeness[] = $included_field;
            }
          }
        }
        else {
          if ($this->isEntityReferenceRevisions($included_field) && !$this->isParagraphHasValue($node, $included_field)) {
            $completeness[] = $included_field;
          }
          else {
            //Returns incompleted fields, it will consider 0/FALSE as empty
            if ($node->get($included_field)->isEmpty() || empty($node->get($included_field)->getString())) {
              $completeness[] = $included_field;
            }
          }
        }
      }
      else {
        //Unset from included fields
        $this->unSetIncludedFields($node->getEntityTypeId(), $node->bundle(), $included_field);
      }
    }
    return $completeness;
  }

  public function getPhpSerialized($data) {
    return PhpSerialize::encode($data);
  }

  public function getPhpUnSerialized($data) {
    return PhpSerialize::decode($data);
  }

  public function getIncludedFields($type) {
    $included_field_config = \Drupal::config('field_completeness.node.' . $type . '.settings');
    $allowed_fields = [];
    if (NULL !== $included_field_config->get('node')) {
      foreach ($included_field_config->get('node') as $field => $isIncluded) {
        if ($isIncluded) {
          $allowed_fields[] = $field;
        }
      }
    }
    return $allowed_fields;
  }

  public function isEntityReferenceRevisions($field_name) {
    $field_storage = FieldStorageConfig::loadByName('node', $field_name);
    if ($field_storage->getType() == 'entity_reference_revisions') {
      if (!is_null($field_storage) && $field_storage->getSetting('target_type') == 'paragraph') {
        return TRUE;
      }
    }
    return FALSE;
  }

  /**
   * Get included fields of Paragraph type. In future other types are going to include.
   * is_empty
   *   TRUE - It will return field names as array if any field is empty or return empty array.
   *   FALSE - It will return all the included paragraph fields
   */
  public function getReferenceRevisionFields(EntityInterface $node, $field_name, $is_empty = FALSE) {
    $fields = [];
    if (!empty($node->get($field_name)->first())) {
      $reference_revision = $node->get($field_name)->first()->get('entity')->getTarget()->getValue();
    }

    $paragraph_types = $node->get($field_name)->getSetting('handler_settings')['target_bundles'];
    if (!empty($reference_revision)) {
      if ($reference_revision instanceof Paragraph) {
        $paragraph_type = $reference_revision->getType();
        $paragraph_config = \Drupal::config('field_completeness.paragraph.' . $paragraph_type . '.settings');

        foreach ($paragraph_config->get('paragraph') as $field => $isIncluded) {
          if ($isIncluded) {
            if ($is_empty) {
              if ($reference_revision->get($field)->isEmpty() || empty($reference_revision->get($field)->getString())) {
                $fields[] = $field;
              }
            }
            else {
              if (!$reference_revision->get($field)->isEmpty() && !empty($reference_revision->get($field)->getString())) {
                $fields[$field] = TRUE;
              }
              else {
                $fields[$field] = FALSE;
              }
            }
          }
        }
      }
    }
    else {
      if (!empty($paragraph_types)) {
        foreach ($paragraph_types as $paragraph_type) {
          $paragraph_config = \Drupal::config('field_completeness.paragraph.' . $paragraph_type . '.settings');
          foreach ($paragraph_config->get('paragraph') as $field => $isIncluded) {
            if ($isIncluded) {
              if ($is_empty) {
                $fields[] = $field;
              }
              else {
                $fields[$field] = FALSE;
              }
            }
          }
        }
      }
    }
    return $fields;
  }

  public function isParagraphHasValue($node, $included_field) {
    $reference_revision_fields = $this->getReferenceRevisionFields($node, $included_field, TRUE);
    if (empty($reference_revision_fields)) {
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Remove included fields from configuration which is not existing in Entity
   */
  public function unSetIncludedFields($entity_type_id, $bundle, $field_name) {
    $config = \Drupal::service('config.factory')->getEditable('field_completeness.node.' . $bundle . '.settings');
    $fc_config = $entity_type_id . "." . $field_name;
    $config->set($fc_config, 0)->save();
  }

  /**
   * Gets allowed content types for field completeness
   *
   * @return array
   *   An array of content types list for field completeness
   */
  public function getAllowedContentTypes() {
    return \Drupal::config('field_completeness.settings')->get('allowed_types');
  }

  /**
   * Determines percentage of field completion
   */
  public function getPercentage(EntityInterface $node) {

    if (empty($this->getCompleteness($node, 'incomplete'))) {
      return 100;
    }
    $total = count($this->getCompleteness($node, 'all'));
    $completed = count($this->getCompleteness($node, 'completed'));
    $percentage = floor($completed * (100 / $total));
    return $percentage;
  }

  /**
   * Determines percentage of field completion
   */
  public function getStaticPercentage(EntityInterface $node) {
    $percentage = 0;
    $select = $this->fieldCompletenessStorage->select($node->id());
    $percentage = $select[$node->id()]['percentage'];
    return $percentage;
  }

  /**
   * Gets current node object.
   */
  public function getNode() {
    //need to verify for add page
    $node = \Drupal::routeMatch()->getParameter('node');
    if (!$node instanceof EntityInterface) {
      return FALSE;
    }
    return $node;
  }

  /**
   * Determines if a given paragraph type is allowed for field completeness paragraph.
   *
   * @param string $type
   *   A node type.
   *
   * @return bool
   *   A Boolean TRUE if the node type can be included in field completeness; otherwise, FALSE.
   */
  public function isAllowedParagraphType($type) {
    return in_array($type, $this->getAllowedParagraphTypes());
  }

  /**
   * Gets allowed paragraph types for field completeness
   *
   * @return array
   *   An array of paragraph types list for field completeness
   */
  public function getAllowedParagraphTypes() {
    return \Drupal::config('field_completeness.paragraphs.settings')->get('allowed_types');
  }

  /**
   * Gets entity type from route parameter
   */
  public function getEntityBundleFromRoute() {
    $route_parameters = \Drupal::routeMatch()->getParameters();

    foreach ($route_parameters as $entity) {
      if ($entity instanceof EntityInterface) {
        return $entity->id();
      }
    }
    return NULL;
  }

  /**
   * While Adding or removing a field, it will update required items to reflect immediately to all the nodes of field bundle
   * Update below items to field_completeness DB table
   *   - completeness
   *   - percentage
   *   - complete
   */
  public function setLatestPercentageToBundle($field, $bundle) {
    $fc_data = $this->fieldCompletenessStorage->selectByBundle($bundle);
    if (!empty($fc_data)) {
      foreach ($fc_data as $nid => $fc_values) {
        $node = $this->entityTypeManager->getStorage('node')->load($nid);
        if (is_null($node)) {
          $this->removeDeletedNodeFromCompleteness($nid);
          continue;
        }
        $fc_values['completeness'] = $this->getCompleteness($node, 'all');
        $this->fieldCompletenessStorage->update($nid, $this->calculatePercentageForExistingItem($fc_values));
      }
    }
  }

  /**
   * While Adding or removing a field, it will update required items to reflect immediately to a node
   * Update below items to field_completeness DB table
   *   - completeness
   *   - percentage
   *   - complete
   */
  public function setPercentageWhileUpdateNode($field, $is_empty, $bundle, $nid) {
    if (in_array($field, $this->getIncludedFields($bundle))) {
      $fc_data = $this->fieldCompletenessStorage->select($nid);
      $fc_values['completeness'] = $this->getPhpUnSerialized($fc_data[$nid]['completeness']);
      $fc_values['completeness'][$field] = (bool) $is_empty;
      $this->fieldCompletenessStorage->update($nid, $this->calculatePercentageForExistingItem($fc_values));
    }
  }

  /**
   * Calculate percentage for existing record while updating Field completeness.
   */
  public function calculatePercentageForExistingItem($fc_values) {
    $fc_total = count($fc_values['completeness']);
    $fc_completed = count(array_filter($fc_values['completeness']));
    $fc_values['completeness'] = $this->getPhpSerialized($fc_values['completeness']);
    if ($fc_total > 0) {
      $fc_values['percentage'] = floor($fc_completed * (100 / $fc_total));
    }
    else {
      $fc_values['percentage'] = 100;
    }
    $fc_values['complete'] = ($fc_values['percentage'] == 100) ? 1 : 0;
    return $fc_values;
  }

  /**
   * Observe the changes of Node revision and Field changes
   */
  public function isModified(EntityInterface $node) {
    $nid = $node->id();
    $select = $this->fieldCompletenessStorage->select($nid);
    $is_modified = FALSE;
    //verify existing revision id
    $revision_id = $this->entityTypeManager->getStorage('node')->getLatestRevisionId($nid);
    $exisiting_revision_id = $select[$nid]['revision_id'];
    if ($revision_id <> $exisiting_revision_id) {
      $is_modified = TRUE;
    }

    $old_fields = $this->getPhpUnSerialized($select[$nid]['completeness']);
    $new_fields = $this->getCompleteness($node, 'all');
    if ($old_fields <> $new_fields) {
      $is_modified = TRUE;
    }

    return $is_modified;
  }

  /**
   * Remove a record from field completeness which is not existing in current site
   */
  public function removeDeletedNodeFromCompleteness($nid) {
    $this->fieldCompletenessStorage->delete($nid);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc