mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 08:52:39 +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:
parent
6f5dab634d
commit
d7e5a8b978
5 changed files with 162 additions and 78 deletions
|
@ -55,11 +55,20 @@ final class PhabricatorFavoritesApplication extends PhabricatorApplication {
|
|||
->withInstalled(true)
|
||||
->executeOne();
|
||||
|
||||
$filter_view = id(new PhabricatorFavoritesProfileMenuEngine())
|
||||
$menu_engine = id(new PhabricatorFavoritesProfileMenuEngine())
|
||||
->setViewer($viewer)
|
||||
->setProfileObject($favorites)
|
||||
->setMenuType(PhabricatorProfileMenuEngine::MENU_COMBINED)
|
||||
->buildNavigation();
|
||||
->setProfileObject($favorites);
|
||||
|
||||
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();
|
||||
$item_views = $menu_view->getItems();
|
||||
|
|
|
@ -20,44 +20,40 @@ final class PhabricatorFavoritesProfileMenuEngine
|
|||
|
||||
protected function getBuiltinProfileItems($object) {
|
||||
$items = array();
|
||||
$custom_phid = $this->getCustomPHID();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
// Built-in Global Defaults
|
||||
if (!$custom_phid) {
|
||||
$create_task = array(
|
||||
'name' => null,
|
||||
'formKey' =>
|
||||
id(new ManiphestEditEngine())->getProfileMenuItemDefault(),
|
||||
);
|
||||
$create_task = array(
|
||||
'name' => null,
|
||||
'formKey' =>
|
||||
id(new ManiphestEditEngine())->getProfileMenuItemDefault(),
|
||||
);
|
||||
|
||||
$create_project = array(
|
||||
'name' => null,
|
||||
'formKey' =>
|
||||
id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(),
|
||||
);
|
||||
$create_project = array(
|
||||
'name' => null,
|
||||
'formKey' =>
|
||||
id(new PhabricatorProjectEditEngine())->getProfileMenuItemDefault(),
|
||||
);
|
||||
|
||||
$create_repository = array(
|
||||
'name' => null,
|
||||
'formKey' =>
|
||||
id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(),
|
||||
);
|
||||
$create_repository = array(
|
||||
'name' => null,
|
||||
'formKey' =>
|
||||
id(new DiffusionRepositoryEditEngine())->getProfileMenuItemDefault(),
|
||||
);
|
||||
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK)
|
||||
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
|
||||
->setMenuItemProperties($create_task);
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_TASK)
|
||||
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
|
||||
->setMenuItemProperties($create_task);
|
||||
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT)
|
||||
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
|
||||
->setMenuItemProperties($create_project);
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_PROJECT)
|
||||
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
|
||||
->setMenuItemProperties($create_project);
|
||||
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY)
|
||||
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
|
||||
->setMenuItemProperties($create_repository);
|
||||
}
|
||||
$items[] = $this->newItem()
|
||||
->setBuiltinKey(PhabricatorFavoritesConstants::ITEM_REPOSITORY)
|
||||
->setMenuItemKey(PhabricatorEditEngineProfileMenuItem::MENUITEMKEY)
|
||||
->setMenuItemProperties($create_repository);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
private $profileObject;
|
||||
private $customPHID;
|
||||
private $items;
|
||||
private $menuType;
|
||||
private $menuType = self::MENU_GLOBAL;
|
||||
private $defaultItem;
|
||||
private $controller;
|
||||
private $navigation;
|
||||
|
@ -15,6 +15,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
const MENU_GLOBAL = 'global';
|
||||
const MENU_PERSONAL = 'personal';
|
||||
const MENU_COMBINED = 'menu';
|
||||
const ITEM_CUSTOM_DIVIDER = 'engine.divider';
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
|
@ -82,9 +83,16 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
|
||||
abstract protected function getItemURI($path);
|
||||
|
||||
abstract protected function isMenuEngineConfigurable();
|
||||
|
||||
abstract protected function getBuiltinProfileItems($object);
|
||||
|
||||
protected function getBuiltinCustomProfileItems(
|
||||
$object,
|
||||
$custom_phid) {
|
||||
return array();
|
||||
}
|
||||
|
||||
public function buildResponse() {
|
||||
$controller = $this->getController();
|
||||
|
||||
|
@ -230,6 +238,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
->setBaseURI(new PhutilURI($this->getItemURI('')));
|
||||
|
||||
$menu_items = $this->getItems();
|
||||
|
||||
$filtered_items = array();
|
||||
foreach ($menu_items as $menu_item) {
|
||||
if ($menu_item->isDisabled()) {
|
||||
|
@ -294,23 +303,26 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
$object = $this->getProfileObject();
|
||||
|
||||
$items = $this->loadBuiltinProfileItems();
|
||||
$menu = $this->getMenuType();
|
||||
|
||||
if ($this->getCustomPHID()) {
|
||||
$stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery())
|
||||
->setViewer($viewer)
|
||||
->withProfilePHIDs(array($object->getPHID()))
|
||||
->withCustomPHIDs(array($this->getCustomPHID()))
|
||||
->setMenuType($menu)
|
||||
->execute();
|
||||
} else {
|
||||
$stored_items = id(new PhabricatorProfileMenuItemConfigurationQuery())
|
||||
->setViewer($viewer)
|
||||
->withProfilePHIDs(array($object->getPHID()))
|
||||
->setMenuType($menu)
|
||||
->execute();
|
||||
$query = id(new PhabricatorProfileMenuItemConfigurationQuery())
|
||||
->setViewer($viewer)
|
||||
->withProfilePHIDs(array($object->getPHID()));
|
||||
|
||||
$menu_type = $this->getMenuType();
|
||||
switch ($menu_type) {
|
||||
case self::MENU_GLOBAL:
|
||||
$query->withCustomPHIDs(array(), true);
|
||||
break;
|
||||
case self::MENU_PERSONAL:
|
||||
$query->withCustomPHIDs(array($this->getCustomPHID()), false);
|
||||
break;
|
||||
case self::MENU_COMBINED:
|
||||
$query->withCustomPHIDs(array($this->getCustomPHID()), true);
|
||||
break;
|
||||
}
|
||||
|
||||
$stored_items = $query->execute();
|
||||
|
||||
foreach ($stored_items as $stored_item) {
|
||||
$impl = $stored_item->getMenuItem();
|
||||
$impl->setViewer($viewer);
|
||||
|
@ -339,12 +351,7 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
$items = msort($items, 'getSortKey');
|
||||
|
||||
// Normalize keys since callers shouldn't rely on this array being
|
||||
// partially keyed.
|
||||
$items = array_values($items);
|
||||
|
||||
$items = $this->arrangeItems($items);
|
||||
|
||||
// Make sure exactly one valid item is marked as default.
|
||||
$default = null;
|
||||
|
@ -377,7 +384,26 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
|
||||
private function loadBuiltinProfileItems() {
|
||||
$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();
|
||||
$viewer = $this->getViewer();
|
||||
|
@ -990,4 +1016,40 @@ abstract class PhabricatorProfileMenuEngine extends Phobject {
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ final class PhabricatorProfileMenuItemConfigurationQuery
|
|||
private $phids;
|
||||
private $profilePHIDs;
|
||||
private $customPHIDs;
|
||||
private $menuType;
|
||||
private $includeGlobal;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -24,13 +24,9 @@ final class PhabricatorProfileMenuItemConfigurationQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withCustomPHIDs(array $phids) {
|
||||
public function withCustomPHIDs(array $phids, $include_global = false) {
|
||||
$this->customPHIDs = $phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMenuType($type) {
|
||||
$this->menuType = $type;
|
||||
$this->includeGlobal = $include_global;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -67,10 +63,21 @@ final class PhabricatorProfileMenuItemConfigurationQuery
|
|||
}
|
||||
|
||||
if ($this->customPHIDs !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'customPHID IN (%Ls)',
|
||||
$this->customPHIDs);
|
||||
if ($this->customPHIDs && $this->includeGlobal) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'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;
|
||||
|
|
|
@ -126,18 +126,28 @@ final class PhabricatorProfileMenuItemConfiguration
|
|||
return $this->getMenuItem()->willBuildNavigationItems($items);
|
||||
}
|
||||
|
||||
public function getSortKey() {
|
||||
$order = $this->getMenuItemOrder();
|
||||
if ($order === null) {
|
||||
$order = 'Z';
|
||||
public function getSortVector() {
|
||||
// Sort custom items above global items.
|
||||
if ($this->getCustomPHID()) {
|
||||
$is_global = 0;
|
||||
} else {
|
||||
$order = sprintf('%020d', $order);
|
||||
$is_global = 1;
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'~%s%020d',
|
||||
$order,
|
||||
$this->getID());
|
||||
// Sort items with an explicit order above items without an explicit order,
|
||||
// so any newly created builtins go to the bottom.
|
||||
$order = $this->getMenuItemOrder();
|
||||
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() {
|
||||
|
|
Loading…
Reference in a new issue