1
0
Fork 0
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:
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)
->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();

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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() {