1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 05:50:55 +01:00

Load global and custom profile menu items in a single query

Summary: Ref T5867. Use a single query to load both personal and global items, then reorder them and add a divider if both groups have some stuff.

Test Plan: Viewed menu, edited personal and global items, viewed/edited existing project menus.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T5867

Differential Revision: https://secure.phabricator.com/D17213
This commit is contained in:
epriestley 2017-01-17 12:46:05 -08:00
parent 6f5dab634d
commit d7e5a8b978
5 changed files with 162 additions and 78 deletions

View file

@ -55,11 +55,20 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication {
->withInstalled(true) ->withInstalled(true)
->executeOne(); ->executeOne();
$filter_view = id(new PhabricatorFavoritesProfileMenuEngine()) $menu_engine = id(new PhabricatorFavoritesProfileMenuEngine())
->setViewer($viewer) ->setViewer($viewer)
->setProfileObject($favorites) ->setProfileObject($favorites);
->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED)
->buildNavigation(); if ($viewer->getPHID()) {
$menu_engine
->setCustomPHID($viewer->getPHID())
->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED);
} else {
$menu_engine
->setMenuType(PhabricatorProfileMenuEngine::MENU_GLOBAL);
}
$filter_view = $menu_engine->buildNavigation();
$menu_view = $filter_view->getMenu(); $menu_view = $filter_view->getMenu();
$item_views = $menu_view->getItems(); $item_views = $menu_view->getItems();

View file

@ -20,44 +20,40 @@ final class PhabricatorFavoritesProfileMenuEngine
protected function getBuiltinProfileItems($object) { protected function getBuiltinProfileItems($object) {
$items = array(); $items = array();
$custom_phid = $this->getCustomPHID();
$viewer = $this->getViewer(); $viewer = $this->getViewer();
// Built-in Global Defaults $create_task = array(
if (!$custom_phid) { 'name' => null,
$create_task = array( 'formKey' =>
'name' => null, id(new ManiphestEditEngine())->getProfileMenuItemDefault(),
'formKey' => );
id(new ManiphestEditEngine())->getProfileMenuItemDefault(),
);
$create_project = array( $create_project = array(
'name' => null, 'name' => null,
'formKey' => 'formKey' =>
id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(), id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(),
); );
$create_repository = array( $create_repository = array(
'name' => null, 'name' => null,
'formKey' => 'formKey' =>
id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(), id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(),
); );
$items[] = $this->newItem() $items[] = $this->newItem()
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK) ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK)
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
->setMenuItemProperties($create_task); ->setMenuItemProperties($create_task);
$items[] = $this->newItem() $items[] = $this->newItem()
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT) ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT)
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
->setMenuItemProperties($create_project); ->setMenuItemProperties($create_project);
$items[] = $this->newItem() $items[] = $this->newItem()
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY) ->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY)
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY) ->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
->setMenuItemProperties($create_repository); ->setMenuItemProperties($create_repository);
}
return $items; return $items;
} }

View file

@ -6,7 +6,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
private $profileObject; private $profileObject;
private $customPHID; private $customPHID;
private $items; private $items;
private $menuType; private $menuType = self::MENU_GLOBAL;
private $defaultItem; private $defaultItem;
private $controller; private $controller;
private $navigation; private $navigation;
@ -15,6 +15,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
const MENU_GLOBAL = 'global'; const MENU_GLOBAL = 'global';
const MENU_PERSONAL = 'personal'; const MENU_PERSONAL = 'personal';
const MENU_COMBINED = 'menu'; const MENU_COMBINED = 'menu';
const ITEM_CUSTOM_DIVIDER = 'engine.divider';
public function setViewer(PhabricatorUser $viewer) { public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer; $this->viewer = $viewer;
@ -82,9 +83,16 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
} }
abstract protected function getItemURI($path); abstract protected function getItemURI($path);
abstract protected function isMenuEngineConfigurable(); abstract protected function isMenuEngineConfigurable();
abstract protected function getBuiltinProfileItems($object);
protected function getBuiltinCustomProfileItems(
$object,
$custom_phid) {
return array();
}
public function buildResponse() { public function buildResponse() {
$controller = $this->getController(); $controller = $this->getController();
@ -230,6 +238,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
->setBaseURI(new PhutilURI($this->getItemURI(''))); ->setBaseURI(new PhutilURI($this->getItemURI('')));
$menu_items = $this->getItems(); $menu_items = $this->getItems();
$filtered_items = array(); $filtered_items = array();
foreach ($menu_items as $menu_item) { foreach ($menu_items as $menu_item) {
if ($menu_item->isDisabled()) { if ($menu_item->isDisabled()) {
@ -294,23 +303,26 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
$object = $this->getProfileObject(); $object = $this->getProfileObject();
$items = $this->loadBuiltinProfileItems(); $items = $this->loadBuiltinProfileItems();
$menu = $this->getMenuType();
if ($this->getCustomPHID()) { $query = id(new PhabricatorProfileMenuItemConfigurationQuery())
$stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) ->setViewer($viewer)
->setViewer($viewer) ->withProfilePHIDs(array($object->getPHID()));
->withProfilePHIDs(array($object->getPHID()))
->withCustomPHIDs(array($this->getCustomPHID())) $menu_type = $this->getMenuType();
->setMenuType($menu) switch ($menu_type) {
->execute(); case self::MENU_GLOBAL:
} else { $query->withCustomPHIDs(array(), true);
$stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery()) break;
->setViewer($viewer) case self::MENU_PERSONAL:
->withProfilePHIDs(array($object->getPHID())) $query->withCustomPHIDs(array($this->getCustomPHID()), false);
->setMenuType($menu) break;
->execute(); case self::MENU_COMBINED:
$query->withCustomPHIDs(array($this->getCustomPHID()), true);
break;
} }
$stored_items = $query->execute();
foreach ($stored_items as $stored_item) { foreach ($stored_items as $stored_item) {
$impl = $stored_item->getMenuItem(); $impl = $stored_item->getMenuItem();
$impl->setViewer($viewer); $impl->setViewer($viewer);
@ -339,12 +351,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
} }
} }
$items = msort($items, 'getSortKey'); $items = $this->arrangeItems($items);
// Normalize keys since callers shouldn't rely on this array being
// partially keyed.
$items = array_values($items);
// Make sure exactly one valid item is marked as default. // Make sure exactly one valid item is marked as default.
$default = null; $default = null;
@ -377,7 +384,26 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
private function loadBuiltinProfileItems() { private function loadBuiltinProfileItems() {
$object = $this->getProfileObject(); $object = $this->getProfileObject();
$builtins = $this->getBuiltinProfileItems($object);
$menu_type = $this->getMenuType();
switch ($menu_type) {
case self::MENU_GLOBAL:
$builtins = $this->getBuiltinProfileItems($object);
break;
case self::MENU_PERSONAL:
$builtins = $this->getBuiltinCustomProfileItems(
$object,
$this->getCustomPHID());
break;
case self::MENU_COMBINED:
$builtins = array();
$builtins[] = $this->getBuiltinCustomProfileItems(
$object,
$this->getCustomPHID());
$builtins[] = $this->getBuiltinProfileItems($object);
$builtins = array_mergev($builtins);
break;
}
$items = PhabricatorProfileMenuItem::getAllMenuItems(); $items = PhabricatorProfileMenuItem::getAllMenuItems();
$viewer = $this->getViewer(); $viewer = $this->getViewer();
@ -990,4 +1016,40 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
return $this; return $this;
} }
private function arrangeItems(array $items) {
// Sort the items.
$items = msortv($items, 'getSortVector');
// If we have some global items and some custom items and are in "combined"
// mode, put a hard-coded divider item between them.
if ($this->getMenuType() == self::MENU_COMBINED) {
$list = array();
$seen_custom = false;
$seen_global = false;
foreach ($items as $item) {
if ($item->getCustomPHID()) {
$seen_custom = true;
} else {
if ($seen_custom && !$seen_global) {
$list[] = $this->newItem()
->setBuiltinKey(self::ITEM_CUSTOM_DIVIDER)
->setMenuItemKey(PhabricatorDividerProfileMenuItem::MENUITEMKEY)
->attachMenuItem(
new PhabricatorDividerProfileMenuItem());
}
$seen_global = true;
}
$list[] = $item;
}
$items = $list;
}
// Normalize keys since callers shouldn't rely on this array being
// partially keyed.
$items = array_values($items);
return $items;
}
} }

View file

@ -7,7 +7,7 @@ final class PhabricatorProfileMenuItemConfigurationQuery
private $phids; private $phids;
private $profilePHIDs; private $profilePHIDs;
private $customPHIDs; private $customPHIDs;
private $menuType; private $includeGlobal;
public function withIDs(array $ids) { public function withIDs(array $ids) {
$this->ids = $ids; $this->ids = $ids;
@ -24,13 +24,9 @@ final class PhabricatorProfileMenuItemConfigurationQuery
return $this; return $this;
} }
public function withCustomPHIDs(array $phids) { public function withCustomPHIDs(array $phids, $include_global = false) {
$this->customPHIDs = $phids; $this->customPHIDs = $phids;
return $this; $this->includeGlobal = $include_global;
}
public function setMenuType($type) {
$this->menuType = $type;
return $this; return $this;
} }
@ -67,10 +63,21 @@ final class PhabricatorProfileMenuItemConfigurationQuery
} }
if ($this->customPHIDs !== null) { if ($this->customPHIDs !== null) {
$where[] = qsprintf( if ($this->customPHIDs && $this->includeGlobal) {
$conn, $where[] = qsprintf(
'customPHID IN (%Ls)', $conn,
$this->customPHIDs); 'customPHID IN (%Ls) OR customPHID IS NULL',
$this->customPHIDs);
} else if ($this->customPHIDs) {
$where[] = qsprintf(
$conn,
'customPHID IN (%Ls)',
$this->customPHIDs);
} else {
$where[] = qsprintf(
$conn,
'customPHID IS NULL');
}
} }
return $where; return $where;

View file

@ -126,18 +126,28 @@ final class PhabricatorProfileMenuItemConfiguration
return $this->getMenuItem()->willBuildNavigationItems($items); return $this->getMenuItem()->willBuildNavigationItems($items);
} }
public function getSortKey() { public function getSortVector() {
$order = $this->getMenuItemOrder(); // Sort custom items above global items.
if ($order === null) { if ($this->getCustomPHID()) {
$order = 'Z'; $is_global = 0;
} else { } else {
$order = sprintf('%020d', $order); $is_global = 1;
} }
return sprintf( // Sort items with an explicit order above items without an explicit order,
'~%s%020d', // so any newly created builtins go to the bottom.
$order, $order = $this->getMenuItemOrder();
$this->getID()); if ($order !== null) {
$has_order = 0;
} else {
$has_order = 1;
}
return id(new PhutilSortVector())
->addInt($is_global)
->addInt($has_order)
->addInt((int)$order)
->addInt((int)$this->getID());
} }
public function isDisabled() { public function isDisabled() {