Page MenuHomePhorge

No OneTemporary

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 1bb27137cc..09e6f6c6de 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,122 +1,138 @@
<?php
/**
* This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
* @generated
*/
phutil_register_library_map(array(
'class' =>
array(
'Aphront404Response' => 'aphront/response/404',
'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
'AphrontController' => 'aphront/controller',
'AphrontDatabaseConnection' => 'storage/connection/base',
'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration',
'AphrontDefaultApplicationController' => 'aphront/default/controller',
'AphrontDialogResponse' => 'aphront/response/dialog',
'AphrontDialogView' => 'view/dialog',
'AphrontErrorView' => 'view/form/error',
'AphrontFormControl' => 'view/form/control/base',
'AphrontFormSelectControl' => 'view/form/control/select',
'AphrontFormSubmitControl' => 'view/form/control/submit',
'AphrontFormTextAreaControl' => 'view/form/control/textarea',
'AphrontFormTextControl' => 'view/form/control/text',
'AphrontFormView' => 'view/form/base',
'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql',
'AphrontNullView' => 'view/null',
'AphrontPageView' => 'view/page/base',
'AphrontPanelView' => 'view/layout/panel',
'AphrontQueryConnectionException' => 'storage/exception/connection',
'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost',
'AphrontQueryCountException' => 'storage/exception/count',
'AphrontQueryException' => 'storage/exception/base',
'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing',
'AphrontQueryParameterException' => 'storage/exception/parameter',
'AphrontQueryRecoverableException' => 'storage/exception/recoverable',
'AphrontRedirectResponse' => 'aphront/response/redirect',
'AphrontRequest' => 'aphront/request',
'AphrontResponse' => 'aphront/response/base',
'AphrontTableView' => 'view/control/table',
'AphrontURIMapper' => 'aphront/mapper',
'AphrontView' => 'view/base',
'AphrontWebpageResponse' => 'aphront/response/webpage',
'DifferentialAction' => 'applications/review/constants/action',
'DifferentialChangeType' => 'applications/review/constants/changetype',
'DifferentialLintStatus' => 'applications/review/constants/lintstatus',
'DifferentialRevisionStatus' => 'applications/review/constants/revisionstatus',
'DifferentialUnitStatus' => 'applications/review/constants/unitstatus',
'LiskDAO' => 'storage/lisk/dao',
'PhabricatorController' => 'applications/base/controller/base',
'PhabricatorDirectoryCategory' => 'applications/directory/storage/category',
'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete',
'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit',
'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist',
'PhabricatorDirectoryController' => 'applications/directory/controller/base',
'PhabricatorDirectoryDAO' => 'applications/directory/storage/base',
'PhabricatorDirectoryItem' => 'applications/directory/storage/item',
'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete',
'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit',
'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist',
'PhabricatorDirectoryMainController' => 'applications/directory/controller/main',
'PhabricatorLiskDAO' => 'applications/base/storage/lisk',
+ 'PhabricatorPHID' => 'applications/phid/storage/phid',
+ 'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate',
+ 'PhabricatorPHIDController' => 'applications/phid/controller/base',
+ 'PhabricatorPHIDDAO' => 'applications/phid/storage/base',
+ 'PhabricatorPHIDListController' => 'applications/phid/controller/list',
+ 'PhabricatorPHIDType' => 'applications/phid/storage/type',
+ 'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit',
+ 'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist',
'PhabricatorStandardPageView' => 'view/page/standard',
),
'function' =>
array(
'_qsprintf_check_scalar_type' => 'storage/qsprintf',
'_qsprintf_check_type' => 'storage/qsprintf',
'qsprintf' => 'storage/qsprintf',
'queryfx' => 'storage/queryfx',
'queryfx_all' => 'storage/queryfx',
'queryfx_one' => 'storage/queryfx',
'vqsprintf' => 'storage/qsprintf',
'vqueryfx' => 'storage/queryfx',
'xsprintf_query' => 'storage/qsprintf',
),
'requires_class' =>
array(
'Aphront404Response' => 'AphrontResponse',
'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
'AphrontDefaultApplicationController' => 'AphrontController',
'AphrontDialogResponse' => 'AphrontResponse',
'AphrontDialogView' => 'AphrontView',
'AphrontErrorView' => 'AphrontView',
'AphrontFormControl' => 'AphrontView',
'AphrontFormSelectControl' => 'AphrontFormControl',
'AphrontFormSubmitControl' => 'AphrontFormControl',
'AphrontFormTextAreaControl' => 'AphrontFormControl',
'AphrontFormTextControl' => 'AphrontFormControl',
'AphrontFormView' => 'AphrontView',
'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection',
'AphrontNullView' => 'AphrontView',
'AphrontPageView' => 'AphrontView',
'AphrontPanelView' => 'AphrontView',
'AphrontQueryConnectionException' => 'AphrontQueryException',
'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException',
'AphrontQueryCountException' => 'AphrontQueryException',
'AphrontQueryObjectMissingException' => 'AphrontQueryException',
'AphrontQueryParameterException' => 'AphrontQueryException',
'AphrontQueryRecoverableException' => 'AphrontQueryException',
'AphrontRedirectResponse' => 'AphrontResponse',
'AphrontTableView' => 'AphrontView',
'AphrontWebpageResponse' => 'AphrontResponse',
'PhabricatorController' => 'AphrontController',
'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryController' => 'PhabricatorController',
'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO',
'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO',
'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController',
'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController',
'PhabricatorLiskDAO' => 'LiskDAO',
+ 'PhabricatorPHID' => 'PhabricatorPHIDDAO',
+ 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController',
+ 'PhabricatorPHIDController' => 'PhabricatorController',
+ 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO',
+ 'PhabricatorPHIDListController' => 'PhabricatorPHIDController',
+ 'PhabricatorPHIDType' => 'PhabricatorPHIDDAO',
+ 'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController',
+ 'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController',
'PhabricatorStandardPageView' => 'AphrontPageView',
),
'requires_interface' =>
array(
),
));
diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
index f73dda95f0..4765cf56e6 100644
--- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
+++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
@@ -1,100 +1,109 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group aphront
*/
class AphrontDefaultApplicationConfiguration
extends AphrontApplicationConfiguration {
public function getApplicationName() {
return 'aphront-default';
}
public function getURIMap() {
return array(
'/repository/' => array(
'$' => 'RepositoryListController',
'new/$' => 'RepositoryEditController',
'edit/(?<id>\d+)/$' => 'RepositoryEditController',
'delete/(?<id>\d+)/$' => 'RepositoryDeleteController',
),
'/' => array(
- '$' => 'AphrontDirectoryMainController',
+ '$' => 'PhabricatorDirectoryMainController',
),
'/directory/' => array(
- 'item/$' => 'AphrontDirectoryItemListController',
- 'item/edit/(?:(?<id>\d+)/)?$' => 'AphrontDirectoryItemEditController',
- 'item/delete/(?<id>\d+)/' => 'AphrontDirectoryItemDeleteController',
+ 'item/$'
+ => 'PhabricatorDirectoryItemListController',
+ 'item/edit/(?:(?<id>\d+)/)?$'
+ => 'PhabricatorDirectoryItemEditController',
+ 'item/delete/(?<id>\d+)/'
+ => 'PhabricatorDirectoryItemDeleteController',
'category/$'
- => 'AphrontDirectoryCategoryListController',
+ => 'PhabricatorDirectoryCategoryListController',
'category/edit/(?:(?<id>\d+)/)?$'
- => 'AphrontDirectoryCategoryEditController',
+ => 'PhabricatorDirectoryCategoryEditController',
'category/delete/(?<id>\d+)/'
- => 'AphrontDirectoryCategoryDeleteController',
+ => 'PhabricatorDirectoryCategoryDeleteController',
+ ),
+ '/phid/' => array(
+ '$' => 'PhabricatorPHIDListController',
+ 'type/$' => 'PhabricatorPHIDTypeListController',
+ 'type/edit/(?:(?<id>\d+)/)?$' => 'PhabricatorPHIDTypeEditController',
+ 'new/$' => 'PhabricatorPHIDAllocateController',
),
'.*' => 'AphrontDefaultApplicationController',
);
}
public function buildRequest() {
$request = new AphrontRequest($this->getHost(), $this->getPath());
$request->setRequestData($_GET + $_POST);
return $request;
}
public function handleException(Exception $ex) {
$class = phutil_escape_html(get_class($ex));
$message = phutil_escape_html($ex->getMessage());
$content =
'<div class="aphront-unhandled-exception">'.
'<h1>Unhandled Exception "'.$class.'": '.$message.'</h1>'.
'<code>'.phutil_escape_html((string)$ex).'</code>'.
'</div>';
$view = new PhabricatorStandardPageView();
$view->appendChild($content);
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
}
public function willSendResponse(AphrontResponse $response) {
$request = $this->getRequest();
if ($response instanceof AphrontDialogResponse) {
if (!$request->isAjax()) {
$view = new PhabricatorStandardPageView();
$view->appendChild(
'<div style="padding: 2em 0;">'.
$response->buildResponseString().
'</div>');
$response = new AphrontWebpageResponse();
$response->setContent($view->render());
return $response;
}
}
return $response;
}
}
diff --git a/src/aphront/response/webpage/AphrontWebpageResponse.php b/src/aphront/response/webpage/AphrontWebpageResponse.php
index 40ceb9e2eb..94e976a64c 100644
--- a/src/aphront/response/webpage/AphrontWebpageResponse.php
+++ b/src/aphront/response/webpage/AphrontWebpageResponse.php
@@ -1,35 +1,41 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group aphront
*/
class AphrontWebpageResponse extends AphrontResponse {
private $content;
public function setContent($content) {
$this->content = $content;
return $this;
}
public function buildResponseString() {
return $this->content;
}
+ public function getHeaders() {
+ return array(
+ array('Content-Type', 'text/html; charset=UTF-8'),
+ );
+ }
+
}
diff --git a/src/applications/base/controller/base/__init__.php b/src/applications/base/controller/base/__init__.php
new file mode 100644
index 0000000000..03cfc02dba
--- /dev/null
+++ b/src/applications/base/controller/base/__init__.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'aphront/controller');
+phutil_require_module('phabricator', 'aphront/response/webpage');
+phutil_require_module('phabricator', 'view/page/standard');
+
+
+phutil_require_source('PhabricatorController.php');
diff --git a/src/applications/base/storage/lisk/PhabricatorLiskDAO.php b/src/applications/base/storage/lisk/PhabricatorLiskDAO.php
index 069dca62a3..c27248660e 100644
--- a/src/applications/base/storage/lisk/PhabricatorLiskDAO.php
+++ b/src/applications/base/storage/lisk/PhabricatorLiskDAO.php
@@ -1,49 +1,54 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class PhabricatorLiskDAO extends LiskDAO {
public function establishConnection($mode) {
return new AphrontMySQLDatabaseConnection(
array(
'user' => 'root',
'pass' => '',
'host' => 'localhost',
'database' => 'phabricator_'.$this->getApplicationName(),
));
}
public function getTableName() {
$str = 'phabricator';
$len = strlen($str);
$class = strtolower(get_class($this));
if (!strncmp($class, $str, $len)) {
$class = substr($class, $len);
}
$app = $this->getApplicationName();
if (!strncmp($class, $app, strlen($app))) {
$class = substr($class, strlen($app));
}
- return $app.'_'.$class;
+
+ if (strlen($class)) {
+ return $app.'_'.$class;
+ } else {
+ return $app;
+ }
}
abstract public function getApplicationName();
}
diff --git a/src/applications/directory/storage/item/PhabricatorDirectoryItem.php b/src/applications/directory/storage/item/PhabricatorDirectoryItem.php
index 811bb59a69..6a7ea3c6f8 100644
--- a/src/applications/directory/storage/item/PhabricatorDirectoryItem.php
+++ b/src/applications/directory/storage/item/PhabricatorDirectoryItem.php
@@ -1,36 +1,36 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorDirectoryItem extends PhabricatorDirectoryDAO {
protected $name;
protected $description;
protected $href;
protected $categoryID;
protected $sequence;
- protected $imageGUID;
+ protected $imagePHID;
public function getSortKey() {
return sprintf(
'%08d:%08d:%s',
$this->getCategoryID(),
$this->getSequence(),
$this->getName());
}
}
diff --git a/src/applications/phid/controller/allocate/PhabricatorPHIDAllocateController.php b/src/applications/phid/controller/allocate/PhabricatorPHIDAllocateController.php
new file mode 100644
index 0000000000..53f8af3e14
--- /dev/null
+++ b/src/applications/phid/controller/allocate/PhabricatorPHIDAllocateController.php
@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class PhabricatorPHIDAllocateController
+ extends PhabricatorPHIDController {
+
+ public function processRequest() {
+
+ $request = $this->getRequest();
+ if ($request->isFormPost()) {
+ $type = $request->getStr('type');
+ $phid = PhabricatorPHID::generateNewPHID($type);
+
+ return id(new AphrontRedirectResponse())
+ ->setURI('/phid/?phid='.phutil_escape_uri($phid));
+ }
+
+ $types = id(new PhabricatorPHIDType())->loadAll();
+
+ $options = array();
+ foreach ($types as $type) {
+ $options[$type->getType()] = $type->getType().': '.$type->getName();
+ }
+ asort($options);
+
+ $form = new AphrontFormView();
+ $form->setAction('/phid/new/');
+
+ $form
+ ->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setLabel('PHID Type')
+ ->setName('type')
+ ->setOptions($options))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue('Allocate')
+ ->addCancelButton('/phid/'));
+
+ $panel = new AphrontPanelView();
+ $panel->setHeader('Allocate New PHID');
+
+ $panel->appendChild($form);
+ $panel->setWidth(AphrontPanelView::WIDTH_FORM);
+
+ return $this->buildStandardPageResponse(
+ array($panel),
+ array(
+ 'title' => 'Allocate New PHID',
+ ));
+ }
+
+}
diff --git a/src/applications/phid/controller/allocate/__init__.php b/src/applications/phid/controller/allocate/__init__.php
new file mode 100644
index 0000000000..0605962517
--- /dev/null
+++ b/src/applications/phid/controller/allocate/__init__.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'aphront/response/redirect');
+phutil_require_module('phabricator', 'applications/phid/controller/base');
+phutil_require_module('phabricator', 'applications/phid/storage/phid');
+phutil_require_module('phabricator', 'applications/phid/storage/type');
+phutil_require_module('phabricator', 'view/form/base');
+phutil_require_module('phabricator', 'view/form/control/submit');
+phutil_require_module('phabricator', 'view/layout/panel');
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorPHIDAllocateController.php');
diff --git a/src/applications/phid/controller/base/PhabricatorPHIDController.php b/src/applications/phid/controller/base/PhabricatorPHIDController.php
new file mode 100644
index 0000000000..4c190e9ab7
--- /dev/null
+++ b/src/applications/phid/controller/base/PhabricatorPHIDController.php
@@ -0,0 +1,46 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+abstract class PhabricatorPHIDController extends PhabricatorController {
+
+ public function buildStandardPageResponse($view, array $data) {
+ $page = new PhabricatorStandardPageView();
+
+ $page->setApplicationName('PHID');
+ $page->setBaseURI('/phid/');
+ $page->setTitle(idx($data, 'title'));
+ $page->setTabs(
+ array(
+ 'phids' => array(
+ 'href' => '/phid/',
+ 'name' => 'PHIDs',
+ ),
+ 'types' => array(
+ 'href' => '/phid/type/',
+ 'name' => 'PHID Types',
+ ),
+ ),
+ idx($data, 'tab'));
+ $page->setGlyph('#');
+ $page->appendChild($view);
+
+ $response = new AphrontWebpageResponse();
+ return $response->setContent($page->render());
+ }
+
+}
diff --git a/src/applications/phid/controller/base/__init__.php b/src/applications/phid/controller/base/__init__.php
new file mode 100644
index 0000000000..44f0f1b94d
--- /dev/null
+++ b/src/applications/phid/controller/base/__init__.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'aphront/response/webpage');
+phutil_require_module('phabricator', 'applications/base/controller/base');
+phutil_require_module('phabricator', 'view/page/standard');
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorPHIDController.php');
diff --git a/src/applications/phid/controller/list/PhabricatorPHIDListController.php b/src/applications/phid/controller/list/PhabricatorPHIDListController.php
new file mode 100644
index 0000000000..33803cc4d0
--- /dev/null
+++ b/src/applications/phid/controller/list/PhabricatorPHIDListController.php
@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class PhabricatorPHIDListController
+ extends PhabricatorPHIDController {
+
+ public function processRequest() {
+ $items = id(new PhabricatorPHID())->loadAllWhere(
+ '1 = 1 ORDER BY id DESC limit 100');
+
+ $rows = array();
+ foreach ($items as $item) {
+ $rows[] = array(
+ phutil_escape_html($item->getPHID()),
+ phutil_escape_html($item->getPHIDType()),
+ phutil_escape_html($item->getOwnerPHID()),
+ phutil_escape_html($item->getParentPHID()),
+ );
+ }
+
+ $table = new AphrontTableView($rows);
+ $table->setHeaders(
+ array(
+ 'PHID',
+ 'Type',
+ 'Owner PHID',
+ 'Parent PHID',
+ ));
+
+ $panel = new AphrontPanelView();
+ $panel->appendChild($table);
+ $panel->setHeader('PHIDs');
+ $panel->setCreateButton('Allocate New PHID', '/phid/new/');
+
+ return $this->buildStandardPageResponse($panel, array(
+ 'title' => 'PHIDs',
+ 'tab' => 'phids',
+ ));
+ }
+
+}
diff --git a/src/applications/phid/controller/list/__init__.php b/src/applications/phid/controller/list/__init__.php
new file mode 100644
index 0000000000..913d4fe3f1
--- /dev/null
+++ b/src/applications/phid/controller/list/__init__.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/phid/controller/base');
+phutil_require_module('phabricator', 'applications/phid/storage/phid');
+phutil_require_module('phabricator', 'view/control/table');
+phutil_require_module('phabricator', 'view/layout/panel');
+
+phutil_require_module('phutil', 'markup');
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorPHIDListController.php');
diff --git a/src/applications/phid/controller/typeedit/PhabricatorPHIDTypeEditController.php b/src/applications/phid/controller/typeedit/PhabricatorPHIDTypeEditController.php
new file mode 100644
index 0000000000..a82e63c778
--- /dev/null
+++ b/src/applications/phid/controller/typeedit/PhabricatorPHIDTypeEditController.php
@@ -0,0 +1,132 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class PhabricatorPHIDTypeEditController
+ extends PhabricatorPHIDController {
+
+ private $id;
+
+ public function willProcessRequest(array $data) {
+ $this->id = idx($data, 'id');
+ }
+
+ public function processRequest() {
+
+ if ($this->id) {
+ $type = id(new PhabricatorPHIDType())->load($this->id);
+ if (!$type) {
+ return new Aphront404Response();
+ }
+ } else {
+ $type = new PhabricatorPHIDType();
+ }
+
+ $e_type = true;
+ $e_name = true;
+ $errors = array();
+
+ $request = $this->getRequest();
+ if ($request->isFormPost()) {
+ $type->setName($request->getStr('name'));
+ if (!$type->getID()) {
+ $type->setType($request->getStr('type'));
+ }
+ $type->setDescription($request->getStr('description'));
+
+ if (!strlen($type->getType())) {
+ $errors[] = 'Type code is required.';
+ $e_type = 'Required';
+ }
+
+ if (!strlen($type->getName())) {
+ $errors[] = 'Type name is required.';
+ $e_name = 'Required';
+ }
+
+ if (!$errors) {
+ $type->save();
+ return id(new AphrontRedirectResponse())
+ ->setURI('/phid/type/');
+ }
+ }
+
+ $error_view = null;
+ if ($errors) {
+ $error_view = id(new AphrontErrorView())
+ ->setTitle('Form Errors')
+ ->setErrors($errors);
+ }
+
+ $form = new AphrontFormView();
+ if ($type->getID()) {
+ $form->setAction('/phid/type/edit/'.$type->getID().'/');
+ } else {
+ $form->setAction('/phid/type/edit/');
+ }
+
+ if ($type->getID()) {
+ $type_immutable = true;
+ } else {
+ $type_immutable = false;
+ }
+
+ $form
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setLabel('Type')
+ ->setName('type')
+ ->setValue($type->getType())
+ ->setError($e_type)
+ ->setCaption(
+ 'Four character type identifier. This can not be changed once '.
+ 'it is created.')
+ ->setDisabled($type_immutable))
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setLabel('Name')
+ ->setName('name')
+ ->setValue($type->getName())
+ ->setError($e_name))
+ ->appendChild(
+ id(new AphrontFormTextAreaControl())
+ ->setLabel('Description')
+ ->setName('description')
+ ->setValue($type->getDescription()))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue('Save')
+ ->addCancelButton('/phid/type/'));
+
+ $panel = new AphrontPanelView();
+ if ($type->getID()) {
+ $panel->setHeader('Edit PHID Type');
+ } else {
+ $panel->setHeader('Create New PHID Type');
+ }
+
+ $panel->appendChild($form);
+ $panel->setWidth(AphrontPanelView::WIDTH_FORM);
+
+ return $this->buildStandardPageResponse(
+ array($error_view, $panel),
+ array(
+ 'title' => 'Edit PHID Type',
+ ));
+ }
+
+}
diff --git a/src/applications/phid/controller/typeedit/__init__.php b/src/applications/phid/controller/typeedit/__init__.php
new file mode 100644
index 0000000000..0805e99ff0
--- /dev/null
+++ b/src/applications/phid/controller/typeedit/__init__.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'aphront/response/404');
+phutil_require_module('phabricator', 'aphront/response/redirect');
+phutil_require_module('phabricator', 'applications/phid/controller/base');
+phutil_require_module('phabricator', 'applications/phid/storage/type');
+phutil_require_module('phabricator', 'view/form/base');
+phutil_require_module('phabricator', 'view/form/control/submit');
+phutil_require_module('phabricator', 'view/form/error');
+phutil_require_module('phabricator', 'view/layout/panel');
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorPHIDTypeEditController.php');
diff --git a/src/applications/phid/controller/typelist/PhabricatorPHIDTypeListController.php b/src/applications/phid/controller/typelist/PhabricatorPHIDTypeListController.php
new file mode 100644
index 0000000000..cb961798c0
--- /dev/null
+++ b/src/applications/phid/controller/typelist/PhabricatorPHIDTypeListController.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class PhabricatorPHIDTypeListController
+ extends PhabricatorPHIDController {
+
+ public function processRequest() {
+ $items = id(new PhabricatorPHIDType())->loadAll();
+
+ $rows = array();
+ foreach ($items as $item) {
+ $rows[] = array(
+ $item->getID(),
+ phutil_escape_html($item->getType()),
+ phutil_escape_html($item->getName()),
+ );
+ }
+
+ $table = new AphrontTableView($rows);
+ $table->setHeaders(
+ array(
+ 'ID',
+ 'Type Code',
+ 'Name',
+ ));
+ $table->setColumnClasses(
+ array(
+ null,
+ null,
+ 'wide',
+ ));
+
+ $panel = new AphrontPanelView();
+ $panel->appendChild($table);
+ $panel->setHeader('PHID Types');
+ $panel->setCreateButton('New Type', '/phid/type/edit/');
+
+ return $this->buildStandardPageResponse($panel, array(
+ 'title' => 'PHID Types',
+ 'tab' => 'types',
+ ));
+ }
+
+}
diff --git a/src/applications/phid/controller/typelist/__init__.php b/src/applications/phid/controller/typelist/__init__.php
new file mode 100644
index 0000000000..81a4d0557d
--- /dev/null
+++ b/src/applications/phid/controller/typelist/__init__.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/phid/controller/base');
+phutil_require_module('phabricator', 'applications/phid/storage/type');
+phutil_require_module('phabricator', 'view/control/table');
+phutil_require_module('phabricator', 'view/layout/panel');
+
+phutil_require_module('phutil', 'markup');
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorPHIDTypeListController.php');
diff --git a/src/aphront/response/webpage/AphrontWebpageResponse.php b/src/applications/phid/storage/base/PhabricatorPHIDDAO.php
similarity index 69%
copy from src/aphront/response/webpage/AphrontWebpageResponse.php
copy to src/applications/phid/storage/base/PhabricatorPHIDDAO.php
index 40ceb9e2eb..a133222722 100644
--- a/src/aphront/response/webpage/AphrontWebpageResponse.php
+++ b/src/applications/phid/storage/base/PhabricatorPHIDDAO.php
@@ -1,35 +1,25 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/**
- * @group aphront
- */
-class AphrontWebpageResponse extends AphrontResponse {
-
- private $content;
-
- public function setContent($content) {
- $this->content = $content;
- return $this;
- }
+class PhabricatorPHIDDAO extends PhabricatorLiskDAO {
- public function buildResponseString() {
- return $this->content;
+ public function getApplicationName() {
+ return 'phid';
}
}
diff --git a/src/applications/phid/storage/base/__init__.php b/src/applications/phid/storage/base/__init__.php
new file mode 100644
index 0000000000..5c42a7b15d
--- /dev/null
+++ b/src/applications/phid/storage/base/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/base/storage/lisk');
+
+
+phutil_require_source('PhabricatorPHIDDAO.php');
diff --git a/src/applications/phid/storage/phid/PhabricatorPHID.php b/src/applications/phid/storage/phid/PhabricatorPHID.php
new file mode 100644
index 0000000000..70f018ad4f
--- /dev/null
+++ b/src/applications/phid/storage/phid/PhabricatorPHID.php
@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class PhabricatorPHID extends PhabricatorPHIDDAO {
+
+ protected $phid;
+ protected $phidType;
+ protected $ownerPHID;
+ protected $parentPHID;
+
+ public static function generateNewPHID($type, array $config = array()) {
+ $owner = idx($config, 'owner');
+ $parent = idx($config, 'parent');
+
+ if (!$type) {
+ throw new Exception("Can not generate PHID with no type.");
+ }
+
+ $urandom = @fopen('/dev/urandom', 'r');
+ if (!$urandom) {
+ throw new Exception("Failed to open /dev/urandom!");
+ }
+ $entropy = fread($urandom, 16);
+ if (strlen($entropy) != 16) {
+ throw new Exception("Failed to read from /dev/urandom!");
+ }
+
+ $uniq = sha1($entropy);
+ $phid = 'PHID-'.$type.'-X-'.$uniq;
+
+ $phid_rec = new PhabricatorPHID();
+ $phid_rec->setPHIDType($type);
+ $phid_rec->setOwnerPHID($owner);
+ $phid_rec->setParentPHID($parent);
+ $phid_rec->setPHID($phid);
+ $phid_rec->save();
+
+ return $phid;
+ }
+
+}
diff --git a/src/applications/phid/storage/phid/__init__.php b/src/applications/phid/storage/phid/__init__.php
new file mode 100644
index 0000000000..5ff7852286
--- /dev/null
+++ b/src/applications/phid/storage/phid/__init__.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/phid/storage/base');
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorPHID.php');
diff --git a/src/aphront/response/webpage/AphrontWebpageResponse.php b/src/applications/phid/storage/type/PhabricatorPHIDType.php
similarity index 69%
copy from src/aphront/response/webpage/AphrontWebpageResponse.php
copy to src/applications/phid/storage/type/PhabricatorPHIDType.php
index 40ceb9e2eb..b5c50d512b 100644
--- a/src/aphront/response/webpage/AphrontWebpageResponse.php
+++ b/src/applications/phid/storage/type/PhabricatorPHIDType.php
@@ -1,35 +1,25 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/**
- * @group aphront
- */
-class AphrontWebpageResponse extends AphrontResponse {
-
- private $content;
-
- public function setContent($content) {
- $this->content = $content;
- return $this;
- }
+class PhabricatorPHIDType extends PhabricatorPHIDDAO {
- public function buildResponseString() {
- return $this->content;
- }
+ protected $type;
+ protected $name;
+ protected $description;
}
diff --git a/src/applications/phid/storage/type/__init__.php b/src/applications/phid/storage/type/__init__.php
new file mode 100644
index 0000000000..9753ee3309
--- /dev/null
+++ b/src/applications/phid/storage/type/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/phid/storage/base');
+
+
+phutil_require_source('PhabricatorPHIDType.php');
diff --git a/src/storage/lisk/dao/LiskDAO.php b/src/storage/lisk/dao/LiskDAO.php
index de90777d70..226c89d4fd 100644
--- a/src/storage/lisk/dao/LiskDAO.php
+++ b/src/storage/lisk/dao/LiskDAO.php
@@ -1,1109 +1,1109 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Simple object-authoritative data access object that makes it easy to build
* stuff that you need to save to a database. Basically, it means that the
* amount of boilerplate code (and, particularly, boilerplate SQL) you need
* to write is greatly reduced.
*
* Lisk makes it fairly easy to build something quickly and end up with
* reasonably high-quality code when you're done (e.g., getters and setters,
* objects, transactions, reasonably structured OO code). It's also very thin:
* you can break past it and use MySQL and other lower-level tools when you
* need to in those couple of cases where it doesn't handle your workflow
* gracefully.
*
* However, Lisk won't scale past one database and lacks many of the features
* of modern DAOs like Hibernate: for instance, it does not support joins or
* polymorphic storage.
*
* This means that Lisk is well-suited for tools like Differential, but often a
* poor choice elsewhere. And it is strictly unsuitable for many projects.
*
* Lisk's model is object-authoritative: the PHP class definition is the
* master authority for what the object looks like.
*
* =Building New Objects=
*
* To create new Lisk objects, extend @{class:LiskDAO} and implement
* @{method:establishConnection}. It should return an AphrontDatabaseConnection;
* this will tell Lisk where to save your objects.
*
* class Dog extends LiskDAO {
*
* protected $name;
* protected $breed;
*
* public function establishConnection() {
* return $some_connection_object;
* }
* }
*
* Now, you should create your table:
*
* CREATE TABLE dog (
* id int unsigned not null auto_increment primary key,
* name varchar(32) not null,
* breed varchar(32) not null,
* dateCreated int unsigned not null,
* dateModified int unsigned not null
* );
*
* For each property in your class, add a column with the same name to the
* table (see getConfiguration() for information about changing this mapping).
* Additionally, you should create the three columns `id`, `dateCreated` and
* `dateModified`. Lisk will automatically manage these, using them to implement
* autoincrement IDs and timestamps. If you do not want to use these features,
* see getConfiguration() for information on disabling them. At a bare minimum,
* you must normally have an `id` column which is a primary or unique key with a
* numeric type, although you can change its name by overriding getIDKey() or
* disable it entirely by overriding getIDKey() to return null. Note that many
* methods rely on a single-part primary key and will no longer work (they will
* throw) if you disable it.
*
* As you add more properties to your class in the future, remember to add them
* to the database table as well.
*
* Lisk will now automatically handle these operations: getting and setting
* properties, saving objects, loading individual objects, loading groups
* of objects, updating objects, managing IDs, updating timestamps whenever
* an object is created or modified, and some additional specialized
* operations.
*
* = Creating, Retrieving, Updating, and Deleting =
*
* To create and persist a Lisk object, use save():
*
* $dog = id(new Dog())
* ->setName('Sawyer')
* ->setBreed('Pug')
* ->save();
*
* Note that **Lisk automatically builds getters and setters for all of your
* object's properties** via __call(). You can override these by defining
* versions yourself.
*
* Calling save() will persist the object to the database. After calling
* save(), you can call getID() to retrieve the object's ID.
*
* To load objects by ID, use the load() method:
*
* $dog = id(new Dog())->load($id);
*
* This will load the Dog record with ID $id into $dog, or ##null## if no such
* record exists (load() is an instance method rather than a static method
* because PHP does not support late static binding, at least until PHP 5.3).
*
* To update an object, change its properties and save it:
*
* $dog->setBreed('Lab')->save();
*
* To delete an object, call delete():
*
* $dog->delete();
*
* That's Lisk CRUD in a nutshell.
*
* = Queries =
*
* Often, you want to load a bunch of objects, or execute a more specialized
* query. Use loadAllWhere() or loadOneWhere() to do this:
*
* $pugs = $dog->loadAllWhere('breed = %s', 'Pug');
* $sawyer = $dog->loadOneWhere('name = %s', 'Sawyer');
*
* These methods work like @{function:queryfx}, but only take half of a query
* (the part after the WHERE keyword). Lisk will handle the connection, columns,
* and object construction; you are responsible for the rest of it.
* loadAllWhere() returns a list of objects, while loadOneWhere() returns a
* single object (or null).
*
* @task config Configuring Lisk
* @task load Loading Objects
* @task info Examining Objects
* @task save Writing Objects
* @task hook Hooks and Callbacks
* @task util Utilities
*
* @group storage
*/
abstract class LiskDAO {
const CONFIG_OPTIMISTIC_LOCKS = 'enable-locks';
const CONFIG_IDS = 'id-mechanism';
const CONFIG_TIMESTAMPS = 'timestamps';
- const CONFIG_AUX_GUID = 'auxiliary-guid';
+ const CONFIG_AUX_PHID = 'auxiliary-phid';
const CONFIG_SERIALIZATION = 'col-serialization';
const SERIALIZATION_NONE = 'id';
const SERIALIZATION_JSON = 'json';
const SERIALIZATION_PHP = 'php';
const IDS_AUTOINCREMENT = 'ids-auto';
- const IDS_GUID = 'ids-guid';
+ const IDS_PHID = 'ids-phid';
const IDS_MANUAL = 'ids-manual';
/**
* Build an empty object.
*
* @return obj Empty object.
*/
public function __construct() {
$id_key = $this->getIDKey();
if ($id_key) {
$this->$id_key = null;
}
}
abstract protected function establishConnection($mode);
/* -( Configuring Lisk )--------------------------------------------------- */
/**
* Change Lisk behaviors, like optimistic locks and timestamps. If you want
* to change these behaviors, you should override this method in your child
* class and change the options you're interested in. For example:
*
* public function getConfiguration() {
* return array(
* Lisk_DataAccessObject::CONFIG_EXAMPLE => true,
* ) + parent::getConfiguration();
* }
*
* The available options are:
*
* CONFIG_OPTIMISTIC_LOCKS
* Lisk automatically performs optimistic locking on objects, which protects
* you from read-modify-write concurrency problems. Lock failures are
* detected at write time and arise when two users read an object, then both
* save it. In theory, you should detect these failures and accommodate them
* in some sensible way (for instance, by showing the user differences
* between the original record and the copy they are trying to update, and
* prompting them to merge them). In practice, most Lisk tools are quick
* and dirty and don't get to that level of sophistication, but optimistic
* locks can still protect you from yourself sometimes. If you don't want
* to use optimistic locks, you can disable them. The performance cost of
* doing this locking is very very small (optimistic locks were chosen
* because they're simple and cheap, and highly optimized for the case where
* collisions are rare). By default, this option is OFF.
*
* CONFIG_IDS
* Lisk objects need to have a unique identifying ID. The three mechanisms
* available for generating this ID are IDS_AUTOINCREMENT (default, assumes
- * the ID column is an autoincrement primary key), IDS_GUID (to generate a
- * unique GUID for each object) or IDS_MANUAL (you are taking full
+ * the ID column is an autoincrement primary key), IDS_PHID (to generate a
+ * unique PHID for each object) or IDS_MANUAL (you are taking full
* responsibility for ID management).
*
* CONFIG_TIMESTAMPS
* Lisk can automatically handle keeping track of a `dateCreated' and
* `dateModified' column, which it will update when it creates or modifies
* an object. If you don't want to do this, you may disable this option.
* By default, this option is ON.
*
- * CONFIG_AUX_GUID
+ * CONFIG_AUX_PHID
* This option can be enabled by being set to some truthy value. The meaning
- * of this value is defined by your guid generation mechanism. If this option
- * is enabled, a `guid' property will be populated with a unique GUID when an
+ * of this value is defined by your PHID generation mechanism. If this option
+ * is enabled, a `phid' property will be populated with a unique PHID when an
* object is created (or if it is saved and does not currently have one). You
- * need to override generateGUID() and hook it into your GUID generation
+ * need to override generatePHID() and hook it into your PHID generation
* mechanism for this to work. By default, this option is OFF.
*
* CONFIG_SERIALIZATION
* You can optionally provide a column serialization map that will be applied
* to values when they are written to the database. For example:
*
* self::CONFIG_SERIALIZATION => array(
* 'complex' => self::SERIALIZATION_JSON,
* )
*
* This will cause Lisk to JSON-serialize the 'complex' field before it is
* written, and unserialize it when it is read.
*
*
* @return dictionary Map of configuration options to values.
*
* @task config
*/
protected function getConfiguration() {
return array(
self::CONFIG_OPTIMISTIC_LOCKS => false,
self::CONFIG_IDS => self::IDS_AUTOINCREMENT,
self::CONFIG_TIMESTAMPS => true,
);
}
/**
* Determine the setting of a configuration option for this class of objects.
*
* @param const Option name, one of the CONFIG_* constants.
* @return mixed Option value, if configured (null if unavailable).
*
* @task config
*/
public function getConfigOption($option_name) {
static $options = null;
if (!isset($options)) {
$options = $this->getConfiguration();
}
return idx($options, $option_name);
}
/* -( Loading Objects )---------------------------------------------------- */
/**
* Load an object by ID. You need to invoke this as an instance method, not
* a class method, because PHP doesn't have late static binding (until
* PHP 5.3.0). For example:
*
* $dog = id(new Dog())->load($dog_id);
*
* @param int Numeric ID identifying the object to load.
* @return obj|null Identified object, or null if it does not exist.
*
* @task load
*/
public function load($id) {
if (!($id = (int)$id)) {
throw new Exception("Bogus ID provided to load().");
}
return $this->loadOneWhere(
'%C = %d',
$this->getIDKeyForUse(),
$id);
}
/**
* Loads all of the objects, unconditionally.
*
* @return dict Dictionary of all persisted objects of this type, keyed
* on object ID.
*
* @task load
*/
public function loadAll() {
return $this->loadAllWhere('1 = 1');
}
/**
* Load all objects which match a WHERE clause. You provide everything after
* the 'WHERE'; Lisk handles everything up to it. For example:
*
* $old_dogs = id(new Dog())->loadAllWhere('age > %d', 7);
*
* The pattern and arguments are as per queryfx().
*
* @param string queryfx()-style SQL WHERE clause.
* @param ... Zero or more conversions.
* @return dict Dictionary of matching objects, keyed on ID.
*
* @task load
*/
public function loadAllWhere($pattern/*, $arg, $arg, $arg ... */) {
$args = func_get_args();
$data = call_user_func_array(
array($this, 'loadRawDataWhere'),
$args);
return $this->loadAllFromArray($data);
}
/**
* Load a single object identified by a 'WHERE' clause. You provide
* everything after the 'WHERE', and Lisk builds the first half of the
* query. See loadAllWhere(). This method is similar, but returns a single
* result instead of a list.
*
* @param string queryfx()-style SQL WHERE clause.
* @param ... Zero or more conversions.
* @return obj|null Matching object, or null if no object matches.
*
* @task load
*/
public function loadOneWhere($pattern/*, $arg, $arg, $arg ... */) {
$args = func_get_args();
$data = call_user_func_array(
array($this, 'loadRawDataWhere'),
$args);
if (count($data) > 1) {
throw new AphrontQueryCountException(
"More than 1 result from loadOneWhere()!");
}
$data = reset($data);
if (!$data) {
return null;
}
return $this->loadFromArray($data);
}
protected function loadRawDataWhere($pattern/*, $arg, $arg, $arg ... */) {
$connection = $this->getConnection('r');
$lock_clause = '';
if ($connection->isReadLocking()) {
$lock_clause = 'FOR UPDATE';
} else if ($connection->isWriteLocking()) {
$lock_clause = 'LOCK IN SHARE MODE';
}
$args = func_get_args();
$args = array_slice($args, 1);
$pattern = 'SELECT * FROM %T WHERE '.$pattern.' %Q';
array_unshift($args, $this->getTableName());
array_push($args, $lock_clause);
array_unshift($args, $pattern);
return call_user_func_array(
array($connection, 'queryData'),
$args);
}
/**
* Reload an object from the database, discarding any changes to persistent
* properties. If the object uses optimistic locks and you are in a locking
* mode while transactional, this will effectively synchronize the locks.
* This is pretty heady. It is unlikely you need to use this method.
*
* @return this
*
* @task load
*/
public function reload() {
if (!$this->getID()) {
throw new Exception("Unable to reload object that hasn't been loaded!");
}
$use_locks = $this->getConfigOption(self::CONFIG_OPTIMISTIC_LOCKS);
if (!$use_locks) {
$result = $this->loadOneWhere(
'%C = %d',
$this->getIDKeyForUse(),
$this->getID());
} else {
$result = $this->loadOneWhere(
'%C = %d AND %C = %d',
$this->getIDKeyForUse(),
$this->getID(),
'version',
$this->getVersion());
}
if (!$result) {
throw new AphrontQueryObjectMissingException($use_locks);
}
return $this;
}
/**
* Initialize this object's properties from a dictionary. Generally, you
* load single objects with loadOneWhere(), but sometimes it may be more
* convenient to pull data from elsewhere directly (e.g., a complicated
* join via queryData()) and then load from an array representation.
*
* @param dict Dictionary of properties, which should be equivalent to
* selecting a row from the table or calling getProperties().
* @return this
*
* @task load
*/
public function loadFromArray(array $row) {
$map = array();
foreach ($row as $k => $v) {
$map[$k] = $v;
}
$this->willReadData($map);
foreach ($map as $prop => $value) {
$this->$prop = $value;
}
$this->didReadData();
return $this;
}
/**
* Initialize a list of objects from a list of dictionaries. Usually you
* load lists of objects with loadAllWhere(), but sometimes that isn't
* flexible enough. One case is if you need to do joins to select the right
* objects:
*
* function loadAllWithOwner($owner) {
* $data = $this->queryData(
* 'SELECT d.*
* FROM owner o
* JOIN owner_has_dog od ON o.id = od.ownerID
* JOIN dog d ON od.dogID = d.id
* WHERE o.id = %d',
* $owner);
* return $this->loadAllFromArray($data);
* }
*
* This is a lot messier than loadAllWhere(), but more flexible.
*
* @param list List of property dictionaries.
* @return dict List of constructed objects, keyed on ID.
*
* @task load
*/
public function loadAllFromArray(array $rows) {
$result = array();
$id_key = $this->getIDKey();
foreach ($rows as $row) {
$obj = clone $this;
if ($id_key) {
$result[$row[$id_key]] = $obj->loadFromArray($row);
} else {
$result[] = $obj->loadFromArray($row);
}
}
return $result;
}
/* -( Examining Objects )-------------------------------------------------- */
/**
* Retrieve the unique, numerical ID identifying this object. This value
* will be null if the object hasn't been persisted.
*
* @return int Unique numerical ID.
*
* @task info
*/
public function getID() {
$id_key = $this->getIDKeyForUse();
return $this->$id_key;
}
/**
* Retrieve a list of all object properties. Note that some may be
* "transient", which means they should not be persisted to the database.
* Transient properties can be identified by calling
* getTransientProperties().
*
* @return dict Dictionary of normalized (lowercase) to canonical (original
* case) property names.
*
* @task info
*/
protected function getProperties() {
static $properties = null;
if (!isset($properties)) {
$class = new ReflectionClass(get_class($this));
$properties = array();
foreach ($class->getProperties() as $p) {
$properties[strtolower($p->getName())] = $p->getName();
}
$id_key = $this->getIDKey();
if ($id_key) {
if (!isset($properties[strtolower($id_key)])) {
$properties[strtolower($id_key)] = $id_key;
}
}
if ($this->getConfigOption(self::CONFIG_OPTIMISTIC_LOCKS)) {
$properties['version'] = 'version';
}
if ($this->getConfigOption(self::CONFIG_TIMESTAMPS)) {
$properties['datecreated'] = 'dateCreated';
$properties['datemodified'] = 'dateModified';
}
- if (!$this->isGUIDPrimaryID() &&
- $this->getConfigOption(self::CONFIG_AUX_GUID)) {
- $properties['guid'] = 'guid';
+ if (!$this->isPHIDPrimaryID() &&
+ $this->getConfigOption(self::CONFIG_AUX_PHID)) {
+ $properties['phid'] = 'phid';
}
}
return $properties;
}
/**
* Check if a property exists on this object.
*
* @return string|null Canonical property name, or null if the property
* does not exist.
*
* @task info
*/
protected function checkProperty($property) {
static $properties = null;
if (!isset($properties)) {
$properties = $this->getProperties();
}
return idx($properties, strtolower($property));
}
/**
* Get or build the database connection for this object.
*
* @return LiskDatabaseConnection Lisk connection object.
*
* @task info
*/
protected function getConnection($mode) {
if ($mode != 'r' && $mode != 'w') {
throw new Exception("Unknown mode '{$mode}', should be 'r' or 'w'.");
}
// TODO: We don't do anything with the read/write mode right now, but
// should.
if (!isset($this->__connection)) {
$this->__connection = $this->establishConnection($mode);
}
return $this->__connection;
}
/**
* Convert this object into a property dictionary. This dictionary can be
* restored into an object by using loadFromArray() (unless you're using
* legacy features with CONFIG_CONVERT_CAMELCASE, but in that case you should
* just go ahead and die in a fire).
*
* @return dict Dictionary of object properties.
*
* @task info
*/
protected function getPropertyValues() {
$map = array();
foreach ($this->getProperties() as $p) {
// We may receive a warning here for properties we've implicitly added
// through configuration; squelch it.
$map[$p] = @$this->$p;
}
return $map;
}
/**
* Convert this object into a property dictionary containing only properties
* which will be persisted to the database.
*
* @return dict Dictionary of persistent object properties.
*
* @task info
*/
protected function getPersistentPropertyValues() {
$map = $this->getPropertyValues();
foreach ($this->getTransientProperties() as $p) {
unset($map[$p]);
}
return $map;
}
/* -( Writing Objects )---------------------------------------------------- */
/**
* Persist this object to the database. In most cases, this is the only
* method you need to call to do writes. If the object has not yet been
* inserted this will do an insert; if it has, it will do an update.
*
* @return this
*
* @task save
*/
public function save() {
if ($this->shouldInsertWhenSaved()) {
return $this->insert();
} else {
return $this->update();
}
}
/**
* Save this object, forcing the query to use REPLACE regardless of object
* state.
*
* @return this
*
* @task save
*/
public function replace() {
return $this->insertRecordIntoDatabase('REPLACE');
}
/**
* Save this object, forcing the query to use INSERT regardless of object
* state.
*
* @return this
*
* @task save
*/
public function insert() {
return $this->insertRecordIntoDatabase('INSERT');
}
/**
* Save this object, forcing the query to use UPDATE regardless of object
* state.
*
* @return this
*
* @task save
*/
public function update() {
$use_locks = $this->getConfigOption(self::CONFIG_OPTIMISTIC_LOCKS);
$this->willSaveObject();
$data = $this->getPersistentPropertyValues();
$this->willWriteData($data);
$map = array();
foreach ($data as $k => $v) {
if ($use_locks && $k == 'version') {
continue;
}
$map[$k] = $v;
}
$conn = $this->getConnection('w');
foreach ($map as $key => $value) {
$map[$key] = qsprintf($conn, '%C = %ns', $key, $value);
}
$map = implode(', ', $map);
if ($use_locks) {
$conn->query(
'UPDATE %T SET %Q, version = version + 1 WHERE %C = %d AND %C = %d',
$this->getTableName(),
$map,
$this->getIDKeyForUse(),
$this->getID(),
'version',
$this->getVersion());
} else {
$conn->query(
'UPDATE %T SET %Q WHERE %C = %d',
$this->getTableName(),
$map,
$this->getIDKeyForUse(),
$this->getID());
}
if ($conn->getAffectedRows() !== 1) {
throw new AphrontQueryObjectMissingException($use_locks);
}
if ($use_locks) {
$this->setVersion($this->getVersion() + 1);
}
$this->didWriteData();
return $this;
}
/**
* Delete this object, permanently.
*
* @return this
*
* @task save
*/
public function delete() {
$this->willDelete();
$conn = $this->getConnection('w');
$conn->query(
'DELETE FROM %T WHERE %C = %d',
$this->getTableName(),
$this->getIDKeyForUse(),
$this->getID());
$this->didDelete();
return $this;
}
/**
* Internal implementation of INSERT and REPLACE.
*
* @param const Either "INSERT" or "REPLACE", to force the desired mode.
*
* @task save
*/
protected function insertRecordIntoDatabase($mode) {
$this->willSaveObject();
$data = $this->getPersistentPropertyValues();
$id_mechanism = $this->getConfigOption(self::CONFIG_IDS);
switch ($id_mechanism) {
// If we are using autoincrement IDs, let MySQL assign the value for the
// ID column.
case self::IDS_AUTOINCREMENT:
unset($data[$this->getIDKeyForUse()]);
break;
- case self::IDS_GUID:
+ case self::IDS_PHID:
if (empty($data[$this->getIDKeyForUse()])) {
- $guid = $this->generateGUID();
- $this->setID($guid);
- $data[$this->getIDKeyForUse()] = $guid;
+ $phid = $this->generatePHID();
+ $this->setID($phid);
+ $data[$this->getIDKeyForUse()] = $phid;
}
break;
case self::IDS_MANUAL:
break;
default:
throw new Exception('Unknown CONFIG_IDs mechanism!');
}
if ($this->getConfigOption(self::CONFIG_OPTIMISTIC_LOCKS)) {
$data['version'] = 0;
}
$this->willWriteData($data);
$columns = array_keys($data);
foreach ($columns as $k => $property) {
$columns[$k] = $property;
}
$conn = $this->getConnection('w');
$conn->query(
'%Q INTO %T (%LC) VALUES (%Ls)',
$mode,
$this->getTableName(),
$columns,
$data);
// Update the object with the initial Version value
if ($this->getConfigOption(self::CONFIG_OPTIMISTIC_LOCKS)) {
$this->setVersion(0);
}
// Only use the insert id if this table is using auto-increment ids
if ($id_mechanism === self::IDS_AUTOINCREMENT) {
$this->setID($conn->getInsertID());
}
$this->didWriteData();
return $this;
}
/**
* Method used to determine whether to insert or update when saving.
*
* @return bool true if the record should be inserted
*/
protected function shouldInsertWhenSaved() {
$key_type = $this->getConfigOption(self::CONFIG_IDS);
$use_locks = $this->getConfigOption(self::CONFIG_OPTIMISTIC_LOCKS);
if ($key_type == self::IDS_MANUAL) {
if ($use_locks) {
// If we are manually keyed and the object has a version (which means
// that it has been saved to the DB before), do an update, otherwise
// perform an insert.
if ($this->getID() && $this->getVersion() !== null) {
return false;
} else {
return true;
}
} else {
throw new Exception(
'You are not using optimistic locks, but are using manual IDs. You '.
'must override the shouldInsertWhenSaved() method to properly '.
'detect when to insert a new record.');
}
} else {
return !$this->getID();
}
}
/* -( Hooks and Callbacks )------------------------------------------------ */
/**
* Retrieve the database table name. By default, this is the class name.
*
* @return string Table name for object storage.
*
* @task hook
*/
public function getTableName() {
return get_class($this);
}
/**
- * Helper: Whether this class is configured to use GUIDs as the primary ID.
+ * Helper: Whether this class is configured to use PHIDs as the primary ID.
* @task internal
*/
- private function isGUIDPrimaryID() {
- return ($this->getConfigOption(self::CONFIG_IDS) === self::IDS_GUID);
+ private function isPHIDPrimaryID() {
+ return ($this->getConfigOption(self::CONFIG_IDS) === self::IDS_PHID);
}
/**
* Retrieve the primary key column, "id" by default. If you can not
* reasonably name your ID column "id", override this method.
*
* @return string Name of the ID column.
*
* @task hook
*/
public function getIDKey() {
return
- $this->isGUIDPrimaryID() ?
- 'guid' :
+ $this->isPHIDPrimaryID() ?
+ 'phid' :
'id';
}
protected function getIDKeyForUse() {
$id_key = $this->getIDKey();
if (!$id_key) {
throw new Exception(
"This DAO does not have a single-part primary key. The method you ".
"called requires a single-part primary key.");
}
return $id_key;
}
/**
- * Generate a new GUID, used by CONFIG_AUX_GUID and IDS_GUID.
+ * Generate a new PHID, used by CONFIG_AUX_PHID and IDS_PHID.
*
- * @return guid Unique, newly allocated GUID.
+ * @return phid Unique, newly allocated PHID.
*
* @task hook
*/
- protected function generateGUID() {
+ protected function generatePHID() {
throw new Exception(
- "To use CONFIG_AUX_GUID or IDS_GUID, you need to overload ".
- "generateGUID() to perform GUID generation.");
+ "To use CONFIG_AUX_PHID or IDS_PHID, you need to overload ".
+ "generatePHID() to perform PHID generation.");
}
/**
* If your object has properties which you don't want to be persisted to the
* database, you can override this method and specify them.
*
* @return list List of properties which should NOT be persisted.
* Property names should be in normalized (lowercase) form.
* By default, all properties are persistent.
*
* @task hook
*/
protected function getTransientProperties() {
return array();
}
/**
* Hook to apply serialization or validation to data before it is written to
* the database. See also willReadData().
*
* @task hook
*/
protected function willWriteData(array &$data) {
$this->applyLiskDataSerialization($data, false);
}
/**
* Hook to perform actions after data has been written to the database.
*
* @task hook
*/
protected function didWriteData() {}
/**
* Hook to make internal object state changes prior to INSERT, REPLACE or
* UPDATE.
*
* @task hook
*/
protected function willSaveObject() {
$use_timestamps = $this->getConfigOption(self::CONFIG_TIMESTAMPS);
if ($use_timestamps) {
if (!$this->getDateCreated()) {
$this->setDateCreated(time());
}
$this->setDateModified(time());
}
- if (($this->isGUIDPrimaryID() && !$this->getID())) {
- // If GUIDs are the primary ID, the subclass could have overridden the
+ if (($this->isPHIDPrimaryID() && !$this->getID())) {
+ // If PHIDs are the primary ID, the subclass could have overridden the
// name of the ID column.
- $this->setID($this->generateGUID());
- } else if ($this->getConfigOption(self::CONFIG_AUX_GUID) &&
- !$this->getGUID()) {
- // The subclass could still want GUIDs.
- $this->setGUID($this->generateGUID());
+ $this->setID($this->generatePHID());
+ } else if ($this->getConfigOption(self::CONFIG_AUX_PHID) &&
+ !$this->getPHID()) {
+ // The subclass could still want PHIDs.
+ $this->setPHID($this->generatePHID());
}
}
/**
* Hook to apply serialization or validation to data as it is read from the
* database. See also willWriteData().
*
* @task hook
*/
protected function willReadData(array &$data) {
$this->applyLiskDataSerialization($data, $deserialize = true);
}
/**
* Hook to perform an action on data after it is read from the database.
*
* @task hook
*/
protected function didReadData() {}
/**
* Hook to perform an action before the deletion of an object.
*
* @task hook
*/
protected function willDelete() {}
/**
* Hook to perform an action after the deletion of an object.
*
* @task hook
*/
protected function didDelete() {}
/* -( Utilities )---------------------------------------------------------- */
/**
* Applies configured serialization to a dictionary of values.
*
* @task util
*/
protected function applyLiskDataSerialization(array &$data, $deserialize) {
$serialization = $this->getConfigOption(self::CONFIG_SERIALIZATION);
if ($serialization) {
foreach (array_intersect_key($serialization, $data) as $col => $format) {
switch ($format) {
case self::SERIALIZATION_NONE:
break;
case self::SERIALIZATION_PHP:
if ($deserialize) {
$data[$col] = unserialize($data[$col]);
} else {
$data[$col] = serialize($data[$col]);
}
break;
case self::SERIALIZATION_JSON:
if ($deserialize) {
$data[$col] = json_decode($data[$col], true);
} else {
$data[$col] = json_encode($data[$col]);
}
break;
default:
throw new Exception("Unknown serialization format '{$format}'.");
}
}
}
}
/**
* Black magic. Builds implied get*() and set*() for all properties.
*
* @param string Method name.
* @param list Argument vector.
* @return mixed get*() methods return the property value. set*() methods
* return $this.
* @task util
*/
public function __call($method, $args) {
if (!strncmp($method, 'get', 3)) {
$property = substr($method, 3);
if (!($property = $this->checkProperty($property))) {
throw new Exception("Bad getter call: {$method}");
}
if (count($args) !== 0) {
throw new Exception("Getter call should have zero args: {$method}");
}
return @$this->$property;
}
if (!strncmp($method, 'set', 3)) {
$property = substr($method, 3);
$property = $this->checkProperty($property);
if (!$property) {
throw new Exception("Bad setter call: {$method}");
}
if (count($args) !== 1) {
throw new Exception("Setter should have exactly one arg: {$method}");
}
if ($property == 'ID') {
$property = $this->getIDKeyForUse();
}
$this->$property = $args[0];
return $this;
}
throw new Exception("Unable to resolve method: {$method}.");
}
}
diff --git a/src/view/form/control/base/AphrontFormControl.php b/src/view/form/control/base/AphrontFormControl.php
index 9fa982b131..1f078710f8 100755
--- a/src/view/form/control/base/AphrontFormControl.php
+++ b/src/view/form/control/base/AphrontFormControl.php
@@ -1,127 +1,137 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
abstract class AphrontFormControl extends AphrontView {
private $label;
private $caption;
private $error;
private $name;
private $value;
+ private $disabled;
public function setLabel($label) {
$this->label = $label;
return $this;
}
public function getLabel() {
return $this->label;
}
public function setCaption($caption) {
$this->caption = $caption;
return $this;
}
public function getCaption() {
return $this->caption;
}
public function setError($error) {
$this->error = $error;
return $this;
}
public function getError() {
return $this->error;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
public function setValue($value) {
$this->value = $value;
return $this;
}
public function getValue() {
return $this->value;
}
+ public function setDisabled($disabled) {
+ $this->disabled = $disabled;
+ return $this;
+ }
+
+ public function getDisabled() {
+ return $this->disabled;
+ }
+
abstract protected function renderInput();
abstract protected function getCustomControlClass();
final public function render() {
$custom_class = $this->getCustomControlClass();
if (strlen($this->getLabel())) {
$label =
'<label>'.
phutil_escape_html($this->getLabel()).
':'.
'</label>';
} else {
$label = null;
$custom_class .= ' aphront-form-control-nolabel';
}
$input =
'<div class="aphront-form-input">'.
$this->renderInput().
'</div>';
if (strlen($this->getError())) {
$error = $this->getError();
if ($error === true) {
$error = '*';
} else {
$error = "\xC2\xAB ".$error;
}
$error =
'<div class="aphront-form-error">'.
phutil_escape_html($error).
'</div>';
} else {
$error = null;
}
if (strlen($this->getCaption())) {
$caption =
'<div class="aphront-form-caption">'.
phutil_escape_html($this->getCaption()).
'</div>';
} else {
$caption = null;
}
return
'<div class="aphront-form-control '.$custom_class.'">'.
$error.
$label.
$input.
$caption.
'<div style="clear: both;"></div>'.
'</div>';
}
}
diff --git a/src/view/form/control/select/AphrontFormSelectControl.php b/src/view/form/control/select/AphrontFormSelectControl.php
index a15eda8f49..d2ffaad74d 100755
--- a/src/view/form/control/select/AphrontFormSelectControl.php
+++ b/src/view/form/control/select/AphrontFormSelectControl.php
@@ -1,56 +1,57 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class AphrontFormSelectControl extends AphrontFormControl {
protected function getCustomControlClass() {
return 'aphront-form-control-select';
}
private $options;
public function setOptions(array $options) {
$this->options = $options;
return $this;
}
public function getOptions() {
return $this->options;
}
protected function renderInput() {
$options = array();
foreach ($this->getOptions() as $value => $label) {
$options[] = phutil_render_tag(
'option',
array(
'selected' => ($value == $this->getValue()) ? 'selected' : null,
'value' => $value,
),
phutil_escape_html($label));
}
return phutil_render_tag(
'select',
array(
- 'name' => $this->getName(),
+ 'name' => $this->getName(),
+ 'disabled' => $this->getDisabled() ? 'disabled' : null,
),
implode("\n", $options));
}
}
diff --git a/src/view/form/control/submit/AphrontFormSubmitControl.php b/src/view/form/control/submit/AphrontFormSubmitControl.php
index 16dd7b9a5e..7742a20ae0 100755
--- a/src/view/form/control/submit/AphrontFormSubmitControl.php
+++ b/src/view/form/control/submit/AphrontFormSubmitControl.php
@@ -1,48 +1,49 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class AphrontFormSubmitControl extends AphrontFormControl {
protected $cancelButton;
public function addCancelButton($href, $label = 'Cancel') {
$this->cancelButton = phutil_render_tag(
'a',
array(
'href' => $href,
'class' => 'button grey',
),
phutil_escape_html($label));
return $this;
}
protected function getCustomControlClass() {
return 'aphront-form-control-submit';
}
protected function renderInput() {
return phutil_render_tag(
'button',
array(
- 'name' => '__submit__',
+ 'name' => '__submit__',
+ 'disabled' => $this->getDisabled() ? 'disabled' : null,
),
phutil_escape_html($this->getValue())).
$this->cancelButton;
}
}
diff --git a/src/view/form/control/text/AphrontFormTextControl.php b/src/view/form/control/text/AphrontFormTextControl.php
index f62fd6f463..f8265188af 100755
--- a/src/view/form/control/text/AphrontFormTextControl.php
+++ b/src/view/form/control/text/AphrontFormTextControl.php
@@ -1,35 +1,36 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class AphrontFormTextControl extends AphrontFormControl {
protected function getCustomControlClass() {
return 'aphront-form-control-text';
}
protected function renderInput() {
return phutil_render_tag(
'input',
array(
- 'type' => 'text',
- 'name' => $this->getName(),
- 'value' => $this->getValue(),
+ 'type' => 'text',
+ 'name' => $this->getName(),
+ 'value' => $this->getValue(),
+ 'disabled' => $this->getDisabled() ? 'disabled' : null,
));
}
}
diff --git a/src/view/form/control/textarea/AphrontFormTextAreaControl.php b/src/view/form/control/textarea/AphrontFormTextAreaControl.php
index f52cbeb9d6..2668b825b1 100755
--- a/src/view/form/control/textarea/AphrontFormTextAreaControl.php
+++ b/src/view/form/control/textarea/AphrontFormTextAreaControl.php
@@ -1,34 +1,35 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class AphrontFormTextAreaControl extends AphrontFormControl {
protected function getCustomControlClass() {
return 'aphront-form-control-textarea';
}
protected function renderInput() {
return phutil_render_tag(
'textarea',
array(
- 'name' => $this->getName(),
+ 'name' => $this->getName(),
+ 'disabled' => $this->getDisabled() ? 'disabled' : null,
),
phutil_escape_html($this->getValue()));
}
}
diff --git a/webroot/rsrc/css/base.css b/webroot/rsrc/css/base.css
index f305a544c2..4e49a892d3 100644
--- a/webroot/rsrc/css/base.css
+++ b/webroot/rsrc/css/base.css
@@ -1,534 +1,536 @@
html {
overflow-y: scroll;
}
body, div, dl, dt, dd, ul, ol, li,
h1, h2, h3, h4, h5, h6,
pre, form, fieldset,
p, blockquote, th, td, button {
margin: 0;
padding: 0;
outline: 0;
border: 0;
}
html {
padding-bottom: 16em;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
fieldset, img {
border: 0;
}
address, caption, cite, code, dfn, th, var {
font-style: normal;
font-weight: normal;
}
ol, ul {
list-style: none;
}
caption, th {
text-align: left;
}
td, th {
vertical-align: top;
}
h1, h2, h3, h4, h5, h6 {
font-size: 100%;
font-weight: bold;
}
body {
font: 13px/1.231 'lucida grande', tahoma, verdana, arial, sans-serif;
background: #ACACAC;
direction: ltr;
text-align: left;
unicode-bidi: embed;
*font-size: small;
}
select, input, button, textarea, button {
font: 99% 'lucida grande', tahoma, verdana, arial, clean, sans-serif;
}
table {
font-size: inherit;
font: 100%;
}
h1 {
font-size: 16px;
}
h2 {
font-size: 14px;
}
a {
-moz-outline-style: none;
text-decoration: none;
cursor: pointer;
}
a:visited {
color: #3b5998;
}
a:link {
color: #3b5998;
}
a:hover {
text-decoration: underline;
}
img {
display: block;
}
/******************************************************************************/
/* Buttons */
/******************************************************************************/
button,
a.button,
a.button:visited,
input.inputsubmit {
background: #5e77aa url('/rsrc/image/sprite.png') 0 0 repeat-x;
border: 1px solid #29447e;
border-bottom-color: #1a356e;
color: #fff;
cursor: pointer;
font-weight: bold;
text-align: center;
white-space: nowrap;
display: inline-block;
font-size: 13px;
overflow: visible;
padding: 2px 8px 3px 8px;
line-height: 18px;
vertical-align: baseline;
width: auto;
box-shadow: 0px 1px 0px rgba(0,0,0,.12);
-moz-box-shadow: 0px 1px 0px rgba(0,0,0,.12);
-webkit-box-shadow: 0px 1px 0px rgba(0,0,0,.12);
}
button {
*padding: 2px 4px 1px 8px;
_padding-right: 6px;
}
a.button,
a.button:visited {
*padding: 3px 8px 4px;
}
/* Buttons with images (full size only) */
button.icon,
a.icon,
a.icon:visited {
padding-left: 0;
position: relative;
text-indent: 29px;
}
/* Fix for IE7 within table cells ? */
td button {
*width: 100%;
*padding-right: 8px;
}
button:active,
a.button:active {
background-color: #4f6aa3;
background-position: 0 -100px;
border-bottom-color: #29447e;
}
button.green,
a.green,
a.green:visited {
background-color: #6da952;
background-position: 0 -50px;
border: 1px solid #3b6e22;
border-bottom-color: #2c5a15;
}
button.green:active,
a.green:active {
background-color: #5e9d43;
background-position: 0 -150px;
border-bottom-color: #3b6e22;
}
button.grey,
input.inputaux,
a.grey,
a.grey:visited,
a.button.disabled,
button.disabled {
background-color: #e4e5e5;
background-position: 0 -250px;
border: 1px solid #999;
border-bottom-color: #888;
color: #333;
box-shadow: 0px 1px 0px rgba(0,0,0,.07);
-moz-box-shadow: 0px 1px 0px rgba(0,0,0,.07);
-webkit-box-shadow: 0px 1px 0px rgba(0,0,0,.07);
}
a.disabled,
button.disabled {
filter:alpha(opacity=50);
-moz-opacity:0.5;
-khtml-opacity: 0.5;
opacity: 0.5;
}
button.grey:active,
a.grey:active,
button.grey_active {
background-color: #dddddd;
background-position: 0 -200px;
border-bottom-color: #999;
}
button:active::-moz-focus-inner,
button:focus::-moz-focus-inner {
border-color: #405071;
}
button.green:active::-moz-focus-inner,
button.green:focus::-moz-focus-inner {
border-color: #4c713b;
}
button.grey:active::-moz-focus-inner,
button.grey:focus::-moz-focus-inner {
border-color: #666;
}
a.button:hover {
text-decoration: none;
}
button.small,
a.small,
a.small:visited {
padding: 2px 7px;
height: auto;
font-size: 11px;
line-height: 16px;
}
/******************************************************************************/
/* Aphront */
/******************************************************************************/
.aphront-standard-page {
background: #ffffff;
border-bottom: 1px solid #888888;
font-size: 14px;
-webkit-box-shadow: 0 0 6px #000;
-mox-box-shadow: 0 0 6px #000;
box-shadow: 0 0 6px #000;
}
.aphront-standard-header {
background: #003366;
color: white;
padding: 1em 1em 0.5em 1em;
overflow: hidden;
position: relative;
}
.aphront-standard-header a {
color: white;
}
.aphront-standard-header .aphront-head-tabs {
padding: 0 1em;
font-size: 13px;
font-weight: bold;
}
.aphront-standard-header .aphront-head-tabs a {
border-bottom: 3px solid transparent;
padding: 0.5em 0.75em;
position: relative;
bottom: 2px;
}
.aphront-standard-header .aphront-head-tabs a.aphront-selected-tab {
border-bottom-color: #cccccc;
}
.aphront-standard-header .aphront-head-appname {
padding: 0 1em;
text-transform: uppercase;
}
.aphront-directory-list {
margin: 1em 3% 8em;
}
.aphront-directory-category h1 {
border-bottom: 1px solid #cccccc;
margin-bottom: .5em;
padding-bottom: .1em;
}
.aphront-directory-list h2 {
font-size: 14px;
font-weight: bold;
padding: 0;
margin: 0;
}
.aphront-directory-list p {
color: #444444;
font-size: 12px;
padding: .05em .5em .5em;
}
.aphront-directory-category {
padding: 10px;
width: 300px;
float: left;
}
.aphront-directory-group {
padding: 0 .5em 3em;
}
.aphront-panel-view {
background: #f3f3f3;
border: 1px solid #c0c0c0;
border-width: 1px 0 0;
padding: 1em 2em;
margin: 1em 2em;
}
.aphront-panel-view h1 {
font-size: 14px;
font-weight: bold;
padding: 2px 0 8px;
}
.aphront-panel-view a.create-button {
float: right;
}
.aphront-panel-width-form {
width: 720px;
margin-right: auto;
margin-left: auto;
}
.aphront-table-view {
width: 100%;
border-collapse: collapse;
background: #fdfdfd;
border: 1px solid #003366;
}
.aphront-table-view tr.alt {
background: #efefef;
}
.aphront-table-view th {
font-size: 12px;
font-weight: bold;
padding: 4px 8px;
background: #003366;
color: white;
white-space: nowrap;
}
.aphront-table-view td.header {
padding: 4px 8px;
background: #3b5998;
color: white;
white-space: nowrap;
text-align: right;
}
.aphront-table-view td {
vertical-align: top;
padding: 4px 8px;
font-size: 11px;
white-space: nowrap;
}
.aphront-table-view td.action {
padding-top: 1px;
padding-bottom: 1px;
}
.aphront-table-view td.larger {
font-size: 14px;
}
.aphront-table-view td.pri {
font-weight: bold;
}
.aphront-table-view td.wide {
white-space: normal;
width: 100%;
}
.aphront-table-view td.right {
text-align: right;
}
.aphront-table-view td.mono {
font-family: "Monaco", monospace;
font-size: 10px;
}
.aphront-table-view tr.no-data td {
padding: 1em;
text-align: center;
color: #888888;
font-style: italic;
}
/******************************************************************************/
/* forms */
/******************************************************************************/
.aphront-form-view {
background: #e7e7e7;
border: 1px solid #c4c4c4;
padding: 1em;
}
.aphront-form-view label {
padding-top: 4px;
width: 14%;
float: left;
text-align: right;
font-weight: bold;
font-size: 13px;
color: #666666;
}
.aphront-form-input {
margin-left: 15%;
margin-right: 25%;
width: 60%;
}
.aphront-form-error {
width: 23%;
float: right;
color: #aa0000;
font-weight: bold;
padding-top: 4px;
}
.aphront-form-input input,
.aphront-form-input textarea {
font-size: 12px;
width: 100%;
}
.aphront-form-input textarea {
height: 12em;
}
.aphront-form-control {
padding: 4px;
}
.aphront-form-control-submit button,
.aphront-form-control-submit a.button {
float: right;
margin: 1em 0 0em 2%;
}
.aphront-form-view .aphront-form-caption {
font-size: 11px;
color: #444444;
text-align: right;
clear: both;
margin-right: 25%;
margin-left: 15%;
+ margin-top: 3px;
+ margin-bottom: 6px;
}
.aphront-error-view {
width: 720px;
margin: 1em auto;
border: 1px solid #aa0000;
padding: 1em;
background: #f9b9bc;
}
/******************************************************************************/
/* dialog */
/******************************************************************************/
.aphront-dialog-view {
width: 480px;
padding: 8px;
background: #666;
margin: auto;
}
.aphront-dialog-head {
background: #003366;
border: none;
font-size: 15px;
padding: 5px 12px 6px;
color: #ffffff;
}
.aphront-dialog-body {
background: #ffffff;
padding: 16px 12px;
border: none;
overflow: hidden;
}
.aphront-dialog-tail {
border: none;
background: #ededed;
padding: 0.5em;
text-align: right;
}
.aphront-dialog-tail button,
.aphront-dialog-tail a.button {
float: right;
margin-left: .5em;
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 19:35 (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1128023
Default Alt Text
(92 KB)

Event Timeline