krzysztof-gzocha / payu
与PayU集成
Requires
- php: >=5.4.0
- ext-curl: *
- doctrine/annotations: >=v1.1
- jms/serializer: >=0.11.0
- kriswallsmith/buzz: 0.13
- psr/log: 1.0.*@dev
- symfony/validator: >=2.0.4
Requires (Dev)
- codeception/codeception: 2.1.*@dev
- codeclimate/php-test-reporter: dev-master
- fabpot/php-cs-fixer: >=v1.0
- phing/phing: >=2.4.12
- phpmd/phpmd: >=2.0.0
- phpspec/phpspec: 2.1.*
This package is not auto-updated.
Last update: 2024-09-25 14:54:10 UTC
README
这个用PHP编写的库将允许您轻松地集成PayU API v2.1。
支持PHP版本 >=5.4 和 HHVM。
通过composer安装
要安装此库,只需在composer中添加要求。
您可以通过以下方式实现
php /path/to/composer.phar require "krzysztof-gzocha/payu:v1.0.1"
或简单地将其添加到composer.json中
{ "require": { "krzysztof-gzocha/payu": "v1.0.1" } }
并运行
composer install
基本用法
1. 配置
默认配置对象是 \Team3\PayU\Configuration\Configuration
,但任何实现 \Team3\PayU\Configuration\ConfigurationInterface
的对象都可以完成这项工作。大多数配置参数已经定义,您只需设置从PayU获取的凭据(商户ID和私钥)。测试账户凭据已在 \Team3\PayU\Configuration\Credentials\TestCredentials
中定义,因此如果您只想测试应用程序,则可以使用此类。
使用测试凭据进行配置
use Team3\PayU\Configuration\Configuration; use Team3\PayU\Configuration\Credentials\TestCredentials; $payuConfiguration = new Configuration( new TestCredentials() );
使用真实凭据进行配置
use Team3\PayU\Configuration\Configuration; use Team3\PayU\Configuration\Credentials\Credentials; $payuConfiguration = new Configuration( new Credentials('<merchant pos id>', '<private key>') );
2. 创建基本订单对象
请注意,这些示例中创建的订单配置不足。一些必需的参数(如OpenPayU-Signature、totalAmount、customerIp等)仍然缺失。您可以自动添加它们,但这将在另一章中描述。这两个示例都描述了最基本的配置。由这两个示例创建的订单是相同的。
2.1 使用库中的订单对象
此库中的订单对象默认表示为 \Team3\PayU\Order\Model\Order
,但任何实现 \Team3\PayU\Order\Model\OrderInterface
的对象都可以使用。本章是关于创建此对象,但如果您正在将此库与当前正在运行的应用程序集成,则可以使用下一章中描述的注解自动执行此操作。
示例订单(单个产品)
use \Team3\PayU\Order\Model\Order; use \Team3\PayU\Order\Model\Products\Product; use \Team3\PayU\Order\Model\Money\Money; $order = new Order(); $product = new Product(); $order ->setDescription('Example order') ->setCurrencyCode('EUR') ->setOrderId('123456'); $product ->setName('Some product') ->setQuantity(10) ->setUnitPrice(new Money(10)); $order->getProductCollection()->addProduct($product);
2.2 使用注解
如果您已经在应用程序中有一个订单对象,则不需要创建另一个订单对象。您只需在返回有用参数的 方法 上放置单个注解 \Team3\PayU\Annotation\PayU
。假设您有一个自己的订单类称为 \Users\App\UserOrder
和产品类称为 \Users\App\UserProduct
。注解可以设置在公共、受保护或私有方法上。您可以按以下方式添加注解
namespace Users\App; use Team3\PayU\Annotation\PayU; use Team3\PayU\Order\Model\Money\Money; class UserOrder { /** * @PayU(propertyName="general.orderId") */ public function getId() { return '123456'; } /** * @PayU(propertyName="general.description") */ private function getDescription() { return 'Example order'; } /** * @PayU(propertyName="general.currencyCode") */ private function getCurrencyCode() { return 'EUR'; } /** * @PayU(propertyName="productCollection") */ private function getProducts() { // Both array and \Traversable object can be returned return [ new UserProduct(), ]; } } class UserProduct { /** * @PayU(propertyName="product.name") */ private function getName() { return 'Some product'; } /** * @PayU(propertyName="product.quantity") */ private function getQuantity() { return 10; } /** * @PayU(propertyName="product.unitPrice") */ private function getPrice() { // This method should return anything // that implements \Team3\PayU\Order\Model\Money\MoneyInterface return new Money(10); } }
所有属性名称都可以在 \Team3\PayU\Order\Transformer\UserOrder\TransformerProperties
中找到。值得一提的是,其中一个注解特别适用于复杂的架构。它称为 follow
注解。如果您必须从不同的、相互连接的实体中收集所需的参数,则可以使用此注解。此方法的结果将通过此转换器再次传递。
现在,要创建订单对象,您必须使用UserOrderTransfomer,该转换器将实际转换您的对象以供库使用。为此,您可以按照以下示例操作
use \Team3\PayU\Order\Transformer\UserOrder\UserOrderTransformerFactory; $order = new Order(); // Order for library purposes $userOrder = new UserOrder(); // Order from users application $logger = new NullLogger(); // ONLY for example. Use real logger. $transformerFactory = new UserOrderTransformerFactory(); $transformer = $transformerFactory->build($logger); // Will transform UserOrder into Order $transformer->transform($order, $userOrder); // $order->getDescription() => 'Example order'
3. 订单参数自动完成
在提供其他必需参数(如签名)方面,您不会孤立无援。为此,您可以使用此代码
use \Team3\PayU\NullLogger; use \Team3\PayU\Order\Autocomplete\OrderAutocompleteFactory; $logger = new NullLogger(); // ONLY for example. Use real logger. $autocompleteFactory = new OrderAutocompleteFactory(); $autocomplete = $autocompleteFactory->build($logger); // Complete $order with parameters. Use $credentials try { $autocomplete->autocomplete($order, $credentials); } catch (OrderAutocompleteException $exception) { // Something went wrong. } // $order->getSignature() => '7f46165474d11ee5836777d85df2cdab';
4. 通知PayU关于新订单
要通知PayU关于我们的新订单,您必须发送OrderCreateRequest并使用正确构建的对象,检查响应的HTTP状态码,将响应反序列化为OrderCreateResponse对象,检查请求状态是否为SUCCESS
,并将用户重定向到指定的URL。以下是如何使用RequestProcess的示例
use \Symfony\Component\Validator\ConstraintViolationListInterface; use \Team3\PayU\Communication\Process\RequestProcessFactory; use \Team3\PayU\Communication\Request\OrderCreateRequest; use \Team3\PayU\Communication\Response\OrderCreateResponse; use \Team3\PayU\NullLogger; $logger = new NullLogger(); // ONLY for example. Use real logger. $requestProcessFactory = new RequestProcessFactory(); $requestProcess = $requestProcessFactory->build($logger); try { /** @var OrderCreateResponse $orderCreateResponse **/ $orderCreateResponse = $requestProcess->process( new OrderCreateRequest($order), $configuration ); } catch (InvalidRequestDataObjectException $exception) { /** * $order is invalid. Violations are stored in exception. * @var ConstraintViolationListInterface $violations */ $violations = $exception->getViolations(); } catch (PayUException $exception) { // something went wrong. } if ($orderCreateResponse->getRequestStatus()->isSuccess()) { // Request was ok. You can redirect user to given url $this->redirectTo( $orderCreateResponse->getRedirectUri() ); } else { // Request was not ok. // Pass this information to user however you want }
5. 从PayU检索订单
获取信息的过程与创建新订单类似。您可以使用相同的RequestProcess,但需要使用不同的Request对象。示例:
// $requestProcess was created in exactly the same way. use \Team3\PayU\Communication\Response\OrderRetrieveResponse; $order->setPayUOrderId('<order id from payu>'); $requestProcess->shouldValidate(false); // We dont need to validate this time try { /** @var OrderRetrieveResponse $orderStatusResponse */ $orderStatusResponse = $requestProcess->process( new OrderRetrieveRequest($order), // $order->getPayUOrderId() should not be null $configuration ); } catch (PayUException $exception) { // Something went wrong.. } // Order status: // $status = $orderStatusResponse->getFirstOrder()->getStatus(); // Completed status: // $status->isCompleted() -> true
6. 订单取消请求
您可以向PayU发送请求,表示“取消此订单”。为此,您可以使用上面描述的RequestProcess。如果您向它传递一个对象Team3\Communication\Request\OrderCancelRequest
,并用OrderInterface
和PayUOrderId
参数初始化它,那么您将取消订单。在这种情况下,RequestProcess将返回Team3\Communication\Response\OrderCancelResponse
。您可以在文档中查看其参数。请注意,参数status
是请求的状态,而不是订单的状态!
7. 处理订单通知
PayU可以通知您订单的任何更改。要使用此机制,您只需定义$order->setNotifyUrl('<您的应用中的URL>')
。PayU将直接将通知发送到该URL。在notify URL中定义的操作中,您需要解析通知的JSON字符串并检查订单状态。为此,您可以使用NotificationProcess。
use \Team3\PayU\Communication\Process\NotificationProcess\NotificationProcessFactory; use \Team3\PayU\Communication\Notification\OrderNotification; use \Team3\PayU\Communication\Process\NotificationProcess\NotificationProcessException; $logger = new NullLogger(); // Only for example. $notificationProcessFactory = new NotificationProcessFactory(); $notificationProcess = $notificationProcessFactory->build($logger); // $notificationData is content of received notification // $signatureHeader can be read from http header "OpenPayu-Signature" // from received notification. It can be null. try { /** @var OrderNotification $orderNotification */ $orderNotification = $notificationProcess->process( $configuration->getCredentials(), $notificationData, $signatureHeader ); } catch (NotificationProcessException $exception) { // Something was wrong with the process. Maybe signature was wrong? } catch (PayUException $exception) { // Something went really wrong.. } // $orderNotification->getOrder()->getStatus->isCompleted() -> true
重要
请注意,PayU将以异步方式发送通知,因此当您收到关于订单完成或取消的通知时,您应该忽略所有后续通知。
运行测试
要本地运行测试,您必须使用--require-dev
参数通过composer安装库。这将安装Codeception框架,它有助于单元测试。Codeception使用辅助工具,但它们不在这个库中。您可以使用./bin/codecept build
构建它们 - 现在您已准备好。现在您可以使用./bin/codecept run unit
运行单元测试,或使用./bin/codecept run unit -c codeception.yml --coverage --coverage-html --coverage-xml
生成代码覆盖率报告。此库是使用Phing构建的,因此您可以使用phing unit-tests
或phing coverage
。
实际代码覆盖率报告可在krzysztof-gzocha.github.io/payu/coverage找到。
贡献
所有pull请求都受到欢迎和赞赏 :)
许可
MIT许可证在license.txt中可用。