Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15479386
D10634.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
34 KB
Referenced Files
None
Subscribers
None
D10634.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 9, 6:46 AM (1 w, 3 m ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/dx/vl/gi3qdkb3rjelftdl
Default Alt Text
D10634.diff (34 KB)
Attached To
Mode
D10634: Move Phortune product logic into applications
Attached
Detach File
Event Timeline
Log In to Comment