public function changeParent(Request\ChangeParent $request)
 {
     $result = new Response\ChangeParent();
     $customerId = $request->getCustomerId();
     $newParentId = $request->getNewParentId();
     $formatted = $request->getDate();
     $this->_logger->info("Set up new parent #{$newParentId} for customer #{$customerId}.");
     $def = $this->_manTrans->begin();
     try {
         /* get customer's downline  data */
         $data = $this->_repoCustomer->getById($customerId);
         $currParentId = $data->getParentId();
         $currDepth = $data->getDepth();
         $currPath = $data->getPath();
         if ($currParentId == $newParentId) {
             /* nothing to change */
             $result->markSucceed();
             $this->_manTrans->commit($def);
             $this->_logger->notice("Current parent is the same as new one. Nothing to do.");
         } else {
             if ($customerId == $newParentId) {
                 /* change to root node */
                 $newCustomerDepth = Cfg::INIT_DEPTH;
                 $newCustomerPath = Cfg::DTPS;
             } else {
                 /* get new parent data */
                 $newParentData = $this->_repoCustomer->getById($newParentId);
                 $newParentDepth = $newParentData->getDepth();
                 $newParentPath = $newParentData->getPath();
                 $newCustomerDepth = $newParentDepth + 1;
                 $newCustomerPath = $newParentPath . $newParentId . Cfg::DTPS;
             }
             /* update customer with new data */
             $bind = [Customer::ATTR_PARENT_ID => $newParentId, Customer::ATTR_DEPTH => $newCustomerDepth, Customer::ATTR_PATH => $newCustomerPath];
             $updateRows = $this->_repoCustomer->updateById($customerId, $bind);
             if ($updateRows == 1) {
                 /* update depths and paths in downline */
                 $deltaDepth = $newCustomerDepth - $currDepth;
                 $pathKey = $currPath . $customerId . Cfg::DTPS;
                 $pathReplace = $newCustomerPath . $customerId . Cfg::DTPS;
                 $rowsUpdated = $this->_repoCustomer->updateChildrenPath($pathKey, $pathReplace, $deltaDepth);
                 $this->_logger->info("Total '{$rowsUpdated}' customers in downline were updated.");
                 /* save new record into change log */
                 $bind = [Change::ATTR_CUSTOMER_ID => $customerId, Change::ATTR_PARENT_ID => $newParentId, Change::ATTR_DATE_CHANGED => $formatted];
                 $insertedId = $this->_repoChange->create($bind);
                 if ($insertedId) {
                     $this->_logger->info("New change log record #{$insertedId} is inserted (customer: {$customerId}, parent: {$newParentId}, date: {$formatted}).");
                     $this->_manTrans->commit($def);
                     $result->markSucceed();
                     $this->_logger->info("New parent #{$newParentId} for customer #{$customerId} is set.");
                 }
             }
         }
     } finally {
         $this->_manTrans->end($def);
     }
     return $result;
 }
 /**
  * Calculate the last date for existing downline snap or the "yesterday" for the first change log entry.
  *
  * @param Request\GetLastDate $request
  *
  * @return Response\GetLastDate
  */
 public function getLastDate(Request\GetLastDate $request)
 {
     $result = new Response\GetLastDate();
     $this->_logger->info("'Get Last Data' operation is requested.");
     /* get the maximal date for existing snapshot */
     $snapMaxDate = $this->_repoSnap->getMaxDatestamp();
     if ($snapMaxDate) {
         /* there is snapshots data */
         $result->setData([Response\GetLastDate::LAST_DATE => $snapMaxDate]);
         $result->markSucceed();
     } else {
         /* there is no snapshot data yet, get change log minimal date  */
         $changelogMinDate = $this->_repoChange->getChangelogMinDate();
         if ($changelogMinDate) {
             $period = $this->_toolPeriod->getPeriodCurrent($changelogMinDate);
             $dayBefore = $this->_toolPeriod->getPeriodPrev($period);
             $this->_logger->info("The last date for downline snapshot is '{$dayBefore}'.");
             $result->setData([Response\GetLastDate::LAST_DATE => $dayBefore]);
             $result->markSucceed();
         }
     }
     $this->_logger->info("'Get Last Data' operation is completed.");
     return $result;
 }