From 1175784d5d84219d30dc174b86c1dde85450b610 Mon Sep 17 00:00:00 2001 From: Bob Trahan Date: Tue, 10 Apr 2012 14:18:20 -0700 Subject: [PATCH] PhabricatorSlug Summary: This is to be used in Phame so the logic is shared where possible. The change has three main things going on - broke out functionality from PhrictionDocument that isn't Phriction specific. - swept up code base to use new PhabricatorSlug class. - altered the regex ever so slightly per discussion and http://stackoverflow.com/questions/2028022/javascript-how-to-convert-unicode-string-to-ascii I think maybe we should punt on unicode here for quite a bit -- http://www.456bereastreet.com/archive/201006/be_careful_with_non-ascii_characters_in_urls/ -- but we'll be well-positioned to add it with the code here. Test Plan: used phriction to create, edit, view documents. used a tool (codemod) for the codebase sweeping Reviewers: epriestley Reviewed By: epriestley CC: aran Differential Revision: https://secure.phabricator.com/D2195 --- src/__phutil_library_map__.php | 3 + .../ConduitAPI_phriction_history_Method.php | 2 +- .../method/phriction/history/__init__.php | 1 + .../info/ConduitAPI_phriction_info_Method.php | 2 +- .../method/phriction/info/__init__.php | 1 + .../document/PhrictionDocumentController.php | 14 ++-- .../controller/document/__init__.php | 1 + .../edit/PhrictionEditController.php | 4 +- .../phriction/controller/edit/__init__.php | 1 + .../history/PhrictionHistoryController.php | 2 +- .../phriction/controller/history/__init__.php | 1 + .../document/PhrictionDocumentEditor.php | 6 +- .../phriction/editor/document/__init__.php | 1 + .../storage/document/PhrictionDocument.php | 64 +-------------- .../phriction/storage/document/__init__.php | 3 +- .../__tests__/PhrictionDocumentTestCase.php | 52 ------------- .../PhabricatorProjectProfileController.php | 2 +- .../project/controller/profile/__init__.php | 2 +- .../storage/project/PhabricatorProject.php | 2 +- .../project/storage/project/__init__.php | 2 +- .../PhabricatorRemarkupRulePhriction.php | 2 +- .../markuprule/phriction/__init__.php | 1 + .../util/slug/PhabricatorSlug.php | 77 +++++++++++++++++++ src/infrastructure/util/slug/__init__.php | 12 +++ .../__tests__/PhabricatorSlugTestCase.php | 74 ++++++++++++++++++ .../util/slug/__tests__/__init__.php | 13 ++++ 26 files changed, 211 insertions(+), 134 deletions(-) create mode 100644 src/infrastructure/util/slug/PhabricatorSlug.php create mode 100644 src/infrastructure/util/slug/__init__.php create mode 100644 src/infrastructure/util/slug/__tests__/PhabricatorSlugTestCase.php create mode 100644 src/infrastructure/util/slug/__tests__/__init__.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index dde6623a43..5c91811317 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -862,6 +862,8 @@ phutil_register_library_map(array( 'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/option', 'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/poll', 'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/poll', + 'PhabricatorSlug' => 'infrastructure/util/slug', + 'PhabricatorSlugTestCase' => 'infrastructure/util/slug/__tests__', 'PhabricatorSortTableExample' => 'applications/uiexample/examples/sorttable', 'PhabricatorStandardPageView' => 'view/page/standard', 'PhabricatorStatusController' => 'applications/status/base', @@ -1679,6 +1681,7 @@ phutil_register_library_map(array( 'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvotePoll' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController', + 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 'PhabricatorSortTableExample' => 'PhabricatorUIExample', 'PhabricatorStandardPageView' => 'AphrontPageView', 'PhabricatorStatusController' => 'PhabricatorController', diff --git a/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php b/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php index ab2dfd1908..eb26de8a2d 100644 --- a/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php +++ b/src/applications/conduit/method/phriction/history/ConduitAPI_phriction_history_Method.php @@ -46,7 +46,7 @@ final class ConduitAPI_phriction_history_Method $slug = $request->getValue('slug'); $doc = id(new PhrictionDocument())->loadOneWhere( 'slug = %s', - PhrictionDocument::normalizeSlug($slug)); + PhabricatorSlug::normalize($slug)); if (!$doc) { throw new ConduitException('ERR-BAD-DOCUMENT'); } diff --git a/src/applications/conduit/method/phriction/history/__init__.php b/src/applications/conduit/method/phriction/history/__init__.php index 1c09d18552..57cd63042b 100644 --- a/src/applications/conduit/method/phriction/history/__init__.php +++ b/src/applications/conduit/method/phriction/history/__init__.php @@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/conduit/method/phriction/base phutil_require_module('phabricator', 'applications/conduit/protocol/exception'); phutil_require_module('phabricator', 'applications/phriction/storage/content'); phutil_require_module('phabricator', 'applications/phriction/storage/document'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php b/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php index d71fa916a9..c37ff4dc24 100644 --- a/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php +++ b/src/applications/conduit/method/phriction/info/ConduitAPI_phriction_info_Method.php @@ -47,7 +47,7 @@ final class ConduitAPI_phriction_info_Method $doc = id(new PhrictionDocument())->loadOneWhere( 'slug = %s', - PhrictionDocument::normalizeSlug($slug)); + PhabricatorSlug::normalize($slug)); if (!$doc) { throw new ConduitException('ERR-BAD-DOCUMENT'); diff --git a/src/applications/conduit/method/phriction/info/__init__.php b/src/applications/conduit/method/phriction/info/__init__.php index a5d500f2d9..675d9fefdd 100644 --- a/src/applications/conduit/method/phriction/info/__init__.php +++ b/src/applications/conduit/method/phriction/info/__init__.php @@ -10,6 +10,7 @@ phutil_require_module('phabricator', 'applications/conduit/method/phriction/base phutil_require_module('phabricator', 'applications/conduit/protocol/exception'); phutil_require_module('phabricator', 'applications/phriction/storage/content'); phutil_require_module('phabricator', 'applications/phriction/storage/document'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/phriction/controller/document/PhrictionDocumentController.php b/src/applications/phriction/controller/document/PhrictionDocumentController.php index f0fe6e0b6a..3da625f360 100644 --- a/src/applications/phriction/controller/document/PhrictionDocumentController.php +++ b/src/applications/phriction/controller/document/PhrictionDocumentController.php @@ -33,7 +33,7 @@ final class PhrictionDocumentController $request = $this->getRequest(); $user = $request->getUser(); - $slug = PhrictionDocument::normalizeSlug($this->slug); + $slug = PhabricatorSlug::normalize($this->slug); if ($slug != $this->slug) { $uri = PhrictionDocument::getSlugURI($slug); // Canonicalize pages to their one true URI. @@ -208,7 +208,7 @@ final class PhrictionDocumentController private function renderBreadcrumbs($slug) { $ancestor_handles = array(); - $ancestral_slugs = PhrictionDocument::getSlugAncestry($slug); + $ancestral_slugs = PhabricatorSlug::getAncestry($slug); $ancestral_slugs[] = $slug; if ($ancestral_slugs) { $empty_slugs = array_fill_keys($ancestral_slugs, null); @@ -230,7 +230,7 @@ final class PhrictionDocumentController $ancestor_handles[] = $handles[$ancestors[$slug]->getPHID()]; } else { $handle = new PhabricatorObjectHandle(); - $handle->setName(PhrictionDocument::getDefaultSlugTitle($slug)); + $handle->setName(PhabricatorSlug::getDefaultTitle($slug)); $handle->setURI(PhrictionDocument::getSlugURI($slug)); $ancestor_handles[] = $handle; } @@ -264,8 +264,8 @@ final class PhrictionDocumentController $conn = $document_dao->establishConnection('r'); $limit = 50; - $d_child = PhrictionDocument::getSlugDepth($slug) + 1; - $d_grandchild = PhrictionDocument::getSlugDepth($slug) + 2; + $d_child = PhabricatorSlug::getDepth($slug) + 1; + $d_grandchild = PhabricatorSlug::getDepth($slug) + 2; // Select children and grandchildren. $children = queryfx_all( @@ -320,7 +320,7 @@ final class PhrictionDocumentController } else { unset($children[$key]); if ($show_grandchildren) { - $ancestors = PhrictionDocument::getSlugAncestry($child['slug']); + $ancestors = PhabricatorSlug::getAncestry($child['slug']); $grandchildren[end($ancestors)][] = $child; } } @@ -333,7 +333,7 @@ final class PhrictionDocumentController $children[] = array( 'slug' => $slug, 'depth' => $d_child, - 'title' => PhrictionDocument::getDefaultSlugTitle($slug), + 'title' => PhabricatorSlug::getDefaultTitle($slug), 'empty' => true, ); } diff --git a/src/applications/phriction/controller/document/__init__.php b/src/applications/phriction/controller/document/__init__.php index c486bb7f96..11871a5ad9 100644 --- a/src/applications/phriction/controller/document/__init__.php +++ b/src/applications/phriction/controller/document/__init__.php @@ -16,6 +16,7 @@ phutil_require_module('phabricator', 'applications/phriction/storage/content'); phutil_require_module('phabricator', 'applications/phriction/storage/document'); phutil_require_module('phabricator', 'applications/project/storage/project'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phabricator', 'storage/queryfx'); phutil_require_module('phabricator', 'view/form/error'); phutil_require_module('phabricator', 'view/utils'); diff --git a/src/applications/phriction/controller/edit/PhrictionEditController.php b/src/applications/phriction/controller/edit/PhrictionEditController.php index 6a36fd81b7..fafd42bb8c 100644 --- a/src/applications/phriction/controller/edit/PhrictionEditController.php +++ b/src/applications/phriction/controller/edit/PhrictionEditController.php @@ -54,7 +54,7 @@ final class PhrictionEditController } else { $slug = $request->getStr('slug'); - $slug = PhrictionDocument::normalizeSlug($slug); + $slug = PhabricatorSlug::normalize($slug); if (!$slug) { return new Aphront404Response(); } @@ -72,7 +72,7 @@ final class PhrictionEditController $content = new PhrictionContent(); $content->setSlug($slug); - $default_title = PhrictionDocument::getDefaultSlugTitle($slug); + $default_title = PhabricatorSlug::getDefaultTitle($slug); $content->setTitle($default_title); } } diff --git a/src/applications/phriction/controller/edit/__init__.php b/src/applications/phriction/controller/edit/__init__.php index b2d470df71..ba786145d3 100644 --- a/src/applications/phriction/controller/edit/__init__.php +++ b/src/applications/phriction/controller/edit/__init__.php @@ -16,6 +16,7 @@ phutil_require_module('phabricator', 'applications/phriction/storage/document'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phabricator', 'infrastructure/env'); phutil_require_module('phabricator', 'infrastructure/javelin/api'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phabricator', 'view/form/base'); phutil_require_module('phabricator', 'view/form/control/static'); phutil_require_module('phabricator', 'view/form/control/submit'); diff --git a/src/applications/phriction/controller/history/PhrictionHistoryController.php b/src/applications/phriction/controller/history/PhrictionHistoryController.php index 9dabf13ed1..c6af894098 100644 --- a/src/applications/phriction/controller/history/PhrictionHistoryController.php +++ b/src/applications/phriction/controller/history/PhrictionHistoryController.php @@ -35,7 +35,7 @@ final class PhrictionHistoryController $document = id(new PhrictionDocument())->loadOneWhere( 'slug = %s', - PhrictionDocument::normalizeSlug($this->slug)); + PhabricatorSlug::normalize($this->slug)); if (!$document) { return new Aphront404Response(); diff --git a/src/applications/phriction/controller/history/__init__.php b/src/applications/phriction/controller/history/__init__.php index f47ab5a76f..7d8840b1ac 100644 --- a/src/applications/phriction/controller/history/__init__.php +++ b/src/applications/phriction/controller/history/__init__.php @@ -12,6 +12,7 @@ phutil_require_module('phabricator', 'applications/phriction/constants/changetyp phutil_require_module('phabricator', 'applications/phriction/controller/base'); phutil_require_module('phabricator', 'applications/phriction/storage/content'); phutil_require_module('phabricator', 'applications/phriction/storage/document'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phabricator', 'view/control/pager'); phutil_require_module('phabricator', 'view/control/table'); phutil_require_module('phabricator', 'view/layout/crumbs'); diff --git a/src/applications/phriction/editor/document/PhrictionDocumentEditor.php b/src/applications/phriction/editor/document/PhrictionDocumentEditor.php index 17b6d0c0e9..7e0903efa0 100644 --- a/src/applications/phriction/editor/document/PhrictionDocumentEditor.php +++ b/src/applications/phriction/editor/document/PhrictionDocumentEditor.php @@ -1,7 +1,7 @@ loadOneWhere( 'slug = %s', $slug); @@ -51,7 +51,7 @@ final class PhrictionDocumentEditor { } if (!$content) { - $default_title = PhrictionDocument::getDefaultSlugTitle($slug); + $default_title = PhabricatorSlug::getDefaultTitle($slug); $content = new PhrictionContent(); $content->setSlug($slug); $content->setTitle($default_title); diff --git a/src/applications/phriction/editor/document/__init__.php b/src/applications/phriction/editor/document/__init__.php index 037a05d1dd..dd0a1ec878 100644 --- a/src/applications/phriction/editor/document/__init__.php +++ b/src/applications/phriction/editor/document/__init__.php @@ -15,6 +15,7 @@ phutil_require_module('phabricator', 'applications/phriction/storage/content'); phutil_require_module('phabricator', 'applications/phriction/storage/document'); phutil_require_module('phabricator', 'applications/project/storage/project'); phutil_require_module('phabricator', 'applications/search/index/indexer/phriction'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/phriction/storage/document/PhrictionDocument.php b/src/applications/phriction/storage/document/PhrictionDocument.php index 19f45fba9a..f71b5d8543 100644 --- a/src/applications/phriction/storage/document/PhrictionDocument.php +++ b/src/applications/phriction/storage/document/PhrictionDocument.php @@ -61,65 +61,9 @@ final class PhrictionDocument extends PhrictionDAO { } } - public static function normalizeSlug($slug) { - - // TODO: We need to deal with unicode at some point, this is just a very - // basic proof-of-concept implementation. - - $slug = strtolower($slug); - $slug = preg_replace('@/+@', '/', $slug); - $slug = trim($slug, '/'); - $slug = preg_replace('@[^a-z0-9/]+@', '_', $slug); - $slug = trim($slug, '_'); - - return $slug.'/'; - } - - public static function getDefaultSlugTitle($slug) { - $parts = explode('/', trim($slug, '/')); - $default_title = end($parts); - $default_title = str_replace('_', ' ', $default_title); - $default_title = ucwords($default_title); - $default_title = nonempty($default_title, 'Untitled Document'); - return $default_title; - } - - public static function getSlugAncestry($slug) { - $slug = self::normalizeSlug($slug); - - if ($slug == '/') { - return array(); - } - - $ancestors = array( - '/', - ); - - $slug = explode('/', $slug); - array_pop($slug); - array_pop($slug); - - $accumulate = ''; - foreach ($slug as $part) { - $accumulate .= $part.'/'; - $ancestors[] = $accumulate; - } - - return $ancestors; - } - - public static function getSlugDepth($slug) { - $slug = self::normalizeSlug($slug); - if ($slug == '/') { - return 0; - } else { - return substr_count($slug, '/'); - } - } - public function setSlug($slug) { - $this->slug = self::normalizeSlug($slug); - $this->depth = self::getSlugDepth($slug); + $this->slug = PhabricatorSlug::normalize($slug); + $this->depth = PhabricatorSlug::getDepth($slug); return $this; } @@ -136,7 +80,7 @@ final class PhrictionDocument extends PhrictionDAO { } public static function isProjectSlug($slug) { - $slug = self::normalizeSlug($slug); + $slug = PhabricatorSlug::normalize($slug); $prefix = 'projects/'; if ($slug == $prefix) { // The 'projects/' document is not itself a project slug. @@ -150,7 +94,7 @@ final class PhrictionDocument extends PhrictionDAO { throw new Exception("Slug '{$slug}' is not a project slug!"); } - $slug = self::normalizeSlug($slug); + $slug = PhabricatorSlug::normalize($slug); $parts = explode('/', $slug); return $parts[1].'/'; } diff --git a/src/applications/phriction/storage/document/__init__.php b/src/applications/phriction/storage/document/__init__.php index f1fb50f9da..d7a9f2b287 100644 --- a/src/applications/phriction/storage/document/__init__.php +++ b/src/applications/phriction/storage/document/__init__.php @@ -9,8 +9,7 @@ phutil_require_module('phabricator', 'applications/phid/constants'); phutil_require_module('phabricator', 'applications/phid/storage/phid'); phutil_require_module('phabricator', 'applications/phriction/storage/base'); - -phutil_require_module('phutil', 'utils'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_source('PhrictionDocument.php'); diff --git a/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php b/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php index 785c13439f..5bca5f230b 100644 --- a/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php +++ b/src/applications/phriction/storage/document/__tests__/PhrictionDocumentTestCase.php @@ -21,58 +21,6 @@ */ final class PhrictionDocumentTestCase extends PhabricatorTestCase { - public function testSlugNormalization() { - $slugs = array( - '' => '/', - '/' => '/', - '//' => '/', - '&&&' => '/', - '/derp/' => 'derp/', - 'derp' => 'derp/', - 'derp//derp' => 'derp/derp/', - 'DERP//DERP' => 'derp/derp/', - 'a B c' => 'a_b_c/', - ); - - foreach ($slugs as $slug => $normal) { - $this->assertEqual( - $normal, - PhrictionDocument::normalizeSlug($slug), - "Normalization of '{$slug}'"); - } - } - - public function testSlugAncestry() { - $slugs = array( - '/' => array(), - 'pokemon/' => array('/'), - 'pokemon/squirtle/' => array('/', 'pokemon/'), - ); - - foreach ($slugs as $slug => $ancestry) { - $this->assertEqual( - $ancestry, - PhrictionDocument::getSlugAncestry($slug), - "Ancestry of '{$slug}'"); - } - } - - public function testSlugDepth() { - $slugs = array( - '/' => 0, - 'a/' => 1, - 'a/b/' => 2, - 'a////b/' => 2, - ); - - foreach ($slugs as $slug => $depth) { - $this->assertEqual( - $depth, - PhrictionDocument::getSlugDepth($slug), - "Depth of '{$slug}'"); - } - } - public function testProjectSlugs() { $slugs = array( '/' => false, diff --git a/src/applications/project/controller/profile/PhabricatorProjectProfileController.php b/src/applications/project/controller/profile/PhabricatorProjectProfileController.php index 07919ba71d..22c03f7a08 100644 --- a/src/applications/project/controller/profile/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/profile/PhabricatorProjectProfileController.php @@ -60,7 +60,7 @@ final class PhabricatorProjectProfileController $external_arrow = "\xE2\x86\x97"; $tasks_uri = '/maniphest/view/all/?projects='.$project->getPHID(); - $slug = PhrictionDocument::normalizeSlug($project->getName()); + $slug = PhabricatorSlug::normalize($project->getName()); $phriction_uri = '/w/projects/'.$slug; $edit_uri = '/project/edit/'.$project->getID().'/'; diff --git a/src/applications/project/controller/profile/__init__.php b/src/applications/project/controller/profile/__init__.php index 0d4a5a51d9..8447952294 100644 --- a/src/applications/project/controller/profile/__init__.php +++ b/src/applications/project/controller/profile/__init__.php @@ -13,12 +13,12 @@ phutil_require_module('phabricator', 'applications/files/storage/file'); phutil_require_module('phabricator', 'applications/maniphest/query'); phutil_require_module('phabricator', 'applications/maniphest/view/tasksummary'); phutil_require_module('phabricator', 'applications/phid/handle/data'); -phutil_require_module('phabricator', 'applications/phriction/storage/document'); phutil_require_module('phabricator', 'applications/project/controller/base'); phutil_require_module('phabricator', 'applications/project/storage/profile'); phutil_require_module('phabricator', 'applications/project/storage/project'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phabricator', 'infrastructure/javelin/markup'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phabricator', 'view/control/table'); phutil_require_module('phabricator', 'view/layout/profileheader'); phutil_require_module('phabricator', 'view/layout/sidenavfilter'); diff --git a/src/applications/project/storage/project/PhabricatorProject.php b/src/applications/project/storage/project/PhabricatorProject.php index 429558cafc..c279d0a953 100644 --- a/src/applications/project/storage/project/PhabricatorProject.php +++ b/src/applications/project/storage/project/PhabricatorProject.php @@ -82,7 +82,7 @@ final class PhabricatorProject extends PhabricatorProjectDAO { // 'hack_slash' instead of 'hack/slash'). $slug = str_replace('/', ' ', $slug); - $slug = PhrictionDocument::normalizeSlug($slug); + $slug = PhabricatorSlug::normalize($slug); $this->phrictionSlug = $slug; return $this; } diff --git a/src/applications/project/storage/project/__init__.php b/src/applications/project/storage/project/__init__.php index 5f0638b4fb..f567560ad8 100644 --- a/src/applications/project/storage/project/__init__.php +++ b/src/applications/project/storage/project/__init__.php @@ -8,12 +8,12 @@ phutil_require_module('phabricator', 'applications/phid/constants'); phutil_require_module('phabricator', 'applications/phid/storage/phid'); -phutil_require_module('phabricator', 'applications/phriction/storage/document'); phutil_require_module('phabricator', 'applications/project/constants/status'); phutil_require_module('phabricator', 'applications/project/storage/affiliation'); phutil_require_module('phabricator', 'applications/project/storage/base'); phutil_require_module('phabricator', 'applications/project/storage/profile'); phutil_require_module('phabricator', 'applications/project/storage/subproject'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phutil', 'utils'); diff --git a/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php b/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php index b7ae8ba003..718e50554c 100644 --- a/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php +++ b/src/infrastructure/markup/remarkup/markuprule/phriction/PhabricatorRemarkupRulePhriction.php @@ -36,7 +36,7 @@ final class PhabricatorRemarkupRulePhriction $name = explode('/', trim($name, '/')); $name = end($name); - $slug = PhrictionDocument::normalizeSlug($slug); + $slug = PhabricatorSlug::normalize($slug); $uri = PhrictionDocument::getSlugURI($slug); return $this->getEngine()->storeText( diff --git a/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php b/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php index 1c70aaadfc..817f28a35f 100644 --- a/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php +++ b/src/infrastructure/markup/remarkup/markuprule/phriction/__init__.php @@ -7,6 +7,7 @@ phutil_require_module('phabricator', 'applications/phriction/storage/document'); +phutil_require_module('phabricator', 'infrastructure/util/slug'); phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'markup/engine/remarkup/markuprule/base'); diff --git a/src/infrastructure/util/slug/PhabricatorSlug.php b/src/infrastructure/util/slug/PhabricatorSlug.php new file mode 100644 index 0000000000..9ed0938898 --- /dev/null +++ b/src/infrastructure/util/slug/PhabricatorSlug.php @@ -0,0 +1,77 @@ + '/', + '/' => '/', + '//' => '/', + '&&&' => '/', + '/derp/' => 'derp/', + 'derp' => 'derp/', + 'derp//derp' => 'derp/derp/', + 'DERP//DERP' => 'derp/derp/', + 'a B c' => 'a_b_c/', + '-1~2.3abcd' => '1_2_3abcd/', + "T\x95O\x95D\x95O" => 't_o_d_o/', + ); + + foreach ($slugs as $slug => $normal) { + $this->assertEqual( + $normal, + PhabricatorSlug::normalize($slug), + "Normalization of '{$slug}'"); + } + } + + public function testSlugAncestry() { + $slugs = array( + '/' => array(), + 'pokemon/' => array('/'), + 'pokemon/squirtle/' => array('/', 'pokemon/'), + ); + + foreach ($slugs as $slug => $ancestry) { + $this->assertEqual( + $ancestry, + PhabricatorSlug::getAncestry($slug), + "Ancestry of '{$slug}'"); + } + } + + public function testSlugDepth() { + $slugs = array( + '/' => 0, + 'a/' => 1, + 'a/b/' => 2, + 'a////b/' => 2, + ); + + foreach ($slugs as $slug => $depth) { + $this->assertEqual( + $depth, + PhabricatorSlug::getDepth($slug), + "Depth of '{$slug}'"); + } + } +} diff --git a/src/infrastructure/util/slug/__tests__/__init__.php b/src/infrastructure/util/slug/__tests__/__init__.php new file mode 100644 index 0000000000..773469f886 --- /dev/null +++ b/src/infrastructure/util/slug/__tests__/__init__.php @@ -0,0 +1,13 @@ +