work_time-1.0.x-dev/src/Plugin/rest/resource/ApiWorkTimeListResource.php

src/Plugin/rest/resource/ApiWorkTimeListResource.php
<?php

namespace Drupal\work_time\Plugin\rest\resource;

use Drupal\Component\Plugin\DependentPluginInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Link;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\user\Entity\User;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Represents Api Work Time records as resources.
 *
 * @RestResource (
 *   id = "api_work_time_list",
 *   label = @Translation("Api Work Time list"),
 *   uri_paths = {
 *     "canonical" = "/api/work-time-list/{limit}",
 *     "create" = "/api/work-time-list"
 *   }
 * )
 *
 * @DCG
 * This plugin exposes database records as REST resources. In order to enable it
 * import the resource configuration into active configuration storage. You may
 * find an example of such configuration in the following file:
 * core/modules/rest/config/optional/rest.resource.entity.node.yml.
 * Alternatively you can make use of REST UI module.
 * @see https://www.drupal.org/project/restui
 * For accessing Drupal entities through REST interface use
 * \Drupal\rest\Plugin\rest\resource\EntityResource plugin.
 */
class ApiWorkTimeListResource extends ResourceBase implements DependentPluginInterface {

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $dbConnection;

  /**
   * Constructs a Drupal\rest\Plugin\rest\resource\EntityResource object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param array $serializer_formats
   *   The available serialization formats.
   * @param \Psr\Log\LoggerInterface $logger
   *   A logger instance.
   * @param \Drupal\Core\Database\Connection $db_connection
   *   The database connection.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, Connection $db_connection) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
    $this->dbConnection = $db_connection;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->getParameter('serializer.formats'),
      $container->get('logger.factory')->get('rest'),
      $container->get('database')
    );
  }

  /**
   * Responds to GET requests.
   *
   * @param string $limit
   *   The filter of worktime in week or in month.
   *
   * @return \Drupal\rest\ResourceResponse
   *   The response containing the record.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   */
  public function get($limit = 'week') {
    $workTimes = FALSE;
    $currentWorkTimes = [];
    $request = \Drupal::request();
    $entityManager = \Drupal::entityTypeManager();
    $currentUser = \Drupal::currentUser();
    $uid = $currentUser->id();
    // Get work times in week.
    $sql = [
      'week' => "SELECT * FROM {work_time}
WHERE
(
  (FROM_UNIXTIME(created) BETWEEN DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) AND DATE_ADD(CURDATE(), INTERVAL 6 - WEEKDAY(CURDATE()) DAY)) OR
  (FROM_UNIXTIME(stopped) BETWEEN DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) AND DATE_ADD(CURDATE(), INTERVAL 6 - WEEKDAY(CURDATE()) DAY))
      ) AND uid =:uid ORDER BY created DESC",
      'month' => "SELECT * FROM {work_time}
WHERE
(
  (FROM_UNIXTIME(created) BETWEEN DATE_FORMAT(NOW(),'%Y-%m-01') AND LAST_DAY(NOW()))
  OR
  (FROM_UNIXTIME(stopped) BETWEEN DATE_FORMAT(NOW(),'%Y-%m-01') AND LAST_DAY(NOW()))
      ) AND uid = :uid ORDER BY created DESC",
    ];
    if (!empty($sql[$limit])) {
      $workTimes = $this->dbConnection->query($sql[$limit], [':uid' => $uid])
        ->fetchAll(\PDO::FETCH_ASSOC);
    }
    // Get current playing.
    $query = $entityManager->getStorage('work_time')->getQuery()->accessCheck(TRUE);
    $query->condition('uid', $uid);
    $query->notExists('stopped');
    $wids = $query->execute();
    if (!empty($wids)) {
      $nonStopWorkTimes = $entityManager->getStorage('work_time')
        ->loadMultiple($wids);
      // Get last one.
      $workTime = end($nonStopWorkTimes);
      $currentWorkTimes = [
        'id' => $workTime->id(),
        'uuid' => $workTime->uuid(),
        'label' => $workTime->label(),
        'entity_id' => $workTime->get('entity_id')->getString(),
        'entity_type' => $workTime->get('entity_type')->getString(),
        'reference_id' => $workTime->get('reference_id')->getString(),
        'reference_field' => $workTime->get('reference_field')->getString(),
        'reference_type' => $workTime->get('reference_type')->getString(),
        'created' => $workTime->get('created')->getString(),
        'time' => strtotime("now") - (int) $workTime->get('created')->getString(),
      ];
    }
    // Get list projects.
    $projects = [];
    $referenceField = $request->get('referenceField');
    if (!empty($referenceField)) {
      $entity_type = $request->get('entityType');
      $bundle = $request->get('entityBundle');
      $fieldConfig = $entityManager->getStorage('field_config')
        ->load($entity_type . '.' . $bundle . '.' . $referenceField);
      if ($fieldConfig) {
        $settings = $fieldConfig->getSetting('handler_settings');
        $handler = explode(':', $fieldConfig->getSetting('handler'));
        $handler = end($handler);
        if (!empty($settings["target_bundles"])) {
          $ids = $entityManager->getStorage($handler)->getQuery()->accessCheck(TRUE)
            ->condition('type', array_values($settings["target_bundles"]), 'IN')
            ->condition('status', 1)
            ->execute();
          $entities = $entityManager->getStorage($handler)->loadMultiple($ids);
          if (!empty($entities)) {
            foreach ($entities as $project) {
              $projects[] = [
                'id' => $project->id(),
                'label' => $project->label(),
              ];
            }
          }
        }
      }
    }
    return new ModifiedResourceResponse([
      'worktime' => $workTimes,
      'playing' => $currentWorkTimes,
      'projects' => $projects,
    ], 200);
  }

  /**
   * Responds to POST requests and saves the new record.
   *
   * @param mixed $data
   *   Data to write into the database.
   *
   * @return \Drupal\rest\ModifiedResourceResponse
   *   The HTTP response object.
   */
  public function post($data) {
    $workTimeStorage = \Drupal::entityTypeManager()->getStorage('work_time');
    $user = \Drupal::currentUser();
    $currentTimestamp = strtotime('now');
    $query = $workTimeStorage->getQuery()
      ->condition('uid', $user->id())
      ->condition('stopped', NULL, 'IS NULL');
    $workTimes = $query->execute();
    if (!empty($data['entity_type']) && !empty($data['entity_id'])) {
      $taskManager = \Drupal::entityTypeManager()
        ->getStorage($type = $data['entity_type']);
      $task = $taskManager->load($idTask = $data['entity_id']);
      $taskManager->resetCache([$data['entity_id']]);
    }
    // State is stopped.
    if (!empty($workTimes)) {
      foreach ($workTimes as $workTimeId) {
        $workTime = $workTimeStorage->load($workTimeId);
        $start = $workTime->get('created')->value;
        $workTime->set('stopped', $currentTimestamp);
        $workTime->set('time_total', $currentTimestamp - $start);
        $workTime->save();
        // Save value to field.
        if (!empty($task) && !empty($data['entity_field'])) {
          $fieldTimeValue = [
            'value' => gmdate(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $start),
            'end_value' => gmdate(DateTimeItemInterface::DATETIME_STORAGE_FORMAT, $currentTimestamp),
          ];
          $task->get($data['entity_field'])->appendItem($fieldTimeValue);
          $task->save();
        }
      }
    }
    $label = '';
    if (!empty($task)) {
      if (in_array($type, ['user'])) {
        $label = $task->getDisplayName();
      }
      elseif ($type == 'taxonomy_term') {
        $label = $task->getName();
      }
      elseif (method_exists($task, 'getTitle')) {
        $label = $task->getTitle();
      }
    }

    $created_record = ['data' => 'Worktime Save'];
    if ($data['play']) {
      $workTime = $workTimeStorage
        ->create([
          'label' => $label,
          'uid' => $user->id(),
          'created' => $currentTimestamp,
          'entity_id' => $idTask ?? '',
          'entity_type' => $type ?? '',
          'entity_field' => $data['entity_field'] ?? '',
          'reference_id' => $data['reference_id'] ?? '',
          'reference_field' => $data['reference_field'] ?? '',
          'reference_type' => $data['reference_type'] ?? '',
          'stopped' => NULL,
          'type' => 0,
        ]);
      $workTime->save();
      $id = $workTime->id();
      $created_record = $this->loadRecord($id);
    }

    // Return the newly created record in the response body.
    return new ModifiedResourceResponse($created_record, 200);
  }

  /**
   * Responds to entity PATCH requests.
   *
   * @param int $id
   *   The ID of the record.
   *
   * @return \Drupal\rest\ModifiedResourceResponse
   *   The HTTP response object.
   */
  public function patch(int $id = 0) {
    $out = [];
    $entity_ids = json_decode(\Drupal::request()->getContent(), TRUE);
    $database = \Drupal::database();
    $query = $database->select('work_time', 'wt');
    $query->addExpression("CONCAT(wt.entity_type, '-', wt.entity_id)", 'entity');
    $query->addExpression('SUM(wt.time_total)', 'total');
    $query->where("CONCAT(wt.entity_type, '-', wt.entity_id) IN (:entity_ids[])", [':entity_ids[]' => $entity_ids]);
    $query->condition('wt.stopped', NULL, 'IS NOT');
    $query->groupBy('entity');

    $results = $query->execute();
    foreach ($results as $result) {
      $entity = $result->entity;
      $total = $result->total;
      $out[$entity] = $total;
    }
    return new ModifiedResourceResponse($out, 200);
  }

  /**
   * Responds to entity DELETE requests.
   *
   * @param int $entity_id
   *   Entity id.
   * @param string $entity_field
   *   Entity field.
   *
   * @return \Drupal\rest\ModifiedResourceResponse
   *   The HTTP response object.
   */
  public function delete($entity_id, $entity_field) {

    // Make sure the record still exists.
    $checkExist = $this->loadRecord($entity_id);
    if (!empty($checkExist)) {
      $this->dbConnection->delete('work_time')
        ->condition('id', $entity_id)
        ->execute();
      $this->logger->notice('Api Work Time record @id has been deleted.', ['@id' => $entity_id]);
    }
    // Deleted responses have an empty body.
    return new ModifiedResourceResponse(NULL, 204);
  }

  /**
   * Validates incoming record.
   *
   * @param mixed $record
   *   Data to validate.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
   */
  protected function validate($record) {
    if (!is_array($record) || count($record) == 0) {
      throw new BadRequestHttpException('No record content received.');
    }

    $allowed_fields = [
      'title',
      'description',
    ];

    if (count(array_diff(array_keys($record), $allowed_fields)) > 0) {
      throw new BadRequestHttpException('Record structure is not correct.');
    }

    if (empty($record['title'])) {
      throw new BadRequestHttpException('Title is required.');
    }
    elseif (isset($record['title']) && strlen($record['title']) > 255) {
      throw new BadRequestHttpException('Title is too big.');
    }
    // @DCG Add more validation rules here.
  }

  /**
   * Loads record from database.
   *
   * @param int $id
   *   The ID of the record.
   *
   * @return array
   *   The database record.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
   */
  protected function loadRecord($id) {
    $record = $this->dbConnection->query(
      'SELECT * FROM {work_time} WHERE id = :id', [':id' => $id])->fetchAssoc();
    if (!$record) {
      throw new NotFoundHttpException('The record was not found.');
    }
    return $record;
  }

  /**
   * Updates record.
   *
   * @param int $id
   *   The ID of the record.
   * @param array $record
   *   The record to validate.
   *
   * @return \Drupal\rest\ModifiedResourceResponse
   *   The HTTP response object.
   */
  protected function updateRecord($id, array $record) {

    // Make sure the record already exists.
    $this->loadRecord($id);

    $this->validate($record);

    $this->dbConnection->update('work_time')
      ->fields($record)
      ->condition('id', $id)
      ->execute();

    $this->logger->notice('Api Work Time record @id has been updated.', ['@id' => $id]);

    // Return the updated record in the response body.
    $updated_record = $this->loadRecord($id);
    return new ModifiedResourceResponse($updated_record, 200);
  }

  /**
   * {@inheritdoc}
   */
  protected function loadEntities($entity_id, $entity_field) {
    $query = $this->dbConnection->select('work_time', 'w')
      ->fields('w')
      ->condition('stopped', '', 'IS NOT NULL')
      ->condition('entity_id', $entity_id)
      ->condition('entity_field', $entity_field);
    $query->addExpression("FROM_UNIXTIME(created,'%Y-%m-%d')", 'date');
    $work_times = $query->execute();
    $records = [];
    $entityManager = \Drupal::entityTypeManager();
    $projects = [];
    $options = ['absolute' => TRUE];
    foreach ($work_times as $work_time) {
      $user = User::load($work_time->uid);
      if (empty($records[$work_time->uid])) {
        $name = $user->getDisplayName();
        preg_match_all('/(?<=\b)\w/iu', $name, $initials);
        $records[$work_time->uid] = [
          'name' => $name,
          'label' => $work_time->label,
          'initial' => strtoupper(implode('', array_slice($initials[0], 0, 2))),
          'details' => [],
        ];
      }

      if (!empty($work_time->reference_id) && !empty($work_time->reference_field) && empty($projects[$work_time->reference_id])) {
        $task = $entityManager->getStorage($work_time->entity_type)
          ->load($entity_id);
        $referenceItem = $task->get($work_time->reference_field)
          ->referencedEntities();
        $node = current($referenceItem);
        $projects[$work_time->reference_id] = $node;
        $work_time->project = Link::fromTextAndUrl($node->getTitle(), $node->toUrl('canonical', $options))
          ->toString();
      }
      $records[$work_time->uid]['details'][] = (array) $work_time;
    }
    return array_values($records);
  }

  /**
   * {@inheritdoc}
   */
  public function getCurrentPlaying($entity_id) {
    $uid = \Drupal::currentUser()->id();
    $query = $this->dbConnection->select('work_time', 'w')
      ->fields('w', ['created'])
      ->condition('stopped', '', 'IS NULL')
      ->condition('uid', '', $uid)
      ->condition('entity_id', $entity_id);
    $query->execute();
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    return [];
  }

}

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

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