Page MenuHomePhorge

No OneTemporary

diff --git a/docs/manual.md b/docs/manual.md
new file mode 100644
index 0000000..e05bc78
--- /dev/null
+++ b/docs/manual.md
@@ -0,0 +1,38 @@
+# Semi-Structured - manage partly-defined objects
+
+## Types and Instances
+
+TODO: add more instructions.
+
+
+## Planned Features
+
+These are some things I plan to add to the application:
+- bulk extract from json to custom field: a way to define a Custom Field, and
+ then systematically populate its value from the json blob.
+- GUI/Wizard for adding custom field - this should be easier.
+- Have Status field for instances, that allows customized values (per class),
+ and also allows to mark some of the values as Archived.
+- A Custom Field that will allow referring to instances of a different Type.
+ For instance, have a Type for "OS" and a Type for "Software", and allow the
+ Software type to have a field of "Supported OS" with a full selector.
+- Customize Icon for type and/or instance.
+- Allow instances to have their own view/edit Policy.
+
+## Export and Import
+
+There's an Export feature from the Instance Search which will produce full data,
+and there are Conduit methods that allow mass export as well.
+
+For import, currently only available method is to use Conduit and make 2 calls
+per each instance - see `examples/load-xkcd.py` for an example.
+
+
+## Dashboards
+
+There's some strange interaction between Dashboards and Instance queries:
+Instance queries can be added to dashboards, but they can't be //updated//
+directly from dashboards.
+Adding a query from the dashboard's Create Panel button will list all saved
+queries for all instance types; It's easier to find the query in the Item List
+page, and use "Add to Dashboard" from the Use Results drop-down.
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 9e4c604..ef30821 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,168 +1,170 @@
<?php
/**
* This file is automatically generated. Use 'arc liberate' to rebuild it.
*
* @generated
* @phutil-library-version 2
*/
phutil_register_library_map(array(
'__library_version__' => 2,
'class' => array(
'SemiStructuredBaseController' => 'controller/SemiStructuredBaseController.php',
'SemiStructuredDAO' => 'storage/SemiStructuredDAO.php',
'SemiStructuredDataApplication' => 'application/SemiStructuredDataApplication.php',
'SemiStructuredInstanceConfiguredCustomField' => 'customfield/SemiStructuredInstanceConfiguredCustomField.php',
'SemiStructuredInstanceConfiguredCustomFieldStorage' => 'storage/SemiStructuredInstanceConfiguredCustomFieldStorage.php',
'SemiStructuredInstanceCustomField' => 'customfield/SemiStructuredInstanceCustomField.php',
'SemiStructuredInstanceCustomFieldNumericIndex' => 'storage/SemiStructuredInstanceCustomFieldNumericIndex.php',
'SemiStructuredInstanceCustomFieldStringIndex' => 'storage/SemiStructuredInstanceCustomFieldStringIndex.php',
'SemiStructuredInstanceEditConduitAPIMethod' => 'conduit/SemiStructuredInstanceEditConduitAPIMethod.php',
'SemiStructuredInstanceSearchConduitAPIMethod' => 'conduit/SemiStructuredInstanceSearchConduitAPIMethod.php',
'SemiStructuredObjectInstance' => 'storage/SemiStructuredObjectInstance.php',
'SemiStructuredObjectInstanceClassTransaction' => 'xaction/instance/SemiStructuredObjectInstanceClassTransaction.php',
'SemiStructuredObjectInstanceController' => 'controller/instance/SemiStructuredObjectInstanceController.php',
'SemiStructuredObjectInstanceDescriptionTransaction' => 'xaction/instance/SemiStructuredObjectInstanceDescriptionTransaction.php',
'SemiStructuredObjectInstanceEditController' => 'controller/instance/SemiStructuredObjectInstanceEditController.php',
'SemiStructuredObjectInstanceEditEngine' => 'editor/SemiStructuredObjectInstanceEditEngine.php',
'SemiStructuredObjectInstanceFerretEngine' => 'search/SemiStructuredObjectInstanceFerretEngine.php',
'SemiStructuredObjectInstanceFulltextEngine' => 'search/SemiStructuredObjectInstanceFulltextEngine.php',
'SemiStructuredObjectInstanceListController' => 'controller/instance/SemiStructuredObjectInstanceListController.php',
'SemiStructuredObjectInstanceMailReceiver' => 'mail/SemiStructuredObjectInstanceMailReceiver.php',
'SemiStructuredObjectInstanceNameTransaction' => 'xaction/instance/SemiStructuredObjectInstanceNameTransaction.php',
'SemiStructuredObjectInstancePHIDType' => 'phid/SemiStructuredObjectInstancePHIDType.php',
'SemiStructuredObjectInstanceQuery' => 'query/SemiStructuredObjectInstanceQuery.php',
'SemiStructuredObjectInstanceRawDataTransaction' => 'xaction/instance/SemiStructuredObjectInstanceRawDataTransaction.php',
'SemiStructuredObjectInstanceReplyHandler' => 'mail/SemiStructuredObjectInstanceReplyHandler.php',
'SemiStructuredObjectInstanceSearchEngine' => 'query/SemiStructuredObjectInstanceSearchEngine.php',
'SemiStructuredObjectInstanceTransaction' => 'storage/SemiStructuredObjectInstanceTransaction.php',
'SemiStructuredObjectInstanceTransactionComment' => 'storage/SemiStructuredObjectInstanceTransactionComment.php',
'SemiStructuredObjectInstanceTransactionEditor' => 'editor/SemiStructuredObjectInstanceTransactionEditor.php',
'SemiStructuredObjectInstanceTransactionQuery' => 'query/SemiStructuredObjectInstanceTransactionQuery.php',
'SemiStructuredObjectInstanceTransactionType' => 'xaction/instance/SemiStructuredObjectInstanceTransactionType.php',
'SemiStructuredObjectInstanceViewController' => 'controller/instance/SemiStructuredObjectInstanceViewController.php',
'SemiStructuredObjectNewInstanceController' => 'controller/class/SemiStructuredObjectNewInstanceController.php',
'SemiStructuredObjectType' => 'storage/SemiStructuredObjectType.php',
'SemiStructuredObjectTypeArchiveController' => 'controller/class/SemiStructuredObjectTypeArchiveController.php',
'SemiStructuredObjectTypeController' => 'controller/class/SemiStructuredObjectTypeController.php',
'SemiStructuredObjectTypeCustomFieldsTransaction' => 'xaction/class/SemiStructuredObjectTypeCustomFieldsTransaction.php',
'SemiStructuredObjectTypeDescriptionTransaction' => 'xaction/class/SemiStructuredObjectTypeDescriptionTransaction.php',
'SemiStructuredObjectTypeEditConduitAPIMethod' => 'conduit/SemiStructuredObjectTypeEditConduitAPIMethod.php',
'SemiStructuredObjectTypeEditController' => 'controller/class/SemiStructuredObjectTypeEditController.php',
'SemiStructuredObjectTypeEditEngine' => 'editor/SemiStructuredObjectTypeEditEngine.php',
'SemiStructuredObjectTypeFerretEngine' => 'search/SemiStructuredObjectTypeFerretEngine.php',
'SemiStructuredObjectTypeFulltextEngine' => 'search/SemiStructuredObjectTypeFulltextEngine.php',
'SemiStructuredObjectTypeListController' => 'controller/class/SemiStructuredObjectTypeListController.php',
'SemiStructuredObjectTypeMailReceiver' => 'mail/SemiStructuredObjectTypeMailReceiver.php',
'SemiStructuredObjectTypeNameTransaction' => 'xaction/class/SemiStructuredObjectTypeNameTransaction.php',
+ 'SemiStructuredObjectTypePHIDSearchField' => 'search/field/SemiStructuredObjectTypePHIDSearchField.php',
'SemiStructuredObjectTypePHIDType' => 'phid/SemiStructuredObjectTypePHIDType.php',
'SemiStructuredObjectTypeQuery' => 'query/SemiStructuredObjectTypeQuery.php',
'SemiStructuredObjectTypeRemarkupRule' => 'remarkup/SemiStructuredObjectTypeRemarkupRule.php',
'SemiStructuredObjectTypeReplyHandler' => 'mail/SemiStructuredObjectTypeReplyHandler.php',
'SemiStructuredObjectTypeSearchConduitAPIMethod' => 'conduit/SemiStructuredObjectTypeSearchConduitAPIMethod.php',
'SemiStructuredObjectTypeSearchEngine' => 'query/SemiStructuredObjectTypeSearchEngine.php',
'SemiStructuredObjectTypeStatusTransaction' => 'xaction/class/SemiStructuredObjectTypeStatusTransaction.php',
'SemiStructuredObjectTypeTransaction' => 'storage/SemiStructuredObjectTypeTransaction.php',
'SemiStructuredObjectTypeTransactionComment' => 'storage/SemiStructuredObjectTypeTransactionComment.php',
'SemiStructuredObjectTypeTransactionEditor' => 'editor/SemiStructuredObjectTypeTransactionEditor.php',
'SemiStructuredObjectTypeTransactionQuery' => 'query/SemiStructuredObjectTypeTransactionQuery.php',
'SemiStructuredObjectTypeTransactionType' => 'xaction/class/SemiStructuredObjectTypeTransactionType.php',
'SemiStructuredObjectTypeViewController' => 'controller/class/SemiStructuredObjectTypeViewController.php',
'SemiStructuredPatchList' => 'storage/SemiStructuredPatchList.php',
'SemiStructuredSchemaSpec' => 'storage/SemiStructuredSchemaSpec.php',
'SemiStructuredStaticSearchField' => '_to_upstream/SemiStructuredStaticSearchField.php',
),
'function' => array(),
'xmap' => array(
'SemiStructuredBaseController' => 'PhabricatorController',
'SemiStructuredDAO' => 'PhabricatorLiskDAO',
'SemiStructuredDataApplication' => 'PhabricatorApplication',
'SemiStructuredInstanceConfiguredCustomField' => array(
'SemiStructuredInstanceCustomField',
'PhabricatorStandardCustomFieldInterface',
),
'SemiStructuredInstanceConfiguredCustomFieldStorage' => 'PhabricatorCustomFieldStorage',
'SemiStructuredInstanceCustomField' => 'PhabricatorCustomField',
'SemiStructuredInstanceCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage',
'SemiStructuredInstanceCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage',
'SemiStructuredInstanceEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'SemiStructuredInstanceSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'SemiStructuredObjectInstance' => array(
'SemiStructuredDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorSubscribableInterface',
'PhabricatorFlaggableInterface',
'PhabricatorProjectInterface',
'PhabricatorFerretInterface',
'PhabricatorFulltextInterface',
'PhabricatorMentionableInterface',
'PhabricatorConduitResultInterface',
'PhabricatorCustomFieldInterface',
'PhabricatorDestructibleInterface',
),
'SemiStructuredObjectInstanceClassTransaction' => 'SemiStructuredObjectInstanceTransactionType',
'SemiStructuredObjectInstanceController' => 'SemiStructuredBaseController',
'SemiStructuredObjectInstanceDescriptionTransaction' => 'SemiStructuredObjectInstanceTransactionType',
'SemiStructuredObjectInstanceEditController' => 'SemiStructuredBaseController',
'SemiStructuredObjectInstanceEditEngine' => 'PhabricatorEditEngine',
'SemiStructuredObjectInstanceFerretEngine' => 'PhabricatorFerretEngine',
'SemiStructuredObjectInstanceFulltextEngine' => 'PhabricatorFulltextEngine',
- 'SemiStructuredObjectInstanceListController' => 'SemiStructuredObjectTypeController',
+ 'SemiStructuredObjectInstanceListController' => 'SemiStructuredObjectInstanceController',
'SemiStructuredObjectInstanceMailReceiver' => 'PhabricatorObjectMailReceiver',
'SemiStructuredObjectInstanceNameTransaction' => 'SemiStructuredObjectInstanceTransactionType',
'SemiStructuredObjectInstancePHIDType' => 'PhabricatorPHIDType',
'SemiStructuredObjectInstanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'SemiStructuredObjectInstanceRawDataTransaction' => 'SemiStructuredObjectInstanceTransactionType',
'SemiStructuredObjectInstanceReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'SemiStructuredObjectInstanceSearchEngine' => 'PhabricatorApplicationSearchEngine',
'SemiStructuredObjectInstanceTransaction' => 'PhabricatorModularTransaction',
'SemiStructuredObjectInstanceTransactionComment' => 'PhabricatorApplicationTransactionComment',
'SemiStructuredObjectInstanceTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'SemiStructuredObjectInstanceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'SemiStructuredObjectInstanceTransactionType' => 'PhabricatorModularTransactionType',
'SemiStructuredObjectInstanceViewController' => 'SemiStructuredObjectInstanceController',
'SemiStructuredObjectNewInstanceController' => 'SemiStructuredObjectTypeController',
'SemiStructuredObjectType' => array(
'SemiStructuredDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorMentionableInterface',
'PhabricatorSubscribableInterface',
'PhabricatorProjectInterface',
'PhabricatorConduitResultInterface',
'PhabricatorFlaggableInterface',
'PhabricatorDestructibleInterface',
'PhabricatorFerretInterface',
'PhabricatorFulltextInterface',
),
'SemiStructuredObjectTypeArchiveController' => 'SemiStructuredBaseController',
'SemiStructuredObjectTypeController' => 'SemiStructuredBaseController',
'SemiStructuredObjectTypeCustomFieldsTransaction' => 'SemiStructuredObjectTypeTransactionType',
'SemiStructuredObjectTypeDescriptionTransaction' => 'SemiStructuredObjectTypeTransactionType',
'SemiStructuredObjectTypeEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
'SemiStructuredObjectTypeEditController' => 'SemiStructuredBaseController',
'SemiStructuredObjectTypeEditEngine' => 'PhabricatorEditEngine',
'SemiStructuredObjectTypeFerretEngine' => 'PhabricatorFerretEngine',
'SemiStructuredObjectTypeFulltextEngine' => 'PhabricatorFulltextEngine',
'SemiStructuredObjectTypeListController' => 'SemiStructuredBaseController',
'SemiStructuredObjectTypeMailReceiver' => 'PhabricatorObjectMailReceiver',
'SemiStructuredObjectTypeNameTransaction' => 'SemiStructuredObjectTypeTransactionType',
+ 'SemiStructuredObjectTypePHIDSearchField' => 'PhabricatorSearchField',
'SemiStructuredObjectTypePHIDType' => 'PhabricatorPHIDType',
'SemiStructuredObjectTypeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'SemiStructuredObjectTypeRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'SemiStructuredObjectTypeReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'SemiStructuredObjectTypeSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'SemiStructuredObjectTypeSearchEngine' => 'PhabricatorApplicationSearchEngine',
'SemiStructuredObjectTypeStatusTransaction' => 'SemiStructuredObjectTypeTransactionType',
'SemiStructuredObjectTypeTransaction' => 'PhabricatorModularTransaction',
'SemiStructuredObjectTypeTransactionComment' => 'PhabricatorApplicationTransactionComment',
'SemiStructuredObjectTypeTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
'SemiStructuredObjectTypeTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'SemiStructuredObjectTypeTransactionType' => 'PhabricatorModularTransactionType',
'SemiStructuredObjectTypeViewController' => 'SemiStructuredObjectTypeController',
'SemiStructuredPatchList' => 'PhabricatorSQLPatchList',
'SemiStructuredSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'SemiStructuredStaticSearchField' => 'PhabricatorSearchField',
),
));
diff --git a/src/application/SemiStructuredDataApplication.php b/src/application/SemiStructuredDataApplication.php
index 20f0932..13a3f95 100644
--- a/src/application/SemiStructuredDataApplication.php
+++ b/src/application/SemiStructuredDataApplication.php
@@ -1,67 +1,72 @@
<?php
final class SemiStructuredDataApplication extends PhabricatorApplication {
const ICON_OBJECT_TYPE = 'fa-camera';
const ICON_OBJECT_INSTANCE = 'fa-dribbble';
const ICON_OBJECT_TYPE_MANY = 'fa-todo';
const ICON_OBJECT_INSTANCE_MANY = 'fa-group';
const ICON_APPLICATION = 'fa-wpforms';
public function getName() {
return pht('Semi-Structured');
}
public function getShortDescription() {
return pht('Work with evolving data sets.');
}
public function getIcon() {
return self::ICON_APPLICATION;
}
public function getBaseURI() {
return '/semistruct/';
}
public function getRemarkupRules() {
// I think I want to use this method to allow classes
// to define user-provided "RemarkupRule" for their instances.
return array(
new SemiStructuredObjectTypeRemarkupRule(),
);
}
public function getRoutes() {
return array(
'/semistruct/' => array(
$this->getQueryRoutePattern() =>
'SemiStructuredObjectTypeListController',
$this->getEditRoutePattern('editclass/') =>
'SemiStructuredObjectTypeEditController',
'type/(?:(?P<id>\d+)/)?' => array(
'' => 'SemiStructuredObjectTypeViewController',
- 'items/' => 'SemiStructuredObjectInstanceListController',
- $this->getQueryRoutePattern() =>
- 'SemiStructuredObjectInstanceListController',
'archive/' => 'SemiStructuredObjectTypeArchiveController',
),
// If the ID field is called `id`, the EditEngine thinks this is
// editing an existing object.
'type/(?:(?P<typeid>\d+)/)?' => array(
'new/' => 'SemiStructuredObjectNewInstanceController',
+ 'items/' => 'SemiStructuredObjectInstanceListController',
+ $this->getQueryRoutePattern() =>
+ 'SemiStructuredObjectInstanceListController',
+ ),
+
+ 'instance/' => array(
+ $this->getQueryRoutePattern() =>
+ 'SemiStructuredObjectInstanceListController',
),
$this->getEditRoutePattern('editinstance/') =>
'SemiStructuredObjectInstanceEditController',
'instance/(?:(?P<id>\d+)/)?' =>
'SemiStructuredObjectInstanceViewController',
),
);
}
}
diff --git a/src/controller/SemiStructuredBaseController.php b/src/controller/SemiStructuredBaseController.php
index d9fd017..c2871e7 100644
--- a/src/controller/SemiStructuredBaseController.php
+++ b/src/controller/SemiStructuredBaseController.php
@@ -1,15 +1,10 @@
<?php
abstract class SemiStructuredBaseController extends PhabricatorController {
- public function buildApplicationMenu() {
- return $this->newApplicationMenu();
- // ->setSearchEngine(new PhabricatorBadgesSearchEngine());
- }
-
public function shouldAllowPublic() {
return true;
}
}
diff --git a/src/controller/class/SemiStructuredObjectTypeController.php b/src/controller/class/SemiStructuredObjectTypeController.php
index 8b206cf..eba01bf 100644
--- a/src/controller/class/SemiStructuredObjectTypeController.php
+++ b/src/controller/class/SemiStructuredObjectTypeController.php
@@ -1,89 +1,87 @@
<?php
abstract class SemiStructuredObjectTypeController
extends SemiStructuredBaseController {
private $objectType;
public function setObjectType(SemiStructuredObjectType $object_type) {
$this->objectType = $object_type;
return $this;
}
public function getObjectType() {
return $this->objectType;
}
- // TODO ???
public function buildApplicationMenu() {
return $this->buildSideNavView()->getMenu();
}
-
protected function buildHeaderView() {
$viewer = $this->getViewer();
$object_type = $this->getObjectType();
if ($object_type->isArchived()) {
$status_icon = 'fa-ban';
$status_color = 'dark';
} else {
$status_icon = 'fa-check';
$status_color = 'bluegrey';
}
$status_name = idx(
SemiStructuredObjectType::getStatusNameMap(),
$object_type->getStatus());
return id(new PHUIHeaderView())
->setHeader($object_type->getName())
->setUser($viewer)
->setPolicyObject($object_type)
->setStatus($status_icon, $status_color, $status_name)
->setHeaderIcon(SemiStructuredDataApplication::ICON_OBJECT_TYPE);
}
protected function buildApplicationCrumbs() {
$object_type = $this->getObjectType();
$uri = $object_type->getURI();
$crumbs = parent::buildApplicationCrumbs();
$crumbs->addTextCrumb($object_type->getName(), $uri);
$crumbs->setBorder(true);
return $crumbs;
}
protected function buildSideNavView($filter = null) {
$viewer = $this->getViewer();
$object_type = $this->getObjectType();
$id = $object_type->getID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$object_type,
PhabricatorPolicyCapability::CAN_EDIT);
$nav = id(new AphrontSideNavFilterView())
->setBaseURI(new PhutilURI($this->getApplicationURI()));
$nav->addLabel(pht('Object Type'));
$nav->addFilter(
'view',
pht('View Object Type'),
$object_type->getURI(),
SemiStructuredDataApplication::ICON_OBJECT_TYPE);
$nav->addFilter(
'instances',
pht('View Instances'),
$this->getApplicationURI("/type/{$id}/items/"),
'fa-group');
$nav->selectFilter($filter);
return $nav;
}
}
diff --git a/src/controller/instance/SemiStructuredObjectInstanceController.php b/src/controller/instance/SemiStructuredObjectInstanceController.php
index 9f45643..eb0eeea 100644
--- a/src/controller/instance/SemiStructuredObjectInstanceController.php
+++ b/src/controller/instance/SemiStructuredObjectInstanceController.php
@@ -1,74 +1,86 @@
<?php
abstract class SemiStructuredObjectInstanceController
extends SemiStructuredBaseController {
private $object;
private $objectType;
public function setObject(SemiStructuredObjectInstance $object) {
$this->object = $object;
+ $this->setObjectType($object->getClass());
return $this;
}
public function getObject() {
return $this->object;
}
+ public function setObjectType(SemiStructuredObjectType $object_type) {
+ $this->objectType = $object_type;
+ return $this;
+ }
+
+ public function getObjectType() {
+ return $this->objectType;
+ }
+
protected function buildHeaderView() {
$viewer = $this->getViewer();
$object = $this->getObject();
$object_type = $object->getClass();
if ($object_type->isArchived()) {
$status_icon = 'fa-ban';
$status_color = 'dark';
} else {
$status_icon = 'fa-check';
$status_color = 'bluegrey';
}
$status_name = idx(
SemiStructuredObjectType::getStatusNameMap(),
$object_type->getStatus());
return id(new PHUIHeaderView())
->setHeader(
pht(
'%s: %d %s',
$object_type->getName(),
$object->getID(),
$object->getName()))
->setUser($viewer)
->setPolicyObject($object_type)
->setStatus($status_icon, $status_color, $status_name)
->setHeaderIcon(SemiStructuredDataApplication::ICON_OBJECT_TYPE);
}
protected function buildApplicationCrumbs() {
$object = $this->getObject();
- $object_type = $object->getClass();
+ $object_type = $this->getObjectType();
$can_create = true;
$crumbs = parent::buildApplicationCrumbs();
$crumbs->addTextCrumb(
$object_type->getName(),
$object_type->getURI('items/'));
- $crumbs->addTextCrumb(
- pht('%d %s', $object->getID(), $object->getName()), $object->getURI());
+ if ($object) {
+ $crumbs->addTextCrumb(
+ pht('%d %s', $object->getID(), $object->getName()), $object->getURI());
+ }
$crumbs->setBorder(true);
$crumbs->addAction(
id(new PHUIListItemView())
->setName(pht('Create %s', $object_type->getName()))
->setHref($object_type->getURI('new/'))
->setIcon('fa-plus-square')
->setWorkflow(!$can_create)
->setDisabled(!$can_create));
return $crumbs;
}
}
diff --git a/src/controller/instance/SemiStructuredObjectInstanceListController.php b/src/controller/instance/SemiStructuredObjectInstanceListController.php
index 0f5a8a2..51d71af 100644
--- a/src/controller/instance/SemiStructuredObjectInstanceListController.php
+++ b/src/controller/instance/SemiStructuredObjectInstanceListController.php
@@ -1,60 +1,57 @@
<?php
final class SemiStructuredObjectInstanceListController
- extends SemiStructuredObjectTypeController {
+ extends SemiStructuredObjectInstanceController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $object_type = id(new SemiStructuredObjectTypeQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->executeOne();
+ $object_type = SemiStructuredObjectTypeQuery::loadOneById(
+ $viewer,
+ $request->getURIData('typeid'));
if (!$object_type) {
return new Aphront404Response();
}
$this->setObjectType($object_type);
$query_key = $request->getURIData('queryKey');
$controller = id(new PhabricatorApplicationSearchController())
->setQueryKey($query_key)
->setSearchEngine(
id(new SemiStructuredObjectInstanceSearchEngine())
->setObjectType($object_type))
->setNavigation($this->buildSideNavView());
return $this->delegateToController($controller);
}
public function buildSideNavView($filter = null) {
$user = $this->getRequest()->getUser();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
id(new SemiStructuredObjectInstanceSearchEngine())
->setObjectType($this->getObjectType())
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->selectFilter($filter);
return $nav;
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$object_type = $this->getObjectType();
id(new SemiStructuredObjectInstanceEditEngine())
->setObjectType($object_type)
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}
}
diff --git a/src/query/SemiStructuredObjectInstanceSearchEngine.php b/src/query/SemiStructuredObjectInstanceSearchEngine.php
index 38d6371..53e5c29 100644
--- a/src/query/SemiStructuredObjectInstanceSearchEngine.php
+++ b/src/query/SemiStructuredObjectInstanceSearchEngine.php
@@ -1,207 +1,311 @@
<?php
final class SemiStructuredObjectInstanceSearchEngine
extends PhabricatorApplicationSearchEngine {
private $objectType;
public function setObjectType(SemiStructuredObjectType $object_type) {
$this->objectType = $object_type;
return $this;
}
public function getObjectType() {
return $this->objectType;
}
public function getResultTypeDescription() {
return pht('Object Instances');
}
public function getApplicationClassName() {
return 'SemiStructuredDataApplication';
}
public function newQuery() {
$query = id(new SemiStructuredObjectInstanceQuery());
if ($this->getObjectType()) {
$query->withObjectType($this->getObjectType());
}
return $query;
}
protected function buildCustomSearchFields() {
$fields = array(
);
if ($this->getObjectType()) {
$fields[] = id(new SemiStructuredStaticSearchField())
->setKey('objecttype')
->setLabel(pht('Object Type'))
->setValue($this->getObjectType()->getName());
+ $fields[] = id(new SemiStructuredObjectTypePHIDSearchField())
+ ->setKey('classPHIDs')
+ ->setLabel(pht('Object Type PHID'))
+ ->setValue($this->getObjectType()->getPHID());
}
return $fields;
}
protected function getURI($path) {
- return "/semistruct/type/{$this->getObjectType()->getID()}/{$path}";
+ if ($this->getObjectType()) {
+ return "/semistruct/type/{$this->getObjectType()->getID()}/{$path}";
+ }
+ return "/semistruct/instance/{$path}";
+ }
+
+ public function getQueryResultsPageURI($query_key) {
+ $this->loadObjectTypeFromQuery($query_key);
+ return parent::getQueryResultsPageURI($query_key);
+ }
+
+ public function getCustomizeURI($query_key, $object_phid, $context_phid) {
+ $this->loadObjectTypeFromQuery($query_key);
+ return parent::getCustomizeURI($query_key, $object_phid, $context_phid);
+ }
+
+ public function isBuiltinQuery($query_key) {
+ $this->loadObjectTypeFromQuery($query_key);
+
+ $builtins = $this->getBuiltinQueries();
+ $raw = $this->getRawQueryNames();
+ return isset($builtins[$query_key]) || isset($raw[$query_key]);
+
+ }
+
+ public function getQueryManagementURI() {
+ if ($this->getObjectType()) {
+ return parent::getQueryManagementURI();
+ }
+ return '/semistruct/';
}
protected function getBuiltinQueryNames() {
+ $raw_names = $this->getRawQueryNames();
+
+ if (!$this->getObjectType()) {
+ return $raw_names;
+ }
+
+ $names = array();
+ $suffix = '-'.$this->getObjectType()->getId();
+
+ foreach ($raw_names as $key => $value) {
+ $names[$key.$suffix] = $value;
+ }
+
+ return $names;
+ }
+
+ private function getRawQueryNames() {
$names = array();
$names['all'] = pht('All Instances');
return $names;
}
+ private function loadObjectTypeFromQuery($query_key) {
+ $matches = null;
+ if (preg_match('/^(\w+)-(\d+)$/', $query_key, $matches)) {
+ $type_id = $matches[2];
+ $query_key = $matches[1];
+
+ if (!$this->getObjectType()) {
+ $this->setObjectType(
+ SemiStructuredObjectTypeQuery::loadOneById(
+ $this->requireViewer(),
+ $type_id));
+ }
+ return $matches[1];
+ }
+
+ return $query_key;
+ }
+
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
- $viewer = $this->requireViewer();
+
+ $query_key = $this->loadObjectTypeFromQuery($query_key);
switch ($query_key) {
case 'all':
return $query;
case 'open':
return $query->setParameter(
'statuses',
array(
SemiStructuredObjectType::STATUS_ACTIVE,
));
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
+ public function loadAllNamedQueries() {
+ $named_queries = parent::loadAllNamedQueries();
+
+ if (!$this->getObjectType()) {
+ return $named_queries;
+ }
+
+ $target_class_phid = $this->getObjectType()->getPHID();
+
+ $saved_queries = id(new PhabricatorSavedQueryQuery())
+ ->setViewer($this->requireViewer())
+ ->withQueryKeys(mpull($named_queries, 'getQueryKey'))
+ ->execute();
+ $saved_queries = mpull($saved_queries, 'getParameters', 'getQueryKey');
+
+ foreach ($named_queries as $key => $named_query) {
+ if ($named_query->getIsBuiltin()) {
+ continue;
+ }
+
+ $class_phids = idxv($saved_queries, array($key, 'classPHIDs'));
+
+ if (!$class_phids) {
+ continue;
+ }
+
+ if (array_search($target_class_phid, $class_phids) === false) {
+ unset($named_queries[$key]);
+ }
+
+ }
+
+ return $named_queries;
+ }
+
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
// TODO type id/phid
// if ($map['statuses']) {
// $query->withStatuses($map['statuses']);
// }
// if ($map['editable'] !== null) {
// $query->withCanEdit($map['editable']);
// }
return $query;
}
protected function getRequiredHandlePHIDsForResultList(
array $objects,
PhabricatorSavedQuery $query) {
return array();
}
public function renderResultsDirectly(array $items) {
return $this->renderResultList(
$items,
new PhabricatorSavedQuery(),
array());
}
protected function renderResultList(
array $items,
PhabricatorSavedQuery $query ,
array $handles) {
$viewer = $this->requireViewer();
if ($items) {
$edge_query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(mpull($items, 'getPHID'))
->withEdgeTypes(
array(
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
));
$edge_query->execute();
}
$list = id(new PHUIObjectItemListView())
->setViewer($viewer);
foreach ($items as $instance) {
$item = id(new PHUIObjectItemView())
->setViewer($viewer)
->setHeader($instance->getName())
->setHref($instance->getURI())
->setObject($instance);
$icon = id(new PHUIIconView())
->setIcon($instance->getIcon());
$item->setImageIcon($icon);
$item->setEpoch($instance->getDateModified());
$phid = $instance->getPHID();
$project_phids = $edge_query->getDestinationPHIDs(array($phid));
$project_handles = $viewer->loadHandles($project_phids);
$item->addAttribute(
id(new PHUIHandleTagListView())
->setLimit(4)
->setNoDataString(pht('No Tags'))
->setSlim(true)
->setHandles($project_handles));
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No objects found.'));
return $result;
}
/* -( Export )------------------------------------------------------------ */
protected function newExportFields() {
return array(
id(new PhabricatorStringExportField())
->setKey('name')
->setLabel(pht('Name')),
id(new PhabricatorStringExportField())
->setKey('description')
->setLabel(pht('Description')),
id(new PhabricatorStringExportField())
->setKey('rawData')
->setLabel(pht('Raw Data')),
id(new PhabricatorPHIDExportField())
->setKey('classPHID')
->setLabel(pht('Class PHID')),
id(new PhabricatorURIExportField())
->setKey('uri')
->setLabel(pht('URI')),
);
}
protected function newExportData(array $instances) {
// $viewer = $this->requireViewer();
$export = array();
foreach ($instances as $instance) {
$export[] = array(
'name' => $instance->getName(),
'uri' => PhabricatorEnv::getProductionURI($instance->getURI()),
'description' => $instance->getDescription(),
'classPHID' => $instance->getClassPHID(),
'rawData' => $instance->getRawData(),
);
}
return $export;
}
}
diff --git a/src/query/SemiStructuredObjectTypeQuery.php b/src/query/SemiStructuredObjectTypeQuery.php
index 9103282..48c1e55 100644
--- a/src/query/SemiStructuredObjectTypeQuery.php
+++ b/src/query/SemiStructuredObjectTypeQuery.php
@@ -1,84 +1,107 @@
<?php
final class SemiStructuredObjectTypeQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $statuses;
private $canEdit;
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withStatuses(array $statuses) {
$this->statuses = $statuses;
return $this;
}
public function withCanEdit($can_edit) {
$this->canEdit = $can_edit;
return $this;
}
public function newResultObject() {
return new SemiStructuredObjectType();
}
+ // There might already be a similar solution in the Phorge code base.
+ public static function loadOneById(PhabricatorUser $viewer, $id) {
+ $viewer_key = $viewer->getCacheFragment();
+ $cache = PhabricatorCaches::getRequestCache();
+ $cache_key = self::class.'ById';
+
+ $collection = $cache->getKey($cache_key, array());
+ $value = idxv($collection, array($viewer_key, $id));
+
+ if ($value) {
+ return $value;
+ }
+
+ $value = (new self())
+ ->setViewer($viewer)
+ ->withIds(array($id))
+ ->executeOne();
+
+ $collection[$viewer_key][$id] = $value;
+ $cache->setKey($cache_key, $collection);
+ return $value;
+ }
+
protected function didFilterPage(array $items) {
if ($this->canEdit) {
$items = id(new PhabricatorPolicyFilter())
->setViewer($this->getViewer())
->requireCapabilities(array(
PhabricatorPolicyCapability::CAN_EDIT,
))
->apply($items);
}
return $items;
}
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = parent::buildWhereClauseParts($conn);
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,
'classes.id IN (%Ld)',
$this->ids);
}
if ($this->phids !== null) {
$where[] = qsprintf(
$conn,
'classes.phid IN (%Ls)',
$this->phids);
}
if ($this->statuses !== null) {
$where[] = qsprintf(
$conn,
'classes.status IN (%Ls)',
$this->statuses);
}
return $where;
}
public function getQueryApplicationClass() {
return 'SemiStructuredDataApplication';
}
protected function getPrimaryTableAlias() {
return 'classes';
}
}
diff --git a/src/search/field/SemiStructuredObjectTypePHIDSearchField.php b/src/search/field/SemiStructuredObjectTypePHIDSearchField.php
new file mode 100644
index 0000000..89fda6e
--- /dev/null
+++ b/src/search/field/SemiStructuredObjectTypePHIDSearchField.php
@@ -0,0 +1,41 @@
+<?php
+
+final class SemiStructuredObjectTypePHIDSearchField
+ extends PhabricatorSearchField {
+
+ private $value;
+
+ public function setValue(string $value) {
+ $this->value = $value;
+ return $this;
+ }
+
+ public function readValueFromRequest(AphrontRequest $request) {
+ $id = $request->getURIData('typeid');
+ if ($id === null) {
+ return null;
+ }
+
+ $object_type = SemiStructuredObjectTypeQuery::loadOneById(
+ $this->getViewer(),
+ $id);
+ return array($object_type->getPHID());
+ }
+
+
+ protected function getValueFromRequest(AphrontRequest $request, $key) {
+ throw new Exception('Did not expect call');
+ }
+
+
+ protected function getValueForControl() {
+ return $this->value;
+ }
+
+ protected function newControl() {
+ return id(new AphrontFormMarkupControl())
+ ->setValue($this->value);
+ }
+
+
+}
diff --git a/src/storage/SemiStructuredObjectType.php b/src/storage/SemiStructuredObjectType.php
index 296f30c..f060e03 100644
--- a/src/storage/SemiStructuredObjectType.php
+++ b/src/storage/SemiStructuredObjectType.php
@@ -1,204 +1,202 @@
<?php
final class SemiStructuredObjectType extends SemiStructuredDAO
implements
PhabricatorPolicyInterface,
PhabricatorApplicationTransactionInterface,
// PhabricatorMarkupInterface, ?
PhabricatorMentionableInterface,
PhabricatorSubscribableInterface,
PhabricatorProjectInterface,
PhabricatorConduitResultInterface,
PhabricatorFlaggableInterface,
PhabricatorDestructibleInterface,
PhabricatorFerretInterface,
PhabricatorFulltextInterface {
protected $viewPolicy;
protected $editPolicy;
protected $name;
protected $status;
protected $description;
protected $customFieldsConfig = array();
-// icon/logo
-
-
const STATUS_ACTIVE = 'active';
const STATUS_ARCHIVED = 'archived';
public static function initializeNewObjectType(PhabricatorUser $actor) {
return id(new self())
->setName('')
->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy())
->setEditPolicy($actor->getPHID())
->setStatus(self::STATUS_ACTIVE);
}
public function getCustomFieldsConfig() {
if (!$this->customFieldsConfig) {
return array();
}
return $this->customFieldsConfig;
}
public static function getStatusNameMap() {
return array(
self::STATUS_ACTIVE => pht('Active'),
self::STATUS_ARCHIVED => pht('Archived'),
);
}
protected function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'customFieldsConfig' => self::SERIALIZATION_JSON,
),
self::CONFIG_COLUMN_SCHEMA => array(
'name' => 'sort255',
'status' => 'text32',
'description' => 'text',
),
) + parent::getConfiguration();
}
public function getPHIDType() {
return SemiStructuredObjectTypePHIDType::TYPECONST;
}
public function isArchived() {
return ($this->getStatus() == self::STATUS_ARCHIVED);
}
public function getURI($path = '') {
return urisprintf('/semistruct/type/%d/%s', $this->getID(), $path);
}
public function getObjectName() {
return pht('Object Type %d', $this->getID());
}
public function getIcon() {
// TODO copy the feature from Projects, where you can put a custom image
// or select from a list.
return SemiStructuredDataApplication::ICON_OBJECT_TYPE;
}
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
public function getApplicationTransactionEditor() {
return new SemiStructuredObjectTypeTransactionEditor();
}
public function getApplicationTransactionTemplate() {
return new SemiStructuredObjectTypeTransaction();
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
// TODO can-create-instances
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
/* -( PhabricatorConduitResultInterface )---------------------------------- */
public function getFieldSpecificationsForConduit() {
return array(
(new PhabricatorConduitSearchFieldSpecification())
->setKey('name')
->setType('string')
->setDescription(pht('The name of the object type.')),
(new PhabricatorConduitSearchFieldSpecification())
->setKey('description')
->setType('remarkup')
->setDescription(pht('The description.')),
(new PhabricatorConduitSearchFieldSpecification())
->setKey('status')
->setType('string')
->setDescription(pht('Status of this object data.')),
(new PhabricatorConduitSearchFieldSpecification())
->setKey('customFieldsConfig')
->setType('map<string, wild>')
->setDescription(pht('Custom Fields definition')),
);
}
public function getFieldValuesForConduit() {
return array(
'name' => $this->getName(),
'description' => array(
'raw' => $this->getDescription(),
),
'status' => $this->getStatus(),
'customFieldsConfig' => $this->getCustomFieldsConfig(),
);
}
public function getConduitSearchAttachments() {
return array();
}
/* -( PhabricatorFerretInterface )----------------------------------------- */
public function newFerretEngine() {
return new SemiStructuredObjectTypeFerretEngine();
}
/* -( PhabricatorFulltextInterface )--------------------------------------- */
public function newFulltextEngine() {
return new SemiStructuredObjectTypeFulltextEngine();
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->openTransaction();
+ // TODO destroy all instances....
$this->delete();
$this->saveTransaction();
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */
public function isAutomaticallySubscribed($phid) {
return false;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 18:21 (2 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1108595
Default Alt Text
(43 KB)

Event Timeline