src/Services/Communication/SmsProviderTools.php line 42

Open in your IDE?
  1. <?php
  2. //----------------------------------------------------------------------
  3. // src/Services/Communication/SmsProviderTools.php
  4. //----------------------------------------------------------------------
  5. namespace App\Services\Communication;
  6. use Doctrine\Persistence\ManagerRegistry;
  7. use Symfony\Component\Routing\RouterInterface;
  8. use Twilio\Rest\Client as TwilioClient;
  9. use Twilio\Exceptions\TwilioException;
  10. use App\Entity\SocietyGroup;
  11. use App\Entity\Communication\Sms\Sms;
  12. use App\Entity\Communication\Sms\SmsPhoneNumber;
  13. use App\Entity\Communication\Sms\SmsStatus;
  14. use App\Entity\Communication\SmsProviders\SmsProvider;
  15. use App\Entity\Communication\SmsProviders\SmsMode;
  16. use App\Entity\Communication\SmsProviders\SmsModeStatus;
  17. use App\Entity\Communication\SmsProviders\SmsTwilio;
  18. use App\Entity\Communication\SmsProviders\SmsTwilioStatus;
  19. use App\Entity\Config\Config;
  20. use App\Services\LogTools;
  21. use App\Services\Platform\ExternalMessageTools;
  22. use App\Services\Security\PasswordTools;
  23. /**
  24.  * For now all this code works under the assumption that only one SmsProvider is active.
  25.  *
  26.  * Naming conventions :
  27.  *         $smsProvider can be an object of type
  28.  *            SmsProvider::SmsMode
  29.  *            SmsProvider::SmsTwilio
  30.  *        $sms is an object of type Sms::Sms
  31.  *
  32.  * Error logging should be done with both errorlog and smsLogDebug
  33.  *         $msg = "my amazing and unexpected error";
  34.  *         $this->logTools->errorlog($msg);
  35.  *         $this->logTools->smsLogDebug($msg, $activeSmsProvider);
  36.  */
  37. class SmsProviderTools
  38. {
  39.     public function __construct(ManagerRegistry $doctrineLogTools $logToolsPasswordTools $passwordToolsRouterInterface $routerExternalMessageTools $externalMessageToolsstring $smsModeAPIKey)
  40.     {
  41.         $this->em $doctrine->getManager();
  42.         $this->logTools $logTools;
  43.         $this->passwordTools $passwordTools;
  44.         $this->externalMessageTools $externalMessageTools;
  45.         $this->router $router;
  46.         $this->smsModeAPIKey $smsModeAPIKey;
  47.         $this->debug true;
  48.     }
  49.     /**
  50.      * Is SmsMode the currently active SmsProvider ?
  51.      *
  52.      * @return boolean
  53.      */
  54.     public function isActiveSmsMode()
  55.     {
  56.         // Get the active SmsProvider
  57.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  58.             'isActive'        =>    1,
  59.         ));
  60.         // Get the active SmsProvider
  61.         if ($activeSmsProvider === null)
  62.         {
  63.             return false;
  64.         }
  65.         return $activeSmsProvider->isSmsMode();
  66.     }
  67.     /**
  68.      * Is Twilio the currently active SmsProvider ?
  69.      *
  70.      * @return boolean
  71.      */
  72.     public function isActiveSmsTwilio()
  73.     {
  74.         // Get the active SmsProvider
  75.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  76.             'isActive'        =>    1,
  77.         ));
  78.         // Get the active SmsProvider
  79.         if ($activeSmsProvider === null)
  80.         {
  81.             return false;
  82.         }
  83.         return $activeSmsProvider->isSmsTwilio();
  84.     }
  85.     /**
  86.      * Get the currently active SmsProvider
  87.      * Note : Only one SmsProvider should be active
  88.      *
  89.      * @return null|SmsProvider
  90.      */
  91.     public function getActiveSmsProvider()
  92.     {
  93.         // Get the active SmsProvider
  94.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  95.             'isActive'        =>    1,
  96.         ));
  97.         return $activeSmsProvider;
  98.     }
  99.     /**
  100.      * Returns the default SmsStatus depending on the active SmsProvider
  101.      * Note : Only one SmsProvider should be active
  102.      *
  103.      * @return null|SmsStatus
  104.      */
  105.     public function getDefaultSmsStatus()
  106.     {
  107.         // Get the active SmsProvider
  108.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  109.             'isActive'        =>    1,
  110.         ));
  111.         // Get the active SmsProvider
  112.         $provider $activeSmsProvider;
  113.         if ($provider === null)
  114.         {
  115.             $msg "No active SmsProvider";
  116.             $this->logTools->errorlog($msg);
  117.             $this->logTools->smsLogDebug($msg);
  118.             return null;
  119.         }
  120.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: getDefaultSmsStatus] Active provider is ".$provider->displayForLog());
  121.         // Get the DefaultStatus for the active SmsProvider
  122.         $providerStatus null;
  123.         switch ($provider->getName())
  124.         {
  125.             case SmsProvider::CODE_TWILIOSMS:
  126.                 $providerStatus $this->em->getRepository(SmsTwilioStatus::class)->findOneBy(array(
  127.                     'defaultValue'        =>    1,
  128.                 ));
  129.             break;
  130.             case SmsProvider::CODE_SMSMODE:
  131.                 $providerStatus $this->em->getRepository(SmsModeStatus::class)->findOneBy(array(
  132.                     'defaultValue'        =>    1,
  133.                 ));
  134.             break;
  135.         }
  136.         if ($providerStatus === null)
  137.         {
  138.             $msg "No default status for the currently active SmsProvider";
  139.             $this->logTools->errorlog($msg);
  140.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  141.             return null;
  142.         }
  143.         // Based on the code of the SmsProvider's status, get the corresponding SmsStatus
  144.         $code $providerStatus->getCode();
  145.         $status $this->em->getRepository(SmsStatus::class)->findOneByCode($code);
  146.         if ($status === null)
  147.         {
  148.             $msg "No SmsStatus found for code ".$code;
  149.             $this->logTools->errorlog($msg);
  150.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  151.             return null;
  152.         }
  153.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: getDefaultSmsStatus] SmsProvider.DefaultStatus : ".$providerStatus->displayForLog());
  154.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: getDefaultSmsStatus] SmsStatus : ".$status->displayForLog());
  155.         return $status;
  156.     }
  157.     /**
  158.      * Creates an object of type SmsTwilio or SmsMode
  159.      * depending on the active SmsProvider
  160.      * Note : Only one SmsProvider should be active
  161.      *
  162.      * @see \App\Entity\Communication\SmsProviders\SmsProvider for the documentation of the SMSProvider
  163.      *
  164.      * @uses \App\Services\Communication\SmsProviderTools::craftSmsTwilioProvider() to craft the SmsProvider depending on the active SmsProvider
  165.      * @uses \App\Services\Communication\SmsProviderTools::craftSmsModeProvider() to craft the SmsProvider depending on the active SmsProvider
  166.      *
  167.      * @param  Sms $sms
  168.      * @return null|(SmsTwilio|SmsMode)
  169.      */
  170.     public function craftSmsProvider(Sms $sms)
  171.     {
  172.         // Get the active SmsProvider
  173.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  174.             'isActive'        =>    1,
  175.         ));
  176.         // Get the active SmsProvider
  177.         $provider $activeSmsProvider;
  178.         if ($provider === null)
  179.         {
  180.             $msg "No active SmsProvider";
  181.             $this->logTools->errorlog($msg);
  182.             $this->logTools->smsLogDebug($msg);
  183.             return null;
  184.         }
  185.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: craftSmsProvider] Active provider is ".$provider->displayForLog());
  186.         // Get the DefaultStatus for the active SmsProvider
  187.         $smsProvider null;
  188.         switch ($provider->getName())
  189.         {
  190.             case SmsProvider::CODE_TWILIOSMS:
  191.                 $smsProvider $this->craftSmsTwilioProvider($sms);
  192.             break;
  193.             case SmsProvider::CODE_SMSMODE:
  194.                 $smsProvider $this->craftSmsModeProvider($sms);
  195.             break;
  196.         }
  197.         return $smsProvider;
  198.     }
  199.     /**
  200.      * Creates an object of type SmsTwilio
  201.      *
  202.      * @param  Sms $sms
  203.      * @return null|SmsTwilio
  204.      */
  205.     private function craftSmsTwilioProvider(Sms $sms)
  206.     {
  207.         $smsProvider = new SmsTwilio();
  208.         // Generate CODE for url callback
  209.         $code $this->passwordTools->generateUniqId();
  210.         $smsProvider->setCode($code);
  211.         $smsProvider->setClient($sms->getClient());
  212.         $smsProvider->setHumanResource($sms->getHumanResource());
  213.         $smsProvider->setAuthor($sms->getAuthor());
  214.         $smsProvider->setEmitter($sms->getEmitter());
  215.         $smsProvider->setRecipient($sms->getRecipient());
  216.         $smsProvider->setSociety($sms->getSociety());
  217.         $smsProvider->setSocietyGroup($sms->getSocietyGroup());
  218.         $smsProvider->setSubject($sms->getSubject());
  219.         $smsProvider->setBody($sms->getBody());
  220.         $status $this->em->getRepository(SmsTwilioStatus::class)->findOneByCode($sms->getStatus()->getCode());
  221.         $smsProvider->setStatus($status);
  222.         // Link the two objects
  223.         $smsProvider->setSms($sms);
  224.         $this->em->persist($smsProvider);
  225.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: craftSmsTwilioProvider] New SmsTwilio object created");
  226.         return $smsProvider;
  227.     }
  228.     /**
  229.      * Creates an object of type SmsMode
  230.      *
  231.      * @param  Sms $sms
  232.      * @return null|SmsTwilio
  233.      */
  234.     private function craftSmsModeProvider(Sms $sms)
  235.     {
  236.         $smsProvider = new SmsMode();
  237.         $smsProvider->setClient($sms->getClient());
  238.         $smsProvider->setHumanResource($sms->getHumanResource());
  239.         $smsProvider->setAuthor($sms->getAuthor());
  240.         $smsProvider->setEmitter($sms->getEmitter());
  241.         $smsProvider->setRecipient($sms->getRecipient());
  242.         $smsProvider->setSociety($sms->getSociety());
  243.         $smsProvider->setSocietyGroup($sms->getSocietyGroup());
  244.         $smsProvider->setSubject($sms->getSubject());
  245.         $smsProvider->setBody($sms->getBody());
  246.         $status $this->em->getRepository(SmsModeStatus::class)->findOneByCode($sms->getStatus()->getCode());
  247.         $smsProvider->setStatus($status);
  248.         // Link the two objects
  249.         $smsProvider->setSms($sms);
  250.         $this->em->persist($smsProvider);
  251.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: craftSmsModeProvider] New SmsMode object created");
  252.         return $smsProvider;
  253.     }
  254.     /**
  255.      * Sends a sms using the active SmsProvider
  256.      * Note : Only one SmsProvider should be active
  257.      *
  258.      * @uses \App\Services\Communication\SmsProviderTools::sendSmsTwilio() depending on the active SmsProvider
  259.      * @uses \App\Services\Communication\SmsProviderTools::sendSmsMode() depending on the active SmsProvider
  260.      *
  261.      * @param  SmsTwilio|SmsMode $smsProvider
  262.      * @param  string $callbackUrl
  263.      * @return true|false
  264.      */
  265.     public function sendSms($smsProvider)
  266.     {
  267.         if ($smsProvider instanceof SmsTwilio)
  268.         {
  269.             return $this->sendSmsTwilio($smsProvider);
  270.         }
  271.         if ($smsProvider instanceof SmsMode)
  272.         {
  273.             return $this->sendSmsMode($smsProvider);
  274.         }
  275.         return null;
  276.     }
  277.     /**
  278.      * Sends a sms using SmsTwilio
  279.      *
  280.      *
  281.      * @param  SmsTwilio $smsProvider
  282.      * @param  string $callbackUrl
  283.      * @return true|false
  284.      */
  285.     private function sendSmsTwilio($smsProvider)
  286.     {
  287.         // Get the active SmsProvider
  288.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  289.             'isActive'        =>    1,
  290.         ));
  291.         $configRepository $this->em->getRepository(Config::class);
  292.         $twilioId    $configRepository->findOneByName(Config::TWILIO_SMS_ACCOUNT_ID);
  293.         $twilioToken $configRepository->findOneByName(Config::TWILIO_SMS_AUTH_TOKEN);
  294.         $code $smsProvider->getCode();
  295.         $body $smsProvider->getBody();
  296.         $to   $smsProvider->getRecipient();
  297.         $from $smsProvider->getEmitter();
  298.         if (in_array(null, [$twilioId$twilioToken$code$body$to$from]))
  299.         {
  300.             return false;
  301.         }
  302.         $urlConfig $configRepository->findOneByName(Config::URL);
  303.         if ($urlConfig === null)
  304.         {
  305.             $msg "Config::URL not found";
  306.             $this->logTools->errorlog($msg);
  307.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  308.             return false;
  309.         }
  310.         $callbackUrl $urlConfig->getValue() . $this->router->generate('icod_twilio_sms_callback', array('id' => $code));
  311.         $twilioClient = new TwilioClient($twilioId->getValue(), $twilioToken->getValue());
  312.         try
  313.         {
  314.             $message $twilioClient->messages->create($to,    array(
  315.                 'from'                 => $from,
  316.                 'body'                 => $body,
  317.                 'statusCallback'     => $callbackUrl,
  318.             ));
  319.         }
  320.         catch (TwilioException $e)
  321.         {
  322.             $msg $e->getMessage();
  323.             $this->logTools->errorlog($msg);
  324.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  325.             return false;
  326.         }
  327.         $twilioSid $message->sid;
  328.         $numberSegment $message->numSegments;
  329.         if ($twilioSid !== null)
  330.         {
  331.             $smsProvider->setTwilioSid($twilioSid);
  332.         }
  333.         if ($numberSegment !== null)
  334.         {
  335.             $smsProvider->setTwilioNumberSegment($numberSegment);
  336.             $smsProvider->getSms()->setNumberSegment($numberSegment);
  337.         }
  338.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: sendSmsTwilio] SmsTwilio sent ".$smsProvider->displayForLog());
  339.         return true;
  340.     }
  341.     /**
  342.      * Sends a sms using SmsMode
  343.      *
  344.      * @param  SmsMode $smsProvider
  345.      * @param  string $callbackUrl
  346.      * @return true|false
  347.      */
  348.     private function sendSmsMode($smsProvider$sentDate null)
  349.     {
  350.         // Get the active SmsProvider
  351.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  352.             'isActive'        =>    1,
  353.         ));
  354.         // Get required params
  355.         $body $smsProvider->getBody();
  356.         $to $smsProvider->getRecipient();
  357.         $from $smsProvider->getEmitter();
  358.         $societyGroup $smsProvider->getSocietyGroup();
  359.         if (in_array(null, [$body$to$from$societyGroup]))
  360.         {
  361.             return false;
  362.         }
  363.         $configRepository $this->em->getRepository(Config::class);
  364.         // Get the SmsMode Api URL
  365.         $url $configRepository->findOneByName(Config::SMS_MODE_URL);
  366.         if ($url === null)
  367.         {
  368.             $msg "Config::SMS_MODE_URL not found";
  369.             $this->logTools->errorlog($msg);
  370.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  371.             return false;
  372.         }
  373.         $url $url->getValue();
  374.         // Get the Platform URL, used to craft callback url
  375.         $urlConfig $configRepository->findOneByName(Config::URL);
  376.         if ($urlConfig === null)
  377.         {
  378.             $msg "Config::URL not found";
  379.             $this->logTools->errorlog($msg);
  380.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  381.             return false;
  382.         }
  383.         $urlConfig $urlConfig->getValue();
  384.         // Craft callback urls
  385.         $callbackUrl $urlConfig $this->router->generate('icod_smsmode_sms_callback');
  386.         $callbackUrlResponse $urlConfig $this->router->generate('icod_smsmode_sms_response');
  387.         // Get the senderDisplay for the given SocietyGroup
  388.         $senderDisplay $this->getSmsModeSenderDisplay($societyGroup);
  389.         // Detect Encoding SMSMode
  390.         $encoding $this->detectEncodingSmsMode($body);
  391.         // Curl json bod
  392.         $curlPostBody =    array(
  393.                 "recipient" => array("to" => $to), // e.164 format
  394.                 //"from" => "36034", // https://ui.smsmode.com/settings/senders default sender is used if not specified here
  395.                 "from" => $senderDisplay// we can specify what we want here
  396.                 "body" => array(
  397.                     "text" => $body,
  398.                     "encoding" => $encoding // Encoding of the message GSM7 | UNICODE - Detected with detectEncodingSmsMode algo
  399.                 ),
  400.                 // "refClient" => "ref client : " . uniqid(),
  401.                 'callbackUrlStatus'    =>    $callbackUrl,
  402.                 'callbackUrlMo'    =>    $callbackUrlResponse,
  403.             );
  404.         // Encode the body array into Json to bes included in curl call
  405.         $curlPostBody json_encode($curlPostBody);
  406.         // If no sent date provided, use now +30 secs. This gap can be used to unsend the SMS ?
  407.         // If it's not needed, just remove sentDate from $curlPostBody, the sms will be sent asap
  408.         if ($sentDate === null)
  409.         {
  410.             $sentDate = new \DateTime('NOW');
  411.             $sentDate->modify('+30 seconds');
  412.         }
  413.         // format provided sent date in ISO8601 without timezone
  414.         $sentDate $sentDate->format('Y-m-d\TH:i:s');
  415.         // Disable for now
  416.         // $curlPostBody["sentDate"] = $sentDate;
  417.         $ch curl_init();
  418.         curl_setopt($chCURLOPT_URL$url);
  419.         curl_setopt($chCURLOPT_POSTFIELDS$curlPostBody);
  420.         curl_setopt($chCURLOPT_HTTPHEADER, array(
  421.             "X-Api-Key: " $this->smsModeAPIKey,
  422.             "Accept: application/json",
  423.             "content-Type: application/json"
  424.         ));
  425.         curl_setopt($chCURLOPT_CUSTOMREQUEST'POST');
  426.         curl_setopt($chCURLOPT_RETURNTRANSFERtrue);
  427.         $curlResult curl_exec($ch);
  428.         if (curl_errno($ch))
  429.         {
  430.             $msg "curl_exec.error ".curl_error($ch);
  431.             $this->logTools->errorlog($msg);
  432.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  433.             return false;
  434.         }
  435.         $result json_decode($curlResult);
  436.         if (!$result)
  437.         {
  438.             $msg "JSON decode failed";
  439.             $this->logTools->errorlog($msg);
  440.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  441.             return false;
  442.         }
  443.         // Task plan.io #4013
  444.         // If Success, smsMode return 201 else 4xx/5xx
  445.         // Doc : https://dev.smsmode.com/sms/v1/message
  446.         $codeReturned curl_getinfo($chCURLINFO_HTTP_CODE);
  447.         if ($codeReturned != 201)
  448.         {
  449.             $errorMessage $result?->message " - " $result?->detail;
  450.             $this->logTools->errorlog($errorMessage);
  451.             $this->logTools->smsLogDebug($errorMessage$activeSmsProvider);
  452.             return false;
  453.         }
  454.         $messageId $result?->messageId;
  455.         $acceptedAt $result?->acceptedAt;
  456.         $sentTo $result?->recipient?->to;
  457.         $from $result?->from;
  458.         $encoding $result?->body?->encoding;
  459.         $messagePartCount $result?->body?->messagePartCount;
  460.         $statusValue $result?->status?->value;
  461.         $statusDeliveryDate$result?->status?->deliveryDate;
  462.         $rawJson $curlResult;
  463.         $smsProvider->setRawData($curlResult);
  464.         if (!empty($messageId))
  465.         {
  466.             $smsProvider->setMessageId($messageId);
  467.         }
  468.         if (!empty($messagePartCount))
  469.         {
  470.             $smsProvider->setMessagePartCount($messagePartCount);
  471.             $smsProvider->getSms()->setNumberSegment($messagePartCount);
  472.         }
  473.         $this->logTools->sms_debug($this->debug"[SmsProviderTools :: sendSmsMode] SmsMode sent ".$smsProvider->displayForLog());
  474.         return true;
  475.     }
  476.     /**
  477.      * @param  SocietyGroup $societyGroup
  478.      * @return string
  479.      */
  480.     public function getSmsModeSenderDisplay(SocietyGroup $societyGroup)
  481.     {
  482.         $defaultSenderDisplay SmsMode::DEFAULT_SHORTCODE;
  483.         $senderDisplay null;
  484.         $smsPhoneNumber $this->em->getRepository(SmsPhoneNumber::class)->findOneBy(array(
  485.             'societyGroup'        =>    $societyGroup,
  486.         ));
  487.         if ($smsPhoneNumber !== null)
  488.         {
  489.             $senderDisplay $smsPhoneNumber->getSenderDisplay();
  490.             if (!empty($senderDisplay))
  491.             {
  492.                 return $senderDisplay;
  493.             }
  494.         }
  495.         return $defaultSenderDisplay;
  496.     }
  497.     public function detectEncodingSmsMode(string $body)
  498.     {
  499.         $gsm7 = array(
  500.             "!"'"'"#""$""%""&""'""("")"")"")""*""+"",""-",
  501.             ".""/""0""1""2""3""4""5""6""7""8""9"":"";""<",
  502.             "="">""?""@""\r""\n"" ""A""B""C""D""E""F""G""H",
  503.             "I""J""K""L""M""N""O""P""Q""R""S""T""U""V""W""X""Y""Z",
  504.             "a""b""c""d""e""f""g""h""i""j""k""l""m""n""o""p""q""r",
  505.             "s""t""u""v""w""x""y""z""¡""£""¤""Â¥""§""¿""Ä""Ã…""Æ""Ç",
  506.             "É""Ñ""Ö""Ø""Ü""ß""à""ä""Ã¥""æ""è""é""ì""ñ""ò""ö""ø""ù",
  507.             "ü""Γ""Θ""Λ""Ξ""Π""Σ""Φ""Ψ""Ω""∆"
  508.         );
  509.         $gsm7Extended = array("€""{""|""}""~""[""]""^""\f");
  510.         $encoding "GSM7";
  511.         foreach(mb_str_split($body) as $char)
  512.         {
  513.             if(!in_array($char$gsm7) && !in_array($char$gsm7Extended))
  514.             {
  515.                 $encoding "UNICODE";
  516.                 break;
  517.             }
  518.         }
  519.         return $encoding;
  520.     }
  521.     /**
  522.      * Creates a SmsTwilioStatus|SmsModeStatus for a given value
  523.      * depending on the active SmsProvider
  524.      * Note : Only one SmsProvider should be active
  525.      *
  526.      * @uses \App\Services\Communication\SmsProviderTools::createSmsTwilioStatus() depending on the active SmsProvider
  527.      * @uses \App\Services\Communication\SmsProviderTools::createSmsModeStatus() depending on the active SmsProvider
  528.      *
  529.      * @param  SmsTwilio|SmsMode $smsProvider
  530.      * @param  string $value
  531.      * @return true|false
  532.      */
  533.     public function createSmsStatus($smsProvider$value)
  534.     {
  535.         $smsProviderStatus null;
  536.         if ($smsProvider instanceof SmsTwilio)
  537.         {
  538.             $smsProviderStatus $this->createSmsTwilioStatus($value);
  539.         }
  540.         if ($smsProvider instanceof SmsMode)
  541.         {
  542.             $smsProviderStatus $this->createSmsModeStatus($value);
  543.         }
  544.         if ($smsProviderStatus === null)
  545.         {
  546.             return null;
  547.         }
  548.         $status = new SmsStatus();
  549.         $status->setValue($value);
  550.         $status->setCode($smsProviderStatus->getCode());
  551.         $this->em->persist($status);
  552.         return array(
  553.             'smsStatus'                => $status,
  554.             'smsProviderStatus'        => $smsProviderStatus,
  555.         );
  556.     }
  557.     /**
  558.      * Creates a SmsTwilioStatus for a given value
  559.      * Can be called from outside of the service
  560.      *
  561.      * @param  string $value
  562.      * @return null|SmsTwilioStatus
  563.      */
  564.     private function createSmsTwilioStatus($value)
  565.     {
  566.         $lastCode $this->em
  567.             ->getRepository(SmsTwilioStatus::class)
  568.             ->findOneBy(
  569.                 array(),
  570.                 array('code' => 'DESC')
  571.             );
  572.         $code 1;
  573.         if ($lastCode !== null)
  574.         {
  575.             $code $lastCode->getCode() + 1;
  576.         }
  577.         $status = new SmsTwilioStatus();
  578.         $status->setStatusTwilio($value);
  579.         $status->setValue($value);
  580.         $status->setCode($code);
  581.         $this->em->persist($status);
  582.         return $status;
  583.     }
  584.     /**
  585.      * Can be called from outside of the service
  586.      * Creates a SmsModeStatus for a given value
  587.      *
  588.      * @param  string $value
  589.      * @return null|SmsModeStatus
  590.      */
  591.     private function createSmsModeStatus($value)
  592.     {
  593.         $lastCode $this->em
  594.             ->getRepository(SmsModeStatus::class)
  595.             ->findOneBy(
  596.                 array(),
  597.                 array('code' => 'DESC')
  598.             );
  599.         $code 1;
  600.         if ($lastCode !== null)
  601.         {
  602.             $code $lastCode->getCode() + 1;
  603.         }
  604.         $status = new SmsModeStatus();
  605.         $status->setStatusSmsMode($value);
  606.         $status->setValue($value);
  607.         $status->setCode($code);
  608.         $this->em->persist($status);
  609.         return $status;
  610.     }
  611.     /**
  612.      * Tries to find a SmsTwilioStatus|SmsModeStatus with the given value (statusValue)
  613.      * depending on the active SmsProvider.
  614.      * If the status is not found, one is created for the given value.
  615.      * In both cases, the corresponding SmsStatus is also returned.
  616.      * Note : Only one SmsProvider should be active
  617.      *
  618.      * @uses \App\Services\Communication\SmsProviderTools::handleSmsTwilioStatus() depending on the active SmsProvider
  619.      * @uses \App\Services\Communication\SmsProviderTools::handleSmsModeStatus() depending on the active SmsProvider
  620.      *
  621.      * @param  Sms $sms
  622.      * @param  string $value
  623.      * @return null|array
  624.      */
  625.     public function handleSmsStatus(Sms $sms$statusValue)
  626.     {
  627.         $smsProvider $sms->getProvider();
  628.         if ($smsProvider === null)
  629.         {
  630.             return null;
  631.         }
  632.         if ($smsProvider->isSmsTwilio())
  633.         {
  634.             return $this->handleSmsTwilioStatus($smsProvider$statusValue);
  635.         }
  636.         if ($smsProvider->isSmsMode())
  637.         {
  638.             return $this->handleSmsModeStatus($smsProvider$statusValue);
  639.         }
  640.         // if ($smsProvider instanceof SmsTwilio)
  641.         // {
  642.         //     return $this->handleSmsTwilioStatus($smsProvider, $statusValue);
  643.         // }
  644.         // if ($smsProvider instanceof SmsMode)
  645.         // {
  646.         //     return $this->handleSmsModeStatus($smsProvider, $statusValue);
  647.         // }
  648.         return null;
  649.     }
  650.     /**
  651.      * Tries to find a SmsTwilioStatus with the given value (statusValue).
  652.      * If the status is not found, one is created for the given value.
  653.      * In both cases, the corresponding SmsStatus is also returned.
  654.      *
  655.      * Can be called from outside of the service
  656.      *
  657.      * @param  SmsProvider $smsProvider
  658.      * @param  string $value
  659.      * @return null|array
  660.      */
  661.     public function handleSmsTwilioStatus(SmsProvider $smsProvider$statusValue)
  662.     {
  663.         // Get the active SmsProvider
  664.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  665.             'isActive'        =>    1,
  666.         ));
  667.         $smsProviderStatus $this->em
  668.             ->getRepository(SmsTwilioStatus::class)
  669.             ->findOneByStatusTwilio($statusValue);
  670.         if ($smsProviderStatus === null)
  671.         {
  672.             // Create unknown status
  673.             $statusData $this->createSmsStatus($smsProvider$statusValue);
  674.             if ($statusData === null)
  675.             {
  676.                 $msg "SmsTwilioStatus not found and creation of a new custom status failed";
  677.                 $this->logTools->errorlog($msg);
  678.                 $this->logTools->smsLogDebug($msg$activeSmsProvider);
  679.                 return null;
  680.             }
  681.             $smsStatus $statusData['smsStatus'];
  682.             $smsProviderStatus $statusData['smsProviderStatus'];
  683.         }
  684.         else
  685.         {
  686.             $code $smsProviderStatus->getCode();
  687.             $smsStatus $this->em->getRepository(SmsStatus::class)->findOneByCode($code);
  688.             if ($smsStatus === null)
  689.             {
  690.                 $msg "SmsStatus not found for code $code";
  691.                 $this->logTools->errorlog($msg);
  692.                 $this->logTools->smsLogDebug($msg$activeSmsProvider);
  693.                 return null;
  694.             }
  695.         }
  696.         return array(
  697.             'smsStatus'                =>    $smsStatus,
  698.             'smsProviderStatus'        =>    $smsProviderStatus,
  699.         );
  700.     }
  701.     /**
  702.      * Tries to find a SmsModeStatus with the given value (statusValue).
  703.      * If the status is not found, one is created for the given value.
  704.      * In both cases, the corresponding SmsStatus is also returned.
  705.      *
  706.      * Can be called from outside of the service
  707.      *
  708.      * @param  string $value
  709.      * @return null|array
  710.      */
  711.     public function handleSmsModeStatus(SmsProvider $smsProvider$statusValue)
  712.     {
  713.         // Get the active SmsProvider
  714.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  715.             'isActive'        =>    1,
  716.         ));
  717.         $smsProviderStatus $this->em
  718.             ->getRepository(SmsModeStatus::class)
  719.             ->findOneByStatusSmsMode($statusValue);
  720.         if ($smsProviderStatus === null)
  721.         {
  722.             // Create unknown status
  723.             $statusData $this->createSmsStatus($smsProvider$statusValue);
  724.             if ($statusData === null)
  725.             {
  726.                 $msg "SmsModeStatus not found and creation of a new custom status failed";
  727.                 $this->logTools->errorlog($msg);
  728.                 $this->logTools->smsLogDebug($msg$activeSmsProvider);
  729.                 return null;
  730.             }
  731.             $smsStatus $statusData['smsStatus'];
  732.             $smsProviderStatus $statusData['smsProviderStatus'];
  733.         }
  734.         else
  735.         {
  736.             $code $smsProviderStatus->getCode();
  737.             $smsStatus $this->em->getRepository(SmsStatus::class)->findOneByCode($code);
  738.             if ($smsStatus === null)
  739.             {
  740.                 $msg "SmsStatus not found for code $code";
  741.                 $this->logTools->errorlog($msg);
  742.                 $this->logTools->smsLogDebug($msg$activeSmsProvider);
  743.                 return null;
  744.             }
  745.         }
  746.         return array(
  747.             'smsStatus'                =>    $smsStatus,
  748.             'smsProviderStatus'        =>    $smsProviderStatus,
  749.         );
  750.     }
  751.     /**
  752.      * Creates Sms, SmsTwilio, ExternalMessage for the given data.
  753.      * Objects are properly linked.
  754.      * In case of success returns an array containing the three objects.
  755.      *
  756.      * Called by SmsTwilioController :: smsResponse
  757.      * when someone answers to the Twilio sms they received
  758.      *
  759.      * @uses \App\Services\Platform\ExternalMessageTools::createExternalMessageForSmsChild()
  760.      *
  761.      * @param  SmsTwilio $parentSmsProvider
  762.      * @param  string $value
  763.      * @return null|array
  764.      */
  765.     public function craftObjectsFromTwilioData(SmsTwilio $parentSmsProvider$twilioData)
  766.     {
  767.         // Get the active SmsProvider
  768.         $activeSmsProvider $this->em->getRepository(SmsProvider::class)->findOneBy(array(
  769.             'isActive'        =>    1,
  770.         ));
  771.         $smsProviderTwilio $this->em->getRepository(SmsProvider::class)->findOneByName(SmsProvider::CODE_TWILIOSMS);
  772.         if ($smsProviderTwilio === null)
  773.         {
  774.             $msg "SmsProvider not found for name ".SmsProvider::CODE_TWILIOSMS;
  775.             $this->logTools->errorlog($msg);
  776.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  777.             return null;
  778.         }
  779.         // Handle Status for both Sms and TwilioSms
  780.         $statusValue $twilioData["SmsStatus"];
  781.         $statusData $this->handleSmsTwilioStatus($smsProviderTwilio$statusValue);
  782.         if ($statusData === null)
  783.         {
  784.             $msg "SmsTwilioStatus not found and creation of a new custom status failed";
  785.             $this->logTools->errorlog($msg);
  786.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  787.             return null;
  788.         }
  789.         $smsStatus $statusData['smsStatus'];
  790.         $smsProviderStatus $statusData['smsProviderStatus'];
  791.         // Get the SmsParent
  792.         $parentSms $parentSmsProvider->getSms();
  793.         if ($parentSms === null)
  794.         {
  795.             $msg "ParentSms not found for parentSmsProvider ".$parentSmsProvider->displayForLog();
  796.             $this->logTools->errorlog($msg);
  797.             $this->logTools->smsLogDebug($msg$activeSmsProvider);
  798.             return null;
  799.         }
  800.         // At this point nothing can go wrong any more, start creating data
  801.         //----------------------------------------------------------------------
  802.         // PART ONE : Create the SmsTwilio
  803.         $smsProvider = new SmsTwilio();
  804.         $smsProvider->setAuthor($parentSmsProvider->getAuthor());
  805.         $smsProvider->setClient($parentSmsProvider->getClient());
  806.         $smsProvider->setSocietyGroup($parentSmsProvider->getSocietyGroup());
  807.         $smsProvider->setSociety($parentSmsProvider->getSociety());
  808.         $smsProvider->setTwilioTo($twilioData["To"]);
  809.         $smsProvider->setEmitter($twilioData["From"]);
  810.         $smsProvider->setRecipient($twilioData["To"]);
  811.         $smsProvider->setSubject($parentSmsProvider->getSubject());
  812.         $smsProvider->setBody($twilioData["Body"]);
  813.         $smsProvider->setTwilioSid($twilioData["SmsMessageSid"]);
  814.         $smsProvider->setTwilioNumberSegment($twilioData["NumSegments"]);
  815.         $smsProvider->setCallbackDate(new \DateTime());
  816.         $smsProvider->setTwilioRaw(json_encode($twilioData));
  817.         $smsProvider->setStatus($smsProviderStatus);
  818.         $uniqueCode $this->passwordTools->generateUniqId();
  819.         $smsProvider->setCode($uniqueCode);
  820.         //----------------------------------------------------------------------
  821.         // PART TWO : Create the Sms
  822.         $sms = new Sms();
  823.         $sms->setCreationDate($smsProvider->getCreationDate());
  824.         $sms->setRecipient($smsProvider->getRecipient());
  825.         $sms->setEmitter($smsProvider->getEmitter());
  826.         $sms->setSubject($smsProvider->getSubject());
  827.         $sms->setBody($smsProvider->getBody());
  828.         $sms->setError($smsProvider->getError());
  829.         $sms->setPrice($smsProvider->getPrice());
  830.         $sms->setNumberSegment($smsProvider->getTwilioNumberSegment());
  831.         $sms->setAuthor($smsProvider->getAuthor());
  832.         $sms->setClient($smsProvider->getClient());
  833.         $sms->setHumanResource($smsProvider->getHumanResource());
  834.         $sms->setSociety($smsProvider->getSociety());
  835.         $sms->setSocietyGroup($smsProvider->getSocietyGroup());
  836.         $sms->setStatus($smsStatus);
  837.         $sms->setMission($parentSms->getMission());
  838.         // smsProviderTwilio = SmsProvider :: class -> SmsProvider::CODE_TWILIOSMS
  839.         $sms->setProvider($smsProviderTwilio);
  840.         //----------------------------------------------------------------------
  841.         // PART THREE : Link objects (part.one)
  842.         // This is needed to create the ExternalMessage
  843.         // Sms : Link the parent and child Sms
  844.         $sms->setParent($parentSms);
  845.         // SmsProvider : Link the parent and child
  846.         $smsProvider->setParent($parentSmsProvider);
  847.         // Make the link between the Sms and TwilioSms
  848.         $smsProvider->setSms($sms);
  849.         //----------------------------------------------------------------------
  850.         // PART FOUR : Create the ExternalMessage
  851.         $externalMessage $this->externalMessageTools->createExternalMessageForSmsChild($sms);
  852.         if ($externalMessage === null)
  853.         {
  854.             // Error is logged in ExternalMessageTools
  855.             return null;
  856.         }
  857.         // At this point the ExternalMessage and the Sms are already linked (done in ExternalMessageTools)
  858.         // $externalMessage->setSms($sms);
  859.         //----------------------------------------------------------------------
  860.         // PART FIVE : Persist data
  861.         $this->em->persist($sms);
  862.         $this->em->persist($smsProvider);
  863.         return array(
  864.             'sms'                =>    $sms,
  865.             'smsProvider'        =>    $smsProvider,
  866.             'externalMessage'    =>    $externalMessage,
  867.         );
  868.     }
  869. }