Search code examples
phpsymfonypaypalpayment-gatewaypayum

Setting up Payum Bundle with Symfony2 giving error


I am working with Symfony 2.6 and trying to setup PayumBundle (paypal express checkout) and I am getting an error

InvalidConfigurationException in BaseNode.php line 313: Invalid configuration for path "payum.security.token_storage": The storage entry must be a valid model class. It is set Acme\featuresBundle\Entity\PaymentToken

I am following the steps mentioned in there documetation

This is how my config.yml looks like

    doctrine:
        orm:
            auto_generate_proxy_classes: "%kernel.debug%"
            entity_managers:
                default:
                    auto_mapping: true
                    mappings:
                        payum:
                            is_bundle: false
                            type: xml
                            dir: %kernel.root_dir%/../vendor/payum/core/Payum/Core/Bridge/Doctrine/Resources/mapping
                            prefix: Payum\Core\Model

    payum:
        security:
            token_storage:
                Acme\featuresBundle\Entity\PaymentToken: { doctrine: orm }

        storages:
            Acme\featuresBundle\Entity\PaymentDetails: { doctrine: orm }

        contexts:
            paypal:
                paypal_express_checkout_nvp:
                    username: 'asdasd'
                    password: 'adsasd'
                    signature: 'asdasdasd'
                    sandbox: true

This is my Entity PaymentToken

namespace Acme\featuresBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Token;

/**
 * @ORM\Table
 * @ORM\Entity
 */
class PaymentToken extends Token
{

}

And this is Entity PaymentDetails

namespace Acme\featuresBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Order as BaseOrder;

/**
 * @ORM\Table
 * @ORM\Entity
 */
class PaymentDetails extends BaseOrder
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     *
     * @var integer $id
     */
    protected $id;
}

I have gone through alot of documentation online and other posts like this but I dont understand why I am getting this error.

The storage entry must be a valid model class. It is set Acme\featuresBundle\Entity\PaymentToken

I cant even get to the controller so something tells me it is the config.yml configuration of Payum that is not set correctly. I have gone through the documentation over and over and over and I cant seem to find what am I doing wrong.

I will really appreciate any help in getting pass this error.


Solution

  • I finally managed to get it done.

    I needed 4 files

    1. PaymentController
    2. Orders (Entity)
    3. PaymentToken (Entity)
    4. Orders (Model)

    This is my PaymentController looks like

    <?php
    
    namespace ClickTeck\featuresBundle\Controller;
    
    use ClickTeck\featuresBundle\Entity\Orders;
    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Payum\Paypal\ExpressCheckout\Nvp\Api;
    use Payum\Core\Registry\RegistryInterface;
    use Payum\Core\Request\GetHumanStatus;
    use Payum\Core\Security\GenericTokenFactoryInterface;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\JsonResponse;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration as Extra;
    
    
        class PaymentController extends Controller
        {
            public function preparePaypalExpressCheckoutPaymentAction(Request $request)
            {
                $paymentName = 'paypal';
                $eBook = array(
                    'author' => 'Jules Verne',
                    'name' => 'The Mysterious Island',
                    'description' => 'The Mysterious Island is a novel by Jules Verne, published in 1874.',
                    'price' => 8.64,
                    'currency_symbol' => '$',
                    'currency' => 'USD',
                    'clientId' => '222',
                    'clientemail' => '[email protected]'
                );
    
    
    
                $storage = $this->get('payum')->getStorage('ClickTeck\featuresBundle\Entity\Orders');
                /** @var $paymentDetails Orders */
                $paymentDetails = $storage->create();
    
                $paymentDetails->setNumber(uniqid());
                $paymentDetails->setCurrencyCode($eBook['currency']);
                $paymentDetails->setTotalAmount($eBook['price']);
                $paymentDetails->setDescription($eBook['description']);
                $paymentDetails->setClientId($eBook['clientId']);
                $paymentDetails->setClientEmail($eBook['clientemail']);
    
    
                $paymentDetails['PAYMENTREQUEST_0_CURRENCYCODE'] = $eBook['currency'];
                $paymentDetails['PAYMENTREQUEST_0_AMT'] = $eBook['price'];
                $paymentDetails['NOSHIPPING'] = Api::NOSHIPPING_NOT_DISPLAY_ADDRESS;
                $paymentDetails['REQCONFIRMSHIPPING'] = Api::REQCONFIRMSHIPPING_NOT_REQUIRED;
                $paymentDetails['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = Api::PAYMENTREQUEST_ITERMCATEGORY_DIGITAL;
                $paymentDetails['L_PAYMENTREQUEST_0_AMT0'] = $eBook['price'];
                $paymentDetails['L_PAYMENTREQUEST_0_NAME0'] = $eBook['author'].'. '.$eBook['name'];
                $paymentDetails['L_PAYMENTREQUEST_0_DESC0'] = $eBook['description'];
                $storage->update($paymentDetails);
                $captureToken = $this->getTokenFactory()->createCaptureToken(
                    $paymentName,
                    $paymentDetails,
                    'payment_done'
                );
                $paymentDetails['INVNUM'] = $paymentDetails->getId();
                $storage->update($paymentDetails);
                return $this->redirect($captureToken->getTargetUrl());
    
    
            }
    
            public function doneAction(Request $request)
            {
    
                $token = $this->get('payum.security.http_request_verifier')->verify($request);
    
                $payment = $this->get('payum')->getPayment($token->getPaymentName());
    
                // you can invalidate the token. The url could not be requested any more.
                // $this->get('payum.security.http_request_verifier')->invalidate($token);
    
                // Once you have token you can get the model from the storage directly.
                //$identity = $token->getDetails();
                //$order = $payum->getStorage($identity->getClass())->find($identity);
    
                // or Payum can fetch the model for you while executing a request (Preferred).
                $payment->execute($status = new GetHumanStatus($token));
                $order = $status->getFirstModel();
    
                // you have order and payment status
                // so you can do whatever you want for example you can just print status and payment details.
    
                return new JsonResponse(array(
                    'status' => $status->getValue(),
                    'response' => array(
                        'order' => $order->getTotalAmount(),
                        'currency_code' => $order->getCurrencyCode(),
                        'details' => $order->getDetails(),
                    ),
                ));
    
            }
    
            /**
             * @return RegistryInterface
             */
            protected function getPayum()
            {
                return $this->get('payum');
            }
            /**
             * @return GenericTokenFactoryInterface
             */
            protected function getTokenFactory()
            {
                return $this->get('payum.security.token_factory');
            }
    
        }
    

    This is my Orders Entity

    <?php
    
    namespace ClickTeck\featuresBundle\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use ClickTeck\featuresBundle\Model\Orders as BasePaymentDetails;
    
    /**
     * Orders
     */
    class Orders extends BasePaymentDetails
    {
        /**
         * @var integer
         */
        protected $id;
    
        private $number;
    
        private $description;
    
        private $client_email;
    
        private $client_id;
    
        private $total_amount;
    
        private $currency_code;
    
        protected $details;
    
    
    
        /**
         * Get id
         *
         * @return integer 
         */
        public function getId()
        {
            return $this->id;
        }
    
        /**
         * Set number
         *
         * @param integer $number
         * @return Orders
         */
        public function setNumber($number)
        {
            $this->number = $number;
    
            return $this;
        }
    
        /**
         * Get number
         *
         * @return integer 
         */
        public function getNumber()
        {
            return $this->number;
        }
    
        /**
         * Set description
         *
         * @param string $description
         * @return Orders
         */
        public function setDescription($description)
        {
            $this->description = $description;
    
            return $this;
        }
    
        /**
         * Get description
         *
         * @return string 
         */
        public function getDescription()
        {
            return $this->description;
        }
    
        /**
         * Set client_email
         *
         * @param string $clientEmail
         * @return Orders
         */
        public function setClientEmail($clientEmail)
        {
            $this->client_email = $clientEmail;
    
            return $this;
        }
    
        /**
         * Get client_email
         *
         * @return string 
         */
        public function getClientEmail()
        {
            return $this->client_email;
        }
    
        /**
         * Set client_id
         *
         * @param string $clientId
         * @return Orders
         */
        public function setClientId($clientId)
        {
            $this->client_id = $clientId;
    
            return $this;
        }
    
        /**
         * Get client_id
         *
         * @return string 
         */
        public function getClientId()
        {
            return $this->client_id;
        }
    
        /**
         * Set total_amount
         *
         * @param float $totalAmount
         * @return Orders
         */
        public function setTotalAmount($totalAmount)
        {
    
            $this->total_amount = $totalAmount;
            return $this;
        }
    
        /**
         * Get total_amount
         *
         * @return float
         */
        public function getTotalAmount()
        {
            return $this->total_amount;
        }
    
        /**
         * Set currency_code
         *
         * @param string $currencyCode
         * @return Orders
         */
        public function setCurrencyCode($currencyCode)
        {
            $this->currency_code = $currencyCode;
    
            return $this;
        }
    
        /**
         * Get currency_code
         *
         * @return string 
         */
        public function getCurrencyCode()
        {
            return $this->currency_code;
        }
    
        /**
         * Set details
         *
         * @param string $details
         * @return Orders
         */
        public function setDetails($details)
        {
            $this->details = $details;
    
            return $this;
        }
    
        /**
         * Get details
         *
         * @return string 
         */
        public function getDetails()
        {
            return $this->details;
        }
    }
    

    This is my PaymentToken Entity

    <?php
    
    namespace ClickTeck\featuresBundle\Entity;
    
    use Doctrine\ORM\Mapping as ORM;
    use Payum\Core\Model\Token;
    
    /**
     * PaymentToken
     */
    class PaymentToken extends Token
    {
    
    }
    

    This is my Orders model

    <?php
    
    namespace ClickTeck\featuresBundle\Model;
    
    use Payum\Core\Model\ArrayObject;
    
        class Orders extends ArrayObject
        {
            protected $id;
            /**
             * @return int
             */
            public function getId()
            {
                return $this->id;
            }
        }
    
    1. Now when I call the Action preparePaypalExpressCheckoutPaymentAction via route
    2. I get redirected to make the payment
    3. I can see the response in doneAction

    Very neat library. Took me a while to figure it out and I am glad it works now. I am sure i have alot more to learn about Payum and I hope someone can confirm if this is the right way :)