/**
  * Buy a product
  *
  * @param User     $user
  * @param IPayment $paymentService
  * @param array    $paymentDetails
  *
  * @throws Exception
  */
 public function buy(User $user, IPayment $paymentService, $paymentDetails)
 {
     if (!$this->_isSalable()) {
         throw new Exception('Not for sale');
     }
     if ($this->_isPremium() && !$user->isSubscribed()) {
         throw new Exception('Need to continue subscription to buy this product');
     }
     //...
     if ($paymentService->processPayment($orderData)) {
         $paymentService->savePayment();
         $order = new Order($orderData, $paymentService->getData());
         $order->save();
         return $order;
     }
     throw new Exception('An error occurred while processing the payment');
 }
 /**
  * Pay for subscription and save it to DB
  *
  * @param User      $user
  * @param int       $units
  * @param IPayment  $paymentService
  * @param array     $paymentDetails
  *
  * @return bool
  * @throws Exception
  */
 public static function buy(User $user, $units, IPayment $paymentService, $paymentDetails)
 {
     $userData = $user->getData();
     if ($user->getUserGroup() == User::ADMIN_USER_GROUP) {
         throw new Exception('Administrators can\'t buy subscription');
     }
     if ($user->isSubscribed()) {
         $units += ($userData['subscribed_to'] - strtotime(date('Y-m-d', time()) . ' 00:00:00')) / 86400;
     }
     //...
     if ($paymentService->processPayment($paymentData)) {
         $userData['subscribed_to'] = strtotime(date('Y-m-d', strtotime("+{$units} days")) . ' 00:00:00');
         $paymentService->savePayment();
         return true;
     }
     throw new Exception('An error occurred while processing the payment');
     //...
 }