From 27cc0f4261dc0ad23d1092643a381640e22bbb80 Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Sun, 8 Feb 2015 20:03:55 +1300 Subject: [PATCH] Legacy class migration --- .travis.yml | 4 +- code/compat/pages/BlogEntry.php | 72 ++++++++++++++++++++++++ code/compat/pages/BlogHolder.php | 37 +++++++++++++ code/compat/pages/BlogTree.php | 32 +++++++++++ code/compat/tasks/BlogMigrationTask.php | 73 +++++++++++++++++++++++++ code/compat/tasks/MigratableObject.php | 9 +++ code/compat/widgets/ArchiveWidget.php | 28 ++++++++++ code/compat/widgets/TagCloudWidget.php | 29 ++++++++++ code/model/BlogPost.php | 2 +- composer.json | 3 + tests/BlogCategoryTest.php | 4 ++ tests/BlogPostFilterTest.php | 5 ++ tests/BlogTagTest.php | 5 ++ tests/BlogTest.php | 14 +++-- 14 files changed, 311 insertions(+), 6 deletions(-) create mode 100644 code/compat/pages/BlogEntry.php create mode 100644 code/compat/pages/BlogHolder.php create mode 100644 code/compat/pages/BlogTree.php create mode 100644 code/compat/tasks/BlogMigrationTask.php create mode 100644 code/compat/tasks/MigratableObject.php create mode 100644 code/compat/widgets/ArchiveWidget.php create mode 100644 code/compat/widgets/TagCloudWidget.php diff --git a/.travis.yml b/.travis.yml index fd8eba2..1a05426 100755 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ env: - DB=MYSQL CORE_RELEASE=3.1 matrix: + allow_failures: + - php: hhvm-nightly include: - php: 5.6 env: DB=MYSQL @@ -29,4 +31,4 @@ before_script: - cd ~/builds/ss script: - - phpunit silverstripe-blog/tests/ \ No newline at end of file + - vendor/bin/phpunit blog/tests/ diff --git a/code/compat/pages/BlogEntry.php b/code/compat/pages/BlogEntry.php new file mode 100644 index 0000000..1d78954 --- /dev/null +++ b/code/compat/pages/BlogEntry.php @@ -0,0 +1,72 @@ + "SS_Datetime", + "Author" => "Text", + "Tags" => "Text" + ); + + /** + * Safely split and parse all distinct tags assigned to this BlogEntry + * + * @return array Associative array of lowercase tag to native case tags + * @deprecated since version 2.0 + */ + public function TagNames() { + $tags = preg_split("/\s*,\s*/", trim($this->Tags)); + $results = array(); + foreach($tags as $tag) { + if($tag) $results[mb_strtolower($tag)] = $tag; + } + return $results; + } + + public function canCreate($member = null) { + // Deprecated + return false; + } + + public function up() { + // Migrate tags + foreach($this->TagNames() as $tag) { + // Skip if tag already assigned + if($this->Tags()->filter('Title', $tag)->count()) continue; + + // Create tag + $tagObject = new BlogTag(); + $tagObject->Title = $tag; + $tagObject->BlogID = $this->ParentID; + $tagObject->write(); + $this->Tags()->add($tagObject); + } + + // Update fields + $this->PublishDate = $this->Date; + if($this->ClassName === 'BlogEntry') { + $this->ClassName = 'BlogPost'; + $this->write(); + } + } + + public function requireDefaultRecords() { + parent::requireDefaultRecords(); + + if(BlogMigrationTask::config()->run_during_dev_build) { + $task = new BlogMigrationTask(); + $task->up(); + } + } +} + +/** + * @deprecated since version 2.0 + */ +class BlogEntry_Controller extends BlogPost_Controller { +} diff --git a/code/compat/pages/BlogHolder.php b/code/compat/pages/BlogHolder.php new file mode 100644 index 0000000..a3cd43e --- /dev/null +++ b/code/compat/pages/BlogHolder.php @@ -0,0 +1,37 @@ + 'Boolean', + 'ShowFullEntry' => 'Boolean', + ); + + private static $has_one = array( + 'Owner' => 'Member', + ); + + public function canCreate($member = null) { + // Deprecated + return false; + } + + public function up() { + if($this->ClassName === 'BlogHolder') { + $this->ClassName = 'Blog'; + $this->write(); + } + } +} + +/** + * @deprecated since version 2.0 + */ +class BlogHolder_Controller extends BlogTree_Controller { + +} \ No newline at end of file diff --git a/code/compat/pages/BlogTree.php b/code/compat/pages/BlogTree.php new file mode 100644 index 0000000..a93240d --- /dev/null +++ b/code/compat/pages/BlogTree.php @@ -0,0 +1,32 @@ + 'Varchar(255)', + 'LandingPageFreshness' => 'Varchar', + ); + + public function canCreate($member = null) { + // Deprecated + return false; + } + + public function up() { + if($this->ClassName === 'BlogTree') { + $this->ClassName = 'Blog'; + $this->write(); + } + } +} + +/** + * @deprecated since version 2.0 + */ +class BlogTree_Controller extends Blog_Controller { +} \ No newline at end of file diff --git a/code/compat/tasks/BlogMigrationTask.php b/code/compat/tasks/BlogMigrationTask.php new file mode 100644 index 0000000..5165e7f --- /dev/null +++ b/code/compat/tasks/BlogMigrationTask.php @@ -0,0 +1,73 @@ +message('Migrating legacy blog records'); + + foreach($classes as $class) { + // migrate objects in each stage + if(is_subclass_of($class, 'SiteTree')) { + foreach(array('Stage', 'Live') as $stage) { + $oldMode = Versioned::get_reading_mode(); + Versioned::reading_stage($stage); + $this->upClass($class, $stage); + Versioned::set_reading_mode($oldMode); + } + } else { + // Migrate object + $this->upClass($class); + } + } + } + + public function down() { + $this->message('BlogMigrationTask::down() not implemented'); + } + + /** + * Migrate records of a single class + * + * @param type $class + * @param type $stage + */ + protected function upClass($class, $stage = null) { + // Migrate all records + $items = $class::get(); + if($count = $items->count()) { + $stageMessage = " in stage {$stage}"; + $this->message("Migrating {$count} legacy {$class} records{$stageMessage}."); + foreach($items as $item) { + // Cancel if onBeforeUp returns false + $cancel = $item->extend('onBeforeUp'); + if($cancel && min($cancel) === false) continue; + // Up + $item->up(); + // Post extensions + $item->extend('onAfterUp'); + } + } + } +} diff --git a/code/compat/tasks/MigratableObject.php b/code/compat/tasks/MigratableObject.php new file mode 100644 index 0000000..7870c04 --- /dev/null +++ b/code/compat/tasks/MigratableObject.php @@ -0,0 +1,9 @@ + 'Varchar' + ); + + private static $only_available_in = array('none'); + + public function canCreate($member = null) { + // Deprecated + return false; + } + + public function up() { + if($this->DisplayMode) { + $this->Type = ($this->DisplayMode === 'year') ? 'Yearly' : 'Monthly'; + } + $this->ClassName = 'BlogArchiveWidget'; + $this->write(); + } +} diff --git a/code/compat/widgets/TagCloudWidget.php b/code/compat/widgets/TagCloudWidget.php new file mode 100644 index 0000000..cf9d55a --- /dev/null +++ b/code/compat/widgets/TagCloudWidget.php @@ -0,0 +1,29 @@ + "Varchar", + "Limit" => "Int", + "Sortby" => "Varchar" + ); + + private static $only_available_in = array('none'); + + public function canCreate($member = null) { + // Deprecated + return false; + } + + public function up() { + $this->ClassName = 'BlogTagsWidget'; + $this->write(); + } +} \ No newline at end of file diff --git a/code/model/BlogPost.php b/code/model/BlogPost.php index e4b0cb9..4f9422a 100644 --- a/code/model/BlogPost.php +++ b/code/model/BlogPost.php @@ -117,7 +117,7 @@ class BlogPost extends Page { /** * If no publish date is set, set the date to now. **/ - public function onBeforeWrite() { + protected function onBeforeWrite() { parent::onBeforeWrite(); if(!$this->PublishDate) $this->setCastedField("PublishDate", time()); } diff --git a/composer.json b/composer.json index 0ff2225..fa52439 100755 --- a/composer.json +++ b/composer.json @@ -7,6 +7,9 @@ "silverstripe/cms": "^3.1.0", "silverstripe/lumberjack": "~1.1" }, + "require-dev": { + "phpunit/PHPUnit": "~3.7@stable" + }, "license": "BSD-2-Clause", "authors": [ { diff --git a/tests/BlogCategoryTest.php b/tests/BlogCategoryTest.php index bdec7a3..5b618ca 100755 --- a/tests/BlogCategoryTest.php +++ b/tests/BlogCategoryTest.php @@ -9,6 +9,10 @@ class BlogCategoryTest extends FunctionalTest { parent::setUp(); } + public function tearDown() { + SS_Datetime::clear_mock_now(); + parent::tearDown(); + } /** * Tests that any blog posts returned from $category->BlogPosts() many_many are published, diff --git a/tests/BlogPostFilterTest.php b/tests/BlogPostFilterTest.php index 5dfe667..8ef694d 100755 --- a/tests/BlogPostFilterTest.php +++ b/tests/BlogPostFilterTest.php @@ -9,6 +9,11 @@ class BlogPostFilterTest extends SapphireTest { parent::setUp(); } + public function tearDown() { + SS_Datetime::clear_mock_now(); + parent::tearDown(); + } + public function testFilter() { $member = Member::currentUser(); if($member) $member->logout(); diff --git a/tests/BlogTagTest.php b/tests/BlogTagTest.php index ef77dee..6bf44e3 100755 --- a/tests/BlogTagTest.php +++ b/tests/BlogTagTest.php @@ -9,6 +9,11 @@ class BlogTagTest extends FunctionalTest { parent::setUp(); } + public function tearDown() { + SS_Datetime::clear_mock_now(); + parent::tearDown(); + } + /** * Tests that any blog posts returned from $tag->BlogPosts() many_many are published, * both by normal 'save & publish' functionality and by publish date. diff --git a/tests/BlogTest.php b/tests/BlogTest.php index 3300463..b26c037 100755 --- a/tests/BlogTest.php +++ b/tests/BlogTest.php @@ -5,11 +5,17 @@ class BlogTest extends SapphireTest { static $fixture_file = "blog.yml"; public function setUp() { - SS_Datetime::set_mock_now("2013-10-10 20:00:00"); parent::setUp(); - + Config::nest(); + SS_Datetime::set_mock_now("2013-10-10 20:00:00"); $this->objFromFixture("Blog", "firstblog")->publish("Stage", "Live"); } + + public function tearDown() { + SS_Datetime::clear_mock_now(); + Config::unnest(); + parent::tearDown(); + } public function testGetExcludedSiteTreeClassNames() { $member = Member::currentUser(); @@ -19,11 +25,11 @@ class BlogTest extends SapphireTest { Config::inst()->update("BlogPost", "show_in_sitetree", true); $classes = $blog->getExcludedSiteTreeClassNames(); - $this->assertEquals(0, count($classes), "No classes should be hidden."); + $this->assertNotContains('BlogPost', $classes, "BlogPost class should be hidden."); Config::inst()->update("BlogPost", "show_in_sitetree", false); $classes = $blog->getExcludedSiteTreeClassNames(); - $this->assertEquals(1, count($classes), "BlogPost class should be hidden."); + $this->assertContains('BlogPost', $classes, "BlogPost class should be hidden."); }