Skip to content

Commit

Permalink
Develop webhook event listeners. Add stripe service wrappers.
Browse files Browse the repository at this point in the history
  • Loading branch information
mirovskyi committed Nov 26, 2015
1 parent e0a4558 commit c8b35cd
Show file tree
Hide file tree
Showing 30 changed files with 1,848 additions and 97 deletions.
2 changes: 1 addition & 1 deletion Controller/WebhookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function handleAction(Request $request)
}

$eventType = new StripeEventType($stripeEvent);
$this->get('event_dispatcher')->dispatch($stripeEvent->type, $eventType);
$this->get('event_dispatcher')->dispatch('stripe.' . $stripeEvent->type, $eventType);

return new Response();
}
Expand Down
19 changes: 19 additions & 0 deletions DependencyInjection/AimirStripeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

Expand All @@ -23,6 +24,24 @@ public function load(array $configs, ContainerBuilder $container)
$config = $this->processConfiguration($configuration, $configs);

$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));

if ($customManagerName = $config['model_manager_name']) {
$container->setAlias('aimir_stripe.object_manager', $customManagerName);
} else {
if ($config['db_driver'] === 'orm') {
$doctrineService = 'doctrine.orm.entity_manager';
} else {
//TODO: support another db_drivers (mongodb, couchdb, propel)
$doctrineService = null;
}
$container->setAlias('aimir_stripe.object_manager', $doctrineService);
}

foreach ($config['model'] as $name => $class) {
$container->setParameter(sprintf('aimir_stripe.model.%s.class', $name), $class);
}

$loader->load('services.xml');
$loader->load('listener.xml');
}
}
48 changes: 45 additions & 3 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Aimir\StripeBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

Expand All @@ -20,10 +21,51 @@ public function getConfigTreeBuilder()
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('aimir_stripe');

// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
$supportedDrivers = array('orm', /** coming soon) */);

$rootNode
->children()
->scalarNode('db_driver')
->defaultValue('orm')
->validate()
->ifNotInArray($supportedDrivers)
->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($supportedDrivers))
->end()
->cannotBeOverwritten()
->isRequired()
->cannotBeEmpty()
->end()
->scalarNode('model_manager_name')->defaultNull()->end()
->scalarNode('secret_key')
->isRequired()
->cannotBeEmpty()
->end()
->end();

$this->modelClassesSection($rootNode);

return $treeBuilder;
}

/**
* @param ArrayNodeDefinition $node
*/
private function modelClassesSection(ArrayNodeDefinition $node)
{
$node
->children()
->arrayNode('model')->isRequired()
->children()
->scalarNode('card')->isRequired()->cannotBeEmpty()->end()
->scalarNode('charge')->isRequired()->cannotBeEmpty()->end()
->scalarNode('coupon')->isRequired()->cannotBeEmpty()->end()
->scalarNode('customer')->isRequired()->cannotBeEmpty()->end()
->scalarNode('invoice')->isRequired()->cannotBeEmpty()->end()
->scalarNode('plan')->isRequired()->cannotBeEmpty()->end()
->scalarNode('refund')->isRequired()->cannotBeEmpty()->end()
->scalarNode('subscription')->isRequired()->cannotBeEmpty()->end()
->end()
->end()
->end();
}
}
36 changes: 21 additions & 15 deletions Doctrine/DoctrineManagerAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,7 @@ public function __construct(ObjectManager $objectManager, $class)
}

/**
* Create model object
*
* @return StripeModelInterface
* @throws \Exception
* {@inheritdoc}
*/
public function create()
{
Expand All @@ -47,9 +44,7 @@ public function create()
}

/**
* @param string $stripeId
*
* @return StripeModelInterface
* {@inheritdoc}
*/
public function retrieve($stripeId)
{
Expand All @@ -59,13 +54,7 @@ public function retrieve($stripeId)
}

/**
* Create|Update stripe model from stripe object
*
* @param StripeObject $stripeObject
* @param bool $flush Flush data to storage
*
* @return StripeModelInterface
* @throws \Exception
* {@inheritdoc}
*/
public function save(StripeObject $stripeObject, $flush = false)
{
Expand All @@ -84,4 +73,21 @@ public function save(StripeObject $stripeObject, $flush = false)

return $model;
}
}

/**
* {@inheritdoc}
*/
public function remove($stripeId, $flush = false)
{
if ($model = $this->retrieve($stripeId)) {
$this->objectManager->remove($model);
if ($flush) {
$this->objectManager->flush($model);
}

return true;
}

return false;
}
}
56 changes: 28 additions & 28 deletions Event/StripeEventType.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,34 @@

class StripeEventType
{
const CHARGE_CAPTURED = 'charge.captured';
const CHARGE_FAILED = 'charge.failed';
const CHARGE_REFUNDED = 'charge.refunded';
const CHARGE_SUCCEEDED = 'charge.succeeded';
const CHARGE_UPDATED = 'charge.updated';
const COUPON_CREATED = 'coupon.created';
const COUPON_DELETED = 'coupon.deleted';
const COUPON_UPDATED = 'coupon.updated';
const CUSTOMER_CREATED = 'customer.created';
const CUSTOMER_DELETED = 'customer.deleted';
const CUSTOMER_UPDATED = 'customer.updated';
const CUSTOMER_DISCOUNT_CREATED = 'customer.discount.created';
const CUSTOMER_DISCOUNT_DELETED = 'customer.discount.deleted';
const CUSTOMER_DISCOUNT_UPDATED = 'customer.discount.updated';
const CUSTOMER_SOURCE_CREATED = 'customer.source.created';
const CUSTOMER_SOURCE_DELETED = 'customer.source.deleted';
const CUSTOMER_SOURCE_UPDATED = 'customer.source.updated';
const CUSTOMER_SUBSCRIPTION_CREATED = 'customer.subscription.created';
const CUSTOMER_SUBSCRIPTION_DELETED = 'customer.subscription.deleted';
const CUSTOMER_SUBSCRIPTION_UPDATED = 'customer.subscription.updated';
const CUSTOMER_SUBSCRIPTION_TRAIL_WILL_END = 'customer.subscription.trial_will_end';
const INVOICE_CREATED = 'invoice.created';
const INVOICE_PAYMENT_FAILED = 'invoice.payment_failed';
const INVOICE_PAYMENT_SUCCEEDED = 'invoice.payment_succeeded';
const INVOICE_UPDATED = 'invoice.updated';
const PLAN_CREATED = 'plan.created';
const PLAN_DELETED = 'plan.deleted';
const PLAN_UPDATED = 'plan.updated';
const CHARGE_CAPTURED = 'stripe.charge.captured';
const CHARGE_FAILED = 'stripe.charge.failed';
const CHARGE_REFUNDED = 'stripe.charge.refunded';
const CHARGE_SUCCEEDED = 'stripe.charge.succeeded';
const CHARGE_UPDATED = 'stripe.charge.updated';
const COUPON_CREATED = 'stripe.coupon.created';
const COUPON_DELETED = 'stripe.coupon.deleted';
const COUPON_UPDATED = 'stripe.coupon.updated';
const CUSTOMER_CREATED = 'stripe.customer.created';
const CUSTOMER_DELETED = 'stripe.customer.deleted';
const CUSTOMER_UPDATED = 'stripe.customer.updated';
const CUSTOMER_DISCOUNT_CREATED = 'stripe.customer.discount.created';
const CUSTOMER_DISCOUNT_DELETED = 'stripe.customer.discount.deleted';
const CUSTOMER_DISCOUNT_UPDATED = 'stripe.customer.discount.updated';
const CUSTOMER_SOURCE_CREATED = 'stripe.customer.source.created';
const CUSTOMER_SOURCE_DELETED = 'stripe.customer.source.deleted';
const CUSTOMER_SOURCE_UPDATED = 'stripe.customer.source.updated';
const CUSTOMER_SUBSCRIPTION_CREATED = 'stripe.customer.subscription.created';
const CUSTOMER_SUBSCRIPTION_DELETED = 'stripe.customer.subscription.deleted';
const CUSTOMER_SUBSCRIPTION_UPDATED = 'stripe.customer.subscription.updated';
const CUSTOMER_SUBSCRIPTION_TRAIL_WILL_END = 'stripe.customer.subscription.trial_will_end';
const INVOICE_CREATED = 'stripe.invoice.created';
const INVOICE_PAYMENT_FAILED = 'stripe.invoice.payment_failed';
const INVOICE_PAYMENT_SUCCEEDED = 'stripe.invoice.payment_succeeded';
const INVOICE_UPDATED = 'stripe.invoice.updated';
const PLAN_CREATED = 'stripe.plan.created';
const PLAN_DELETED = 'stripe.plan.deleted';
const PLAN_UPDATED = 'stripe.plan.updated';

/**
* @var StripeObject
Expand Down
79 changes: 79 additions & 0 deletions EventListener/CardEventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

namespace Aimir\StripeBundle\EventListener;

use Aimir\StripeBundle\Event\StripeEventType;
use Aimir\StripeBundle\ModelManager\ModelManagerInterface;
use Aimir\StripeBundle\Stripe\StripeCard;
use Aimir\StripeBundle\StripeException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class CardEventListener implements EventSubscriberInterface
{
/**
* @var ModelManagerInterface
*/
protected $cardManager;

/**
* CardEventListener constructor.
*
* @param ModelManagerInterface $cardManager
*/
public function __construct(ModelManagerInterface $cardManager)
{
$this->cardManager = $cardManager;
}

/**
* {@inheritDoc}
*/
public static function getSubscribedEvents()
{
return [
StripeEventType::CUSTOMER_SOURCE_CREATED => 'onCardEvent',
StripeEventType::CUSTOMER_SOURCE_DELETED => 'onCardEvent',
StripeEventType::CUSTOMER_SOURCE_UPDATED => 'onCardEvent',
];
}

/**
* Handle card events
*
* @param StripeEventType $event
*
* @throws StripeException
*/
public function onCardEvent(StripeEventType $event)
{
$stripeCard = $event->getEvent()['data']['object'];
if ($stripeCard['object'] != StripeCard::STRIPE_OBJECT) {
throw new StripeException(sprintf(
'Invalid object type "%s". Expected type is "%s".',
$stripeCard['object'],
StripeCard::STRIPE_OBJECT
));
}
$this->cardManager->save($stripeCard, true);
}

/**
* Handle card delete event
*
* @param StripeEventType $event
*
* @throws StripeException
*/
public function onCardDeleteEvent(StripeEventType $event)
{
$stripeCard = $event->getEvent()['data']['object'];
if ($stripeCard['object'] != StripeCard::STRIPE_OBJECT) {
throw new StripeException(sprintf(
'Invalid object type "%s". Expected type is "%s".',
$stripeCard['object'],
StripeCard::STRIPE_OBJECT
));
}
$this->cardManager->remove($stripeCard, true);
}
}
61 changes: 61 additions & 0 deletions EventListener/ChargeEventListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Aimir\StripeBundle\EventListener;

use Aimir\StripeBundle\Event\StripeEventType;
use Aimir\StripeBundle\ModelManager\ModelManagerInterface;
use Aimir\StripeBundle\Stripe\StripeCharge;
use Aimir\StripeBundle\StripeException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ChargeEventListener implements EventSubscriberInterface
{
/**
* @var ModelManagerInterface
*/
protected $chargeManager;

/**
* CardEventListener constructor.
*
* @param ModelManagerInterface $chargeManager
*/
public function __construct(ModelManagerInterface $chargeManager)
{
$this->chargeManager = $chargeManager;
}

/**
* {@inheritDoc}
*/
public static function getSubscribedEvents()
{
return [
StripeEventType::CHARGE_CAPTURED => 'onChargeEvent',
StripeEventType::CHARGE_FAILED => 'onChargeEvent',
StripeEventType::CHARGE_REFUNDED => 'onChargeEvent',
StripeEventType::CHARGE_SUCCEEDED => 'onChargeEvent',
StripeEventType::CHARGE_UPDATED => 'onChargeEvent'
];
}

/**
* Handle charge events
*
* @param StripeEventType $event
*
* @throws StripeException
*/
public function onChargeEvent(StripeEventType $event)
{
$stripeCharge = $event->getEvent()['data']['object'];
if ($stripeCharge['object'] != StripeCharge::STRIPE_OBJECT) {
throw new StripeException(sprintf(
'Invalid object type "%s". Expected type is "%s".',
$stripeCharge['object'],
StripeCharge::STRIPE_OBJECT
));
}
$this->chargeManager->save($stripeCharge, true);
}
}
Loading

0 comments on commit c8b35cd

Please sign in to comment.