mardi 10 août 2021

CQRS / Query / Response Handler - How to handle a query whose result relies on properties generated from a second table query?

I have some confusion on an direction to take on approach and I am faced with two options on how to query a resource that needs to feed result(s) into a domain model object but simultaneously needs to create another extra property by performing another query also.

My domain model deviates from my actual column structure of my resource table.

  1. I can call another method prior to serving the request

Or

  1. I can invoke two consecutive fetch requests from the client

This is somewhat of a subjective programming question but I am unclear on what is regarded as a proper pattern for CQRS (Command/Query Responsibility Segregation) and especially adherence to the Single Responsibility Principle.

My example has one Domain Model so far.

<?php
     namespace Domain;

     class Risk
     {
          public $riskid;          
          public $risktitle;
          public $riskstate;
          public $riskstatement;
          public $context;
          public $approver;
          public $owner;
          public $creator;
          public $approverid;
          public $ownerid;
          public $creatorid;
          public $assessmentdate;
          public $likelihood;
          public $technical;
          public $schedule;
          public $cost;

          public $level = '';
          public $value = '';
          public $creatorlastname = '';
          public $creatorfirstname = '';
          public $ownerlastname = '';
          public $ownerfirstname = '';
          public $approverlastname = '';
          public $approverfirstname = '';

          public function getLevel()
          {
               
          }

          public function getCreatorFullName()
          {
               return trim(join(', ', [$this->creatorlastname, $this->creatorfirstname]), ', ');
          }

          public function getOwnerFullName()
          {
               return trim(join(', ', [$this->ownerlastname, $this->ownerfirstname]), ', ');
          }

          public function getApproverFullName()
          {
               return trim(join(', ', [$this->approverlastname, $this->approverfirstname]), ', ');
          }
     }

Level and Value need to be assigned a value corresponding to the the result of this query (fields - likelihood, technical, schedule, cost) and a query from a configuration table, not Risk. I have not created the domain model for that object yet.

public $level = '';
public $value = '';

My query handle so far

<?php
    use Provider\Database;

    class GetRiskSummaryQueryHandler
    {
        public function GetRiskSummary()
        {
            $sql = "SELECT riskid AS 'RiskID',
                            creator.userid AS 'CreatorID',
                            owner.userid AS 'OwnerID',  
                            approver.userid AS 'ApproverID', 
                            creator.lastname AS 'creator.lastname',
                            creator.firstname AS 'creator.firstname',
                            owner.lastname AS 'owner.lastname',
                            owner.firstname AS 'owner.firstname',
                            approver.lastname AS 'approver.lastname',
                            approver.firstname AS 'approver.firstname',
                            r.riskstate AS 'RiskState',    
                            r.likelihood AS 'Likelihood',
                            r.technical AS 'Technical', 
                            r.schedule AS 'Schedule',
                            r.cost AS 'Cost',
                            r.AssessmentDate AS 'AssessmentDate',
                            r.risktitle AS 'RiskTitle', 
                            r.riskstatement AS 'RiskStatement',
                            r.context AS 'Context',
                            r.closurecriteria AS 'ClosureCriteria'
                        FROM risks r
                        LEFT JOIN users creator
                            ON r.creatorid = creator.userid
                        LEFT JOIN users OWNER
                            ON r.ownerid = owner.userid
                        LEFT JOIN users approver
                            ON r.approverid = approver.userid";
            try
            {
                $db = new Database();
                $statement = $db->prepare($sql);
                $statement->execute();
                $resultArray = $statement->fetchAll();
                return $resultArray;
            }
            catch (PDOException $e)
            {
                return $e->getMessage();
            }
        }
    }

And my controller

<?php
    use Infrastructure\Mapper\RisksMapper;

    class GetRiskSummaryController
    {
        #[Route('GET', '/risks')]
        public function Controller()
        {
            try
            {
                $mapper = new RisksMapper(); 
                $handler = new GetRiskSummaryQueryHandler();
                $resultArray = $handler->GetRiskSummary();
                $responseResult = $mapper->populateFromCollection($resultArray); 
                return(["succeeded" => true, "data" => $responseResult]);
            }
            catch(Exception $e)
            {
                return ["succeeded" => false, "data" => $e->getMessage()];    
            }
        }
    }

My Mapper Class, is not shown, but gets instantiated in my controller (my Business Logic).

I tried on first attempt to use a transaction in one database function before I refactored my code (smell) to not query two different things from one table, but realized I was violating the Single Responsibility Principle and had some different folders for different tiers of the application, before moving to CQRS/CQS architecture.

How do I assign result of a second query result to the corresponding properties in my domain model object and not introduce an anti-pattern?

Aucun commentaire:

Enregistrer un commentaire