Page MenuHomePhabricator

D10634.id25541.diff
No OneTemporary

D10634.id25541.diff

diff --git a/resources/sql/autopatches/20141005.phortuneproduct.sql b/resources/sql/autopatches/20141005.phortuneproduct.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20141005.phortuneproduct.sql
@@ -0,0 +1,22 @@
+DROP TABLE {$NAMESPACE}_phortune.phortune_producttransaction;
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_product
+ DROP productName;
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_product
+ DROP priceAsCurrency;
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_product
+ ADD productClassKey BINARY(12) NOT NULL;
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_product
+ ADD productClass VARCHAR(128) NOT NULL COLLATE utf8_bin;
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_product
+ ADD productRefKey BINARY(12) NOT NULL;
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_product
+ ADD productRef VARCHAR(128) NOT NULL COLLATE utf8_bin;
+
+ALTER TABLE {$NAMESPACE}_phortune.phortune_product
+ ADD UNIQUE KEY `key_product` (productClassKey, productRefKey);
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -669,6 +669,7 @@
'FundBackerEditor' => 'applications/fund/editor/FundBackerEditor.php',
'FundBackerListController' => 'applications/fund/controller/FundBackerListController.php',
'FundBackerPHIDType' => 'applications/fund/phid/FundBackerPHIDType.php',
+ 'FundBackerProduct' => 'applications/fund/phortune/FundBackerProduct.php',
'FundBackerQuery' => 'applications/fund/query/FundBackerQuery.php',
'FundBackerSearchEngine' => 'applications/fund/query/FundBackerSearchEngine.php',
'FundBackerTransaction' => 'applications/fund/storage/FundBackerTransaction.php',
@@ -2580,13 +2581,9 @@
'PhortunePaymentProviderTestCase' => 'applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php',
'PhortunePaypalPaymentProvider' => 'applications/phortune/provider/PhortunePaypalPaymentProvider.php',
'PhortuneProduct' => 'applications/phortune/storage/PhortuneProduct.php',
- 'PhortuneProductEditController' => 'applications/phortune/controller/PhortuneProductEditController.php',
- 'PhortuneProductEditor' => 'applications/phortune/editor/PhortuneProductEditor.php',
+ 'PhortuneProductImplementation' => 'applications/phortune/product/PhortuneProductImplementation.php',
'PhortuneProductListController' => 'applications/phortune/controller/PhortuneProductListController.php',
- 'PhortuneProductPurchaseController' => 'applications/phortune/controller/PhortuneProductPurchaseController.php',
'PhortuneProductQuery' => 'applications/phortune/query/PhortuneProductQuery.php',
- 'PhortuneProductTransaction' => 'applications/phortune/storage/PhortuneProductTransaction.php',
- 'PhortuneProductTransactionQuery' => 'applications/phortune/query/PhortuneProductTransactionQuery.php',
'PhortuneProductViewController' => 'applications/phortune/controller/PhortuneProductViewController.php',
'PhortuneProviderController' => 'applications/phortune/controller/PhortuneProviderController.php',
'PhortunePurchase' => 'applications/phortune/storage/PhortunePurchase.php',
@@ -3520,6 +3517,7 @@
'FundBackerEditor' => 'PhabricatorApplicationTransactionEditor',
'FundBackerListController' => 'FundController',
'FundBackerPHIDType' => 'PhabricatorPHIDType',
+ 'FundBackerProduct' => 'PhortuneProductImplementation',
'FundBackerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'FundBackerSearchEngine' => 'PhabricatorApplicationSearchEngine',
'FundBackerTransaction' => 'PhabricatorApplicationTransaction',
@@ -5616,13 +5614,8 @@
'PhortuneDAO',
'PhabricatorPolicyInterface',
),
- 'PhortuneProductEditController' => 'PhabricatorController',
- 'PhortuneProductEditor' => 'PhabricatorApplicationTransactionEditor',
'PhortuneProductListController' => 'PhabricatorController',
- 'PhortuneProductPurchaseController' => 'PhortuneController',
'PhortuneProductQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'PhortuneProductTransaction' => 'PhabricatorApplicationTransaction',
- 'PhortuneProductTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhortuneProductViewController' => 'PhortuneController',
'PhortuneProviderController' => 'PhortuneController',
'PhortunePurchase' => array(
diff --git a/src/applications/fund/controller/FundInitiativeBackController.php b/src/applications/fund/controller/FundInitiativeBackController.php
--- a/src/applications/fund/controller/FundInitiativeBackController.php
+++ b/src/applications/fund/controller/FundInitiativeBackController.php
@@ -60,7 +60,19 @@
->setAmountAsCurrency($currency)
->save();
- // TODO: Here, we'd create a purchase and cart.
+ $product = id(new PhortuneProductQuery())
+ ->setViewer($viewer)
+ ->withClassAndRef('FundBackerProduct', $initiative->getPHID())
+ ->executeOne();
+
+ $account = PhortuneAccountQuery::loadActiveAccountForUser(
+ $viewer,
+ PhabricatorContentSource::newFromRequest($request));
+
+ $cart = $account->newCart($viewer);
+
+ $purchase = $cart->newPurchase($viewer, $product);
+ $purchase->setBasePriceAsCurrency($currency)->save();
$xactions = array();
@@ -74,9 +86,8 @@
$editor->applyTransactions($backer, $xactions);
- // TODO: Here, we'd ship the user into Phortune.
-
- return id(new AphrontRedirectResponse())->setURI($initiative_uri);
+ return id(new AphrontRedirectResponse())
+ ->setURI($cart->getCheckoutURI());
}
}
diff --git a/src/applications/fund/phortune/FundBackerProduct.php b/src/applications/fund/phortune/FundBackerProduct.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fund/phortune/FundBackerProduct.php
@@ -0,0 +1,64 @@
+<?php
+
+final class FundBackerProduct extends PhortuneProductImplementation {
+
+ private $initiativePHID;
+ private $initiative;
+
+ public function getRef() {
+ return $this->getInitiativePHID();
+ }
+
+ public function getName(PhortuneProduct $product) {
+ return pht('Back Initiative %s', $this->initiativePHID);
+ }
+
+ public function getPriceAsCurrency(PhortuneProduct $product) {
+ return PhortuneCurrency::newEmptyCurrency();
+ }
+
+ public function setInitiativePHID($initiative_phid) {
+ $this->initiativePHID = $initiative_phid;
+ return $this;
+ }
+
+ public function getInitiativePHID() {
+ return $this->initiativePHID;
+ }
+
+ public function setInitiative(FundInitiative $initiative) {
+ $this->initiative = $initiative;
+ return $this;
+ }
+
+ public function getInitiative() {
+ return $this->initiative;
+ }
+
+ public function loadImplementationsForRefs(
+ PhabricatorUser $viewer,
+ array $refs) {
+
+ $initiatives = id(new FundInitiativeQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($refs)
+ ->execute();
+ $initiatives = mpull($initiatives, null, 'getPHID');
+
+ $objects = array();
+ foreach ($refs as $ref) {
+ $object = id(new FundBackerProduct())
+ ->setInitiativePHID($ref);
+
+ $initiative = idx($initiatives, $ref);
+ if ($initiative) {
+ $object->setInitiative($initiative);
+ }
+
+ $objects[] = $object;
+ }
+
+ return $objects;
+ }
+
+}
diff --git a/src/applications/phortune/application/PhabricatorPhortuneApplication.php b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
--- a/src/applications/phortune/application/PhabricatorPhortuneApplication.php
+++ b/src/applications/phortune/application/PhabricatorPhortuneApplication.php
@@ -58,9 +58,6 @@
'view/(?P<id>\d+)/' => 'PhortuneProductViewController',
'edit/(?:(?P<id>\d+)/)?' => 'PhortuneProductEditController',
),
- 'purchase/(?P<id>\d+)/' => array(
- '' => 'PhortunePurchaseViewController',
- ),
'provider/(?P<digest>[^/]+)/(?P<action>[^/]+)/'
=> 'PhortuneProviderController',
),
diff --git a/src/applications/phortune/controller/PhortuneController.php b/src/applications/phortune/controller/PhortuneController.php
--- a/src/applications/phortune/controller/PhortuneController.php
+++ b/src/applications/phortune/controller/PhortuneController.php
@@ -3,53 +3,9 @@
abstract class PhortuneController extends PhabricatorController {
protected function loadActiveAccount(PhabricatorUser $user) {
- $accounts = id(new PhortuneAccountQuery())
- ->setViewer($user)
- ->withMemberPHIDs(array($user->getPHID()))
- ->execute();
-
- if (!$accounts) {
- return $this->createUserAccount($user);
- } else if (count($accounts) == 1) {
- return head($accounts);
- } else {
- throw new Exception('TODO: No account selection yet.');
- }
- }
-
- protected function createUserAccount(PhabricatorUser $user) {
- $request = $this->getRequest();
-
- $xactions = array();
- $xactions[] = id(new PhortuneAccountTransaction())
- ->setTransactionType(PhortuneAccountTransaction::TYPE_NAME)
- ->setNewValue(pht('Account (%s)', $user->getUserName()));
-
- $xactions[] = id(new PhortuneAccountTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
- ->setMetadataValue(
- 'edge:type',
- PhabricatorEdgeConfig::TYPE_ACCOUNT_HAS_MEMBER)
- ->setNewValue(
- array(
- '=' => array($user->getPHID() => $user->getPHID()),
- ));
-
- $account = id(new PhortuneAccount())
- ->attachMemberPHIDs(array());
-
- $editor = id(new PhortuneAccountEditor())
- ->setActor($user)
- ->setContentSourceFromRequest($request);
-
- // We create an account for you the first time you visit Phortune.
- $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
-
- $editor->applyTransactions($account, $xactions);
-
- unset($unguarded);
-
- return $account;
+ return PhortuneAccountQuery::loadActiveAccountForUser(
+ $user,
+ PhabricatorContentSource::newFromRequest($this->getRequest()));
}
protected function buildChargesTable(array $charges, $show_cart = true) {
diff --git a/src/applications/phortune/controller/PhortuneProductEditController.php b/src/applications/phortune/controller/PhortuneProductEditController.php
deleted file mode 100644
--- a/src/applications/phortune/controller/PhortuneProductEditController.php
+++ /dev/null
@@ -1,133 +0,0 @@
-<?php
-
-final class PhortuneProductEditController extends PhabricatorController {
-
- private $productID;
-
- public function willProcessRequest(array $data) {
- $this->productID = idx($data, 'id');
- }
-
- public function processRequest() {
- $request = $this->getRequest();
- $user = $request->getUser();
-
- if ($this->productID) {
- $product = id(new PhortuneProductQuery())
- ->setViewer($user)
- ->withIDs(array($this->productID))
- ->executeOne();
- if (!$product) {
- return new Aphront404Response();
- }
-
- $is_create = false;
- $cancel_uri = $this->getApplicationURI(
- 'product/view/'.$this->productID.'/');
- } else {
- $product = PhortuneProduct::initializeNewProduct();
- $is_create = true;
- $cancel_uri = $this->getApplicationURI('product/');
- }
-
- $v_name = $product->getProductName();
- $v_price = $product->getPriceAsCurrency()->formatForDisplay();
- $display_price = $v_price;
-
- $e_name = true;
- $e_price = true;
- $errors = array();
-
- if ($request->isFormPost()) {
- $v_name = $request->getStr('name');
- if (!strlen($v_name)) {
- $e_name = pht('Required');
- $errors[] = pht('Product must have a name.');
- } else {
- $e_name = null;
- }
-
- $display_price = $request->getStr('price');
- try {
- $v_price = PhortuneCurrency::newFromUserInput($user, $display_price)
- ->serializeForStorage();
- $e_price = null;
- } catch (Exception $ex) {
- $errors[] = pht('Price should be formatted as: $1.23');
- $e_price = pht('Invalid');
- }
-
- if (!$errors) {
- $xactions = array();
-
- $xactions[] = id(new PhortuneProductTransaction())
- ->setTransactionType(PhortuneProductTransaction::TYPE_NAME)
- ->setNewValue($v_name);
-
- $xactions[] = id(new PhortuneProductTransaction())
- ->setTransactionType(PhortuneProductTransaction::TYPE_PRICE)
- ->setNewValue($v_price);
-
- $editor = id(new PhortuneProductEditor())
- ->setActor($user)
- ->setContinueOnNoEffect(true)
- ->setContentSourceFromRequest($request);
-
- $editor->applyTransactions($product, $xactions);
-
- return id(new AphrontRedirectResponse())->setURI(
- $this->getApplicationURI('product/view/'.$product->getID().'/'));
- }
- }
-
- if ($errors) {
- $errors = id(new AphrontErrorView())
- ->setErrors($errors);
- }
-
- $form = id(new AphrontFormView())
- ->setUser($user)
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Name'))
- ->setName('name')
- ->setValue($v_name)
- ->setError($e_name))
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Price'))
- ->setName('price')
- ->setValue($display_price)
- ->setError($e_price))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue(
- $is_create
- ? pht('Create Product')
- : pht('Save Product'))
- ->addCancelButton($cancel_uri));
-
- $title = pht('Edit Product');
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb(
- pht('Products'),
- $this->getApplicationURI('product/'));
- $crumbs->addTextCrumb(
- $is_create ? pht('Create') : pht('Edit'),
- $request->getRequestURI());
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Edit Product'))
- ->appendChild($form);
-
- return $this->buildApplicationPage(
- array(
- $crumbs,
- $box,
- ),
- array(
- 'title' => $title,
- ));
- }
-
-}
diff --git a/src/applications/phortune/controller/PhortuneProductPurchaseController.php b/src/applications/phortune/controller/PhortuneProductPurchaseController.php
deleted file mode 100644
--- a/src/applications/phortune/controller/PhortuneProductPurchaseController.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-final class PhortuneProductPurchaseController
- extends PhortuneController {
-
- private $accountID;
- private $productID;
-
- public function willProcessRequest(array $data) {
- $this->accountID = $data['accountID'];
- $this->productID = $data['productID'];
- }
-
- public function processRequest() {
- $request = $this->getRequest();
- $user = $request->getUser();
-
- $account = id(new PhortuneAccountQuery())
- ->setViewer($user)
- ->withIDs(array($this->accountID))
- ->executeOne();
- if (!$account) {
- return new Aphront404Response();
- }
-
- $account_uri = $this->getApplicationURI($account->getID().'/');
-
- $product = id(new PhortuneProductQuery())
- ->setViewer($user)
- ->withIDs(array($this->productID))
- ->executeOne();
- if (!$product) {
- return new Aphront404Response();
- }
-
- if ($request->isFormPost()) {
- // TODO: Use ApplicationTransations.
-
- $cart = new PhortuneCart();
- $cart->openTransaction();
-
- $cart->setStatus(PhortuneCart::STATUS_READY);
- $cart->setAccountPHID($account->getPHID());
- $cart->setAuthorPHID($user->getPHID());
- $cart->save();
-
- $purchase = new PhortunePurchase();
- $purchase->setProductPHID($product->getPHID());
- $purchase->setAccountPHID($account->getPHID());
- $purchase->setAuthorPHID($user->getPHID());
- $purchase->setCartPHID($cart->getPHID());
- $purchase->setBasePriceAsCurrency($product->getPriceAsCurrency());
- $purchase->setQuantity(1);
-
- $purchase->setStatus(PhortunePurchase::STATUS_PENDING);
- $purchase->save();
-
- $cart->saveTransaction();
-
- $cart_id = $cart->getID();
- $cart_uri = $this->getApplicationURI('/cart/'.$cart_id.'/checkout/');
- return id(new AphrontRedirectResponse())->setURI($cart_uri);
- }
-
- return $this->newDialog()
- ->setTitle(pht('Purchase Product'))
- ->appendParagraph(pht('Really purchase this stuff?'))
- ->addSubmitButton(pht('Checkout'))
- ->addCancelButton($account_uri);
- }
-}
diff --git a/src/applications/phortune/controller/PhortuneProductViewController.php b/src/applications/phortune/controller/PhortuneProductViewController.php
--- a/src/applications/phortune/controller/PhortuneProductViewController.php
+++ b/src/applications/phortune/controller/PhortuneProductViewController.php
@@ -34,19 +34,7 @@
$actions = id(new PhabricatorActionListView())
->setUser($user)
- ->setObjectURI($request->getRequestURI())
- ->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Edit Product'))
- ->setHref($edit_uri)
- ->setIcon('fa-pencil'))
- ->addAction(
- id(new PhabricatorActionView())
- ->setUser($user)
- ->setName(pht('Purchase'))
- ->setHref($cart_uri)
- ->setIcon('fa-shopping-cart')
- ->setWorkflow(true));
+ ->setObjectURI($request->getRequestURI());
$crumbs = $this->buildApplicationCrumbs();
$crumbs->setActionList($actions);
@@ -64,20 +52,6 @@
pht('Price'),
$product->getPriceAsCurrency()->formatForDisplay());
- $xactions = id(new PhortuneProductTransactionQuery())
- ->setViewer($user)
- ->withObjectPHIDs(array($product->getPHID()))
- ->execute();
-
- $engine = id(new PhabricatorMarkupEngine())
- ->setViewer($user);
-
- $xaction_view = id(new PhabricatorApplicationTransactionView())
- ->setUser($user)
- ->setObjectPHID($product->getPHID())
- ->setTransactions($xactions)
- ->setMarkupEngine($engine);
-
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
@@ -86,7 +60,6 @@
array(
$crumbs,
$object_box,
- $xaction_view,
),
array(
'title' => $title,
diff --git a/src/applications/phortune/editor/PhortuneProductEditor.php b/src/applications/phortune/editor/PhortuneProductEditor.php
deleted file mode 100644
--- a/src/applications/phortune/editor/PhortuneProductEditor.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-
-
-final class PhortuneProductEditor
- extends PhabricatorApplicationTransactionEditor {
-
- public function getEditorApplicationClass() {
- return 'PhabricatorPhortuneApplication';
- }
-
- public function getEditorObjectsDescription() {
- return pht('Phortune Products');
- }
-
- public function getTransactionTypes() {
- $types = parent::getTransactionTypes();
-
- $types[] = PhortuneProductTransaction::TYPE_NAME;
- $types[] = PhortuneProductTransaction::TYPE_PRICE;
-
- return $types;
- }
-
-
- protected function getCustomTransactionOldValue(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
- switch ($xaction->getTransactionType()) {
- case PhortuneProductTransaction::TYPE_NAME:
- return $object->getProductName();
- case PhortuneProductTransaction::TYPE_PRICE:
- return $object->getPriceAsCurrency()->serializeForStorage();
- }
- return parent::getCustomTransactionOldValue($object, $xaction);
- }
-
- protected function getCustomTransactionNewValue(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
- switch ($xaction->getTransactionType()) {
- case PhortuneProductTransaction::TYPE_NAME:
- case PhortuneProductTransaction::TYPE_PRICE:
- return $xaction->getNewValue();
- }
- return parent::getCustomTransactionNewValue($object, $xaction);
- }
-
- protected function applyCustomInternalTransaction(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
- switch ($xaction->getTransactionType()) {
- case PhortuneProductTransaction::TYPE_NAME:
- $object->setProductName($xaction->getNewValue());
- return;
- case PhortuneProductTransaction::TYPE_PRICE:
- $object->setPriceAsCurrency(
- PhortuneCurrency::newFromString($xaction->getNewValue()));
- return;
- }
- return parent::applyCustomInternalTransaction($object, $xaction);
- }
-
- protected function applyCustomExternalTransaction(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
- switch ($xaction->getTransactionType()) {
- case PhortuneProductTransaction::TYPE_NAME:
- case PhortuneProductTransaction::TYPE_PRICE:
- return;
- }
- return parent::applyCustomExternalTransaction($object, $xaction);
- }
-
-}
diff --git a/src/applications/phortune/product/PhortuneProductImplementation.php b/src/applications/phortune/product/PhortuneProductImplementation.php
new file mode 100644
--- /dev/null
+++ b/src/applications/phortune/product/PhortuneProductImplementation.php
@@ -0,0 +1,13 @@
+<?php
+
+abstract class PhortuneProductImplementation {
+
+ abstract public function loadImplementationsForRefs(
+ PhabricatorUser $viewer,
+ array $refs);
+
+ abstract public function getRef();
+ abstract public function getName(PhortuneProduct $product);
+ abstract public function getPriceAsCurrency(PhortuneProduct $product);
+
+}
diff --git a/src/applications/phortune/query/PhortuneAccountQuery.php b/src/applications/phortune/query/PhortuneAccountQuery.php
--- a/src/applications/phortune/query/PhortuneAccountQuery.php
+++ b/src/applications/phortune/query/PhortuneAccountQuery.php
@@ -7,6 +7,24 @@
private $phids;
private $memberPHIDs;
+ public static function loadActiveAccountForUser(
+ PhabricatorUser $user,
+ PhabricatorContentSource $content_source) {
+
+ $accounts = id(new PhortuneAccountQuery())
+ ->setViewer($user)
+ ->withMemberPHIDs(array($user->getPHID()))
+ ->execute();
+
+ if (!$accounts) {
+ return PhortuneAccount::createNewAccount($user, $content_source);
+ } else if (count($accounts) == 1) {
+ return head($accounts);
+ } else {
+ throw new Exception('TODO: No account selection yet.');
+ }
+ }
+
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
diff --git a/src/applications/phortune/query/PhortuneProductQuery.php b/src/applications/phortune/query/PhortuneProductQuery.php
--- a/src/applications/phortune/query/PhortuneProductQuery.php
+++ b/src/applications/phortune/query/PhortuneProductQuery.php
@@ -5,6 +5,7 @@
private $ids;
private $phids;
+ private $refMap;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -16,6 +17,11 @@
return $this;
}
+ public function withClassAndRef($class, $ref) {
+ $this->refMap = array($class => array($ref));
+ return $this;
+ }
+
protected function loadPage() {
$table = new PhortuneProduct();
$conn = $table->establishConnection('r');
@@ -28,26 +34,80 @@
$this->buildOrderClause($conn),
$this->buildLimitClause($conn));
- return $table->loadAllFromArray($rows);
+ $page = $table->loadAllFromArray($rows);
+
+ // NOTE: We're loading product implementations here, but also creating any
+ // products which do not yet exist.
+
+ $class_map = mgroup($page, 'getProductClass');
+ if ($this->refMap) {
+ $class_map += array_fill_keys(array_keys($this->refMap), array());
+ }
+
+ foreach ($class_map as $class => $products) {
+ $refs = mpull($products, null, 'getProductRef');
+ if (isset($this->refMap[$class])) {
+ $refs += array_fill_keys($this->refMap[$class], null);
+ }
+
+ $implementations = newv($class, array())->loadImplementationsForRefs(
+ $this->getViewer(),
+ array_keys($refs));
+ $implementations = mpull($implementations, null, 'getRef');
+
+ foreach ($implementations as $ref => $implementation) {
+ $product = idx($refs, $ref);
+ if ($product === null) {
+ // If this product does not exist yet, create it and add it to the
+ // result page.
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $product = PhortuneProduct::initializeNewProduct()
+ ->setProductClass($class)
+ ->setProductRef($ref)
+ ->save();
+ unset($unguarded);
+
+ $page[] = $product;
+ }
+
+ $product->attachImplementation($implementation);
+ }
+ }
+
+ return $page;
}
private function buildWhereClause(AphrontDatabaseConnection $conn) {
$where = array();
- if ($this->ids) {
+ if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'id IN (%Ld)',
$this->ids);
}
- if ($this->phids) {
+ if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'phid IN (%Ls)',
$this->phids);
}
+ if ($this->refMap !== null) {
+ $sql = array();
+ foreach ($this->refMap as $class => $refs) {
+ foreach ($refs as $ref) {
+ $sql[] = qsprintf(
+ $conn,
+ '(productClassKey = %s AND productRefKey = %s)',
+ PhabricatorHash::digestForIndex($class),
+ PhabricatorHash::digestForIndex($ref));
+ }
+ }
+ $where[] = implode(' OR ', $sql);
+ }
+
$where[] = $this->buildPagingClause($conn);
return $this->formatWhereClause($where);
diff --git a/src/applications/phortune/query/PhortuneProductTransactionQuery.php b/src/applications/phortune/query/PhortuneProductTransactionQuery.php
deleted file mode 100644
--- a/src/applications/phortune/query/PhortuneProductTransactionQuery.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-final class PhortuneProductTransactionQuery
- extends PhabricatorApplicationTransactionQuery {
-
- public function getTemplateApplicationTransaction() {
- return new PhortuneProductTransaction();
- }
-
-}
diff --git a/src/applications/phortune/storage/PhortuneAccount.php b/src/applications/phortune/storage/PhortuneAccount.php
--- a/src/applications/phortune/storage/PhortuneAccount.php
+++ b/src/applications/phortune/storage/PhortuneAccount.php
@@ -13,6 +13,54 @@
private $memberPHIDs = self::ATTACHABLE;
+ public static function initializeNewAccount(PhabricatorUser $actor) {
+ $account = id(new PhortuneAccount());
+
+ $account->memberPHIDs = array();
+
+ return $account;
+ }
+
+ public static function createNewAccount(
+ PhabricatorUser $actor,
+ PhabricatorContentSource $content_source) {
+
+ $account = PhortuneAccount::initializeNewAccount($actor);
+
+ $xactions = array();
+ $xactions[] = id(new PhortuneAccountTransaction())
+ ->setTransactionType(PhortuneAccountTransaction::TYPE_NAME)
+ ->setNewValue(pht('Account (%s)', $actor->getUserName()));
+
+ $xactions[] = id(new PhortuneAccountTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue(
+ 'edge:type',
+ PhabricatorEdgeConfig::TYPE_ACCOUNT_HAS_MEMBER)
+ ->setNewValue(
+ array(
+ '=' => array($actor->getPHID() => $actor->getPHID()),
+ ));
+
+ $editor = id(new PhortuneAccountEditor())
+ ->setActor($actor)
+ ->setContentSource($content_source);
+
+ // We create an account for you the first time you visit Phortune.
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+
+ $editor->applyTransactions($account, $xactions);
+
+ unset($unguarded);
+
+ return $account;
+ }
+
+ public function newCart(PhabricatorUser $actor) {
+ return PhortuneCart::initializeNewCart($actor, $this)
+ ->save();
+ }
+
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
diff --git a/src/applications/phortune/storage/PhortuneCart.php b/src/applications/phortune/storage/PhortuneCart.php
--- a/src/applications/phortune/storage/PhortuneCart.php
+++ b/src/applications/phortune/storage/PhortuneCart.php
@@ -15,6 +15,38 @@
private $account = self::ATTACHABLE;
private $purchases = self::ATTACHABLE;
+ public static function initializeNewCart(
+ PhabricatorUser $actor,
+ PhortuneAccount $account) {
+ $cart = id(new PhortuneCart())
+ ->setAuthorPHID($actor->getPHID())
+ ->setStatus(self::STATUS_READY)
+ ->setAccountPHID($account->getPHID());
+
+ $cart->account = $account;
+ $cart->purchases = array();
+
+ return $cart;
+ }
+
+ public function newPurchase(
+ PhabricatorUser $actor,
+ PhortuneProduct $product) {
+
+ $purchase = PhortunePurchase::initializeNewPurchase($actor, $product)
+ ->setAccountPHID($this->getAccount()->getPHID())
+ ->setCartPHID($this->getPHID())
+ ->save();
+
+ $this->purchases[] = $purchase;
+
+ return $purchase;
+ }
+
+ public function getCheckoutURI() {
+ return '/phortune/cart/'.$this->getID().'/checkout/';
+ }
+
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
diff --git a/src/applications/phortune/storage/PhortuneProduct.php b/src/applications/phortune/storage/PhortuneProduct.php
--- a/src/applications/phortune/storage/PhortuneProduct.php
+++ b/src/applications/phortune/storage/PhortuneProduct.php
@@ -6,9 +6,13 @@
final class PhortuneProduct extends PhortuneDAO
implements PhabricatorPolicyInterface {
- protected $productName;
- protected $priceAsCurrency;
- protected $metadata;
+ protected $productClassKey;
+ protected $productClass;
+ protected $productRefKey;
+ protected $productRef;
+ protected $metadata = array();
+
+ private $implementation = self::ATTACHABLE;
public function getConfiguration() {
return array(
@@ -16,15 +20,17 @@
self::CONFIG_SERIALIZATION => array(
'metadata' => self::SERIALIZATION_JSON,
),
- self::CONFIG_APPLICATION_SERIALIZERS => array(
- 'priceAsCurrency' => new PhortuneCurrencySerializer(),
- ),
self::CONFIG_COLUMN_SCHEMA => array(
- 'productName' => 'text255',
- 'status' => 'text64',
- 'priceAsCurrency' => 'text64',
- 'billingIntervalInMonths' => 'uint32?',
- 'trialPeriodInDays' => 'uint32?',
+ 'productClassKey' => 'bytes12',
+ 'productClass' => 'text128',
+ 'productRefKey' => 'bytes12',
+ 'productRef' => 'text128',
+ ),
+ self::CONFIG_KEY_SCHEMA => array(
+ 'key_product' => array(
+ 'columns' => array('productClassKey', 'productRefKey'),
+ 'unique' => true,
+ ),
),
) + parent::getConfiguration();
}
@@ -35,8 +41,33 @@
}
public static function initializeNewProduct() {
- return id(new PhortuneProduct())
- ->setPriceAsCurrency(PhortuneCurrency::newEmptyCurrency());
+ return id(new PhortuneProduct());
+ }
+
+ public function attachImplementation(PhortuneProductImplementation $impl) {
+ $this->implementation = $impl;
+ }
+
+ public function getImplementation() {
+ return $this->assertAttached($this->implementation);
+ }
+
+ public function save() {
+ $this->productClassKey = PhabricatorHash::digestForIndex(
+ $this->productClass);
+
+ $this->productRefKey = PhabricatorHash::digestForIndex(
+ $this->productRef);
+
+ return parent::save();
+ }
+
+ public function getPriceAsCurrency() {
+ return $this->getImplementation()->getPriceAsCurrency($this);
+ }
+
+ public function getProductName() {
+ return $this->getImplementation()->getName($this);
}
diff --git a/src/applications/phortune/storage/PhortuneProductTransaction.php b/src/applications/phortune/storage/PhortuneProductTransaction.php
deleted file mode 100644
--- a/src/applications/phortune/storage/PhortuneProductTransaction.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-
-final class PhortuneProductTransaction
- extends PhabricatorApplicationTransaction {
-
- const TYPE_NAME = 'product:name';
- const TYPE_PRICE = 'product:price';
-
- public function getApplicationName() {
- return 'phortune';
- }
-
- public function getApplicationTransactionType() {
- return PhabricatorPHIDConstants::PHID_TYPE_PDCT;
- }
-
- public function getApplicationTransactionCommentObject() {
- return null;
- }
-
- public function getTitle() {
- $author_phid = $this->getAuthorPHID();
-
- $old = $this->getOldValue();
- $new = $this->getNewValue();
-
- switch ($this->getTransactionType()) {
- case self::TYPE_NAME:
- if ($old === null) {
- return pht(
- '%s created this product.',
- $this->renderHandleLink($author_phid));
- } else {
- return pht(
- '%s renamed this product from "%s" to "%s".',
- $this->renderHandleLink($author_phid),
- $old,
- $new);
- }
- break;
- case self::TYPE_PRICE:
- if ($old === null) {
- return pht(
- '%s set product price to %s.',
- $this->renderHandleLink($author_phid),
- PhortuneCurrency::newFromString($new)
- ->formatForDisplay());
- } else {
- return pht(
- '%s changed product price from %s to %s.',
- $this->renderHandleLink($author_phid),
- PhortuneCurrency::newFromString($old)
- ->formatForDisplay(),
- PhortuneCurrency::newFromString($new)
- ->formatForDisplay());
- }
- break;
- }
-
- return parent::getTitle();
- }
-
-}
diff --git a/src/applications/phortune/storage/PhortunePurchase.php b/src/applications/phortune/storage/PhortunePurchase.php
--- a/src/applications/phortune/storage/PhortunePurchase.php
+++ b/src/applications/phortune/storage/PhortunePurchase.php
@@ -20,10 +20,21 @@
protected $basePriceAsCurrency;
protected $quantity;
protected $status;
- protected $metadata;
+ protected $metadata = array();
private $cart = self::ATTACHABLE;
+ public static function initializeNewPurchase(
+ PhabricatorUser $actor,
+ PhortuneProduct $product) {
+ return id(new PhortunePurchase())
+ ->setAuthorPHID($actor->getPHID())
+ ->setProductPHID($product->getPHID())
+ ->setQuantity(1)
+ ->setStatus(self::STATUS_PENDING)
+ ->setBasePriceAsCurrency($product->getPriceAsCurrency());
+ }
+
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 25, 6:14 AM (2 w, 11 h ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/dx/vl/gi3qdkb3rjelftdl
Default Alt Text
D10634.id25541.diff (34 KB)

Event Timeline