Merge pull request #421 from robbieaverill/ss4

SilverStripe 4 compatibility
This commit is contained in:
Daniel Hensby 2017-01-26 12:29:33 +00:00 committed by GitHub
commit d5a8761acf
81 changed files with 2553 additions and 2508 deletions

3
.gitignore vendored
View File

@ -1,5 +1,6 @@
.ssh/* .ssh/*
.bash* .bash*
.profile .profile
vendor/* /vendor/*
.sass-cache/* .sass-cache/*
/node_modules/

View File

@ -6,4 +6,4 @@ checks:
duplication: true duplication: true
filter: filter:
paths: [code/*, tests/*] paths: [src/*, tests/*]

View File

@ -12,8 +12,6 @@ before_install:
env: env:
global: global:
- DB=MYSQL CORE_RELEASE=3.1
# Turn coverage off by default, as it's expensive time wise # Turn coverage off by default, as it's expensive time wise
- COVERAGE=0 - COVERAGE=0
@ -21,33 +19,30 @@ env:
- MODULE_PATH=blog - MODULE_PATH=blog
matrix: matrix:
allow_failures:
- php: hhvm-nightly
include: include:
- php: 5.6 - php: 7.1
env: DB=MYSQL COVERAGE=1 env: DB=MYSQL CORE_RELEASE=4 COVERAGE=1
- php: 5.5
env: DB=MYSQL
- php: 5.6
env: DB=PGSQL
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3.2
- php: 5.6
env: DB=PGSQL CORE_RELEASE=3.2
- php: 5.4
env: DB=SQLITE
- php: 5.3
env: DB=MYSQL
- php: hhvm
env: DB=MYSQL
- php: 5.5
env: DB=MYSQL CORE_RELEASE=4
- php: 5.6
env: DB=MYSQL CORE_RELEASE=4
- php: 5.6
env: DB=PGSQL CORE_RELEASE=4
- php: 5.6
env: DB=SQLITE CORE_RELEASE=4
- php: 7.0
env: DB=MYSQL CORE_RELEASE=4
before_script: before_script:
- phpenv rehash - phpenv rehash
- composer self-update || true - composer self-update || true
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - git clone git://github.com/silverstripe/silverstripe-travis-support.git ~/travis-support
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require "silverstripe/comments" --require "silverstripe/widgets" - php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss --require "silverstripe/comments" --require "silverstripe/widgets"
- cd ~/builds/ss - cd ~/builds/ss
- mv "$MODULE_PATH/phpunit.xml.dist" .
#Execute tests with or without coverage #Execute tests with or without coverage
script: script:
@ -57,9 +52,8 @@ script:
# Execute tests with coverage. Do this for a small # Execute tests with coverage. Do this for a small
- "if [ \"$COVERAGE\" = \"1\" ]; then vendor/bin/phpunit --coverage-clover=coverage.clover $MODULE_PATH/tests/; fi" - "if [ \"$COVERAGE\" = \"1\" ]; then vendor/bin/phpunit --coverage-clover=coverage.clover $MODULE_PATH/tests/; fi"
#Upload coverage even if there is a failure # Upload code coverage when tests pass
after_script: after_success:
- "if [ \"$COVERAGE\" = \"1\" ]; then mv coverage.clover ~/build/$TRAVIS_REPO_SLUG/; fi" - "if [ \"$COVERAGE\" = \"1\" ]; then mv coverage.clover ~/build/$TRAVIS_REPO_SLUG/; fi"
- cd ~/build/$TRAVIS_REPO_SLUG - cd ~/build/$TRAVIS_REPO_SLUG
- wget https://scrutinizer-ci.com/ocular.phar - "if [ \"$COVERAGE\" = \"1\" ]; then travis_retry codecov; fi"
- "if [ \"$COVERAGE\" = \"1\" ]; then travis_retry codecov && travis_retry php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi"

33
.upgrade.yml Normal file
View File

@ -0,0 +1,33 @@
mappings:
GridFieldCategorisationConfig: SilverStripe\Blog\Admin\GridFieldCategorisationConfig
GridFieldFormAction: SilverStripe\Blog\Admin\GridFieldFormAction
GridFieldMergeAction: SilverStripe\Blog\Admin\GridFieldMergeAction
BlogCommentExtension: SilverStripe\Blog\Model\BlogCommentExtension
BlogFilter: SilverStripe\Blog\Model\BlogFilter
BlogFilter_GridField: SilverStripe\Blog\Model\BlogFilter\BlogFilterGridField
BlogMemberExtension: SilverStripe\Blog\Model\BlogMemberExtension
BlogPostFilter: SilverStripe\Blog\Model\BlogPostFilter
BlogPostNotifications: SilverStripe\Blog\Model\BlogPostNotifications
Blog: SilverStripe\Blog\Model\Blog
Blog_Controller: SilverStripe\Blog\Controllers\BlogController
BlogController: SilverStripe\Blog\Controllers\BlogController
BlogCategory: SilverStripe\Blog\Model\BlogCategory
BlogPost: SilverStripe\Blog\Model\BlogPost
BlogPost_Controller: SilverStripe\Blog\Controllers\BlogPostController
BlogPostController: SilverStripe\Blog\Controllers\BlogPostController
BlogTag: SilverStripe\Blog\Model\BlogTag
CategorisationObject: SilverStripe\Blog\Model\CategorisationObject
BlogAdminSidebar: SilverStripe\Blog\Forms\BlogAdminSidebar
GridFieldAddByDBField: SilverStripe\Blog\Forms\GridField\GridFieldAddByDBField
GridFieldBlogPostState: SilverStripe\Blog\Forms\GridField\GridFieldBlogPostState
GridFieldConfig_BlogPost: SilverStripe\Blog\Forms\GridField\GridFieldConfig_BlogPost
BlogArchiveWidget: SilverStripe\Blog\Widgets\BlogArchiveWidget
BlogArchiveWidget_Controller: SilverStripe\Blog\Widgets\BlogArchiveWidgetController
BlogCategoriesWidget: SilverStripe\Blog\Widgets\BlogCategoriesWidget
BlogCategoriesWidget_Controller: SilverStripe\Blog\Widgets\BlogCategoriesWidgetController
BlogRecentPostsWidget: SilverStripe\Blog\Widgets\BlogRecentPostsWidget
BlogRecentPostsWidget_Controller: SilverStripe\Blog\Widgets\BlogRecentPostsWidgetController
BlogTagsCloudWidget: SilverStripe\Blog\Widgets\BlogTagsCloudWidget
BlogTagsCloudWidget_Controller: SilverStripe\Blog\Widgets\BlogTagsCloudWidgetController
BlogTagsWidget: SilverStripe\Blog\Widgets\BlogTagsWidget
BlogTagsWidget_Controller: SilverStripe\Blog\Widgets\BlogTagsWidgetController

View File

@ -10,16 +10,16 @@
## Documentation ## Documentation
[User guide](docs/en/userguide/index.md)
[Developer documentation](docs/en/index.md) * [User guide](docs/en/userguide/index.md)
* [Developer documentation](docs/en/index.md)
## Requirements ## Requirements
``` ```
silverstripe/cms: ^3.1 silverstripe/cms: ^4.0
silverstripe/lumberjack: ^1.1 silverstripe/lumberjack: ^2.0
silverstripe/tagfield: ^1.0 silverstripe/tagfield: ^2.0
``` ```
### Suggested Modules ### Suggested Modules
@ -35,8 +35,12 @@ silverstripe/comments: *
composer require silverstripe/blog composer require silverstripe/blog
``` ```
## Upgrading legacy blog to 2.x ## Upgrading
### Upgrading from 2.x to 3.x
Aside from the framework and CMS upgrades required the blog module should not require anything extra to be completed.
### Upgrading legacy blog to 2.x
If you're upgrading from blog version 1.0 to 2.x you will need to run the `BlogMigrationTask`. Run the task using `dev/tasks/BlogMigrationTask` either via the browser or sake CLI to migrate your legacy blog to the new version data structure. If you're upgrading from blog version 1.0 to 2.x you will need to run the `BlogMigrationTask`. Run the task using `dev/tasks/BlogMigrationTask` either via the browser or sake CLI to migrate your legacy blog to the new version data structure.

View File

@ -5,4 +5,4 @@
* *
* @return string * @return string
**/ **/
define('BLOGGER_DIR', ltrim(Director::makeRelative(realpath(__DIR__)), DIRECTORY_SEPARATOR)); define('BLOGGER_DIR', basename(dirname(__FILE__)));

View File

@ -3,15 +3,15 @@ Name: blogcommentsconfig
Only: Only:
moduleexists: comments moduleexists: comments
--- ---
Comment: SilverStripe\Comments\Model\Comment:
extensions: extensions:
- BlogCommentExtension - SilverStripe\Blog\Model\BlogCommentExtension
--- ---
Name: blogcommentnotifications Name: blogcommentnotifications
Only: Only:
moduleexists: 'comment-notifications' moduleexists: 'comment-notifications'
--- ---
BlogPost: SilverStripe\Blog\Model\BlogPost:
extensions: extensions:
- BlogPostNotifications - SilverStripe\Blog\Model\BlogPostNotifications

View File

@ -1,6 +1,6 @@
--- ---
Name: blogconfig Name: blogconfig
--- ---
Member: SilverStripe\Security\Member:
extensions: extensions:
- BlogMemberExtension - SilverStripe\Blog\Model\BlogMemberExtension

9
_config/legacy.yml Normal file
View File

@ -0,0 +1,9 @@
---
Name: bloglegacy
---
SilverStripe\ORM\DatabaseAdmin:
classname_value_remapping:
Blog: SilverStripe\Blog\Model\Blog
BlogCategory: SilverStripe\Blog\Model\BlogCategory
BlogPost: SilverStripe\Blog\Model\BlogPost
BlogTag: SilverStripe\Blog\Model\BlogTag

View File

@ -1,57 +0,0 @@
<?php
class GridFieldCategorisationConfig extends GridFieldConfig_RecordEditor
{
/**
* @param int $itemsPerPage
* @param array|SS_List $mergeRecords
* @param string $parentType
* @param string $parentMethod
* @param string $childMethod
*/
public function __construct($itemsPerPage = 15, $mergeRecords, $parentType, $parentMethod, $childMethod)
{
parent::__construct($itemsPerPage);
$this->removeComponentsByType('GridFieldAddNewButton');
$this->addComponent(
new GridFieldAddByDBField('buttons-before-left')
);
$this->addComponent(
new GridFieldMergeAction($mergeRecords, $parentType, $parentMethod, $childMethod)
);
/**
* @var GridFieldDataColumns $columns
*/
$columns = $this->getComponentByType('GridFieldDataColumns');
$columns->setFieldFormatting(array(
'BlogPostsCount' => function ($value, CategorisationObject $item) {
return $item->BlogPosts()->Count();
}
));
$this->changeColumnOrder();
}
/**
* Reorders GridField columns so that Actions is last.
*/
protected function changeColumnOrder()
{
/**
* @var GridFieldDataColumns $columns
*/
$columns = $this->getComponentByType('GridFieldDataColumns');
$columns->setDisplayFields(array(
'Title' => 'Title',
'BlogPostsCount' => 'Posts',
'MergeAction' => 'MergeAction',
'Actions' => 'Actions',
));
}
}

View File

@ -1,112 +0,0 @@
<?php
/**
* @deprecated since version 2.0
*
* @property int $ParentID
* @property string $Date
* @property string $PublishDate
* @property string $Tags
*/
class BlogEntry extends BlogPost implements MigratableObject
{
/**
* @var string
*/
private static $hide_ancestor = 'BlogEntry';
/**
* @var array
*/
private static $db = array(
'Date' => 'SS_Datetime',
'Author' => 'Text',
'Tags' => 'Text',
);
/**
* {@inheritdoc}
*/
public function canCreate($member = null)
{
return false;
}
/**
* {@inheritdoc}
*/
public function up()
{
//Migrate comma separated tags into BlogTag objects.
foreach ($this->TagNames() as $tag) {
$existingTag = BlogTag::get()->filter(array('Title' => $tag, 'BlogID' => $this->ParentID));
if ($existingTag->count()) {
//if tag already exists we will simply add it to this post.
$tagObject = $existingTag->First();
} else {
//if the tag is now we create it and add it to this post.
$tagObject = new BlogTag();
$tagObject->Title = $tag;
$tagObject->BlogID = $this->ParentID;
$tagObject->write();
}
if ($tagObject) {
$this->Tags()->add($tagObject);
}
}
//Store if the original entity was published or not (draft)
$published = $this->IsPublished();
// If a user has subclassed BlogEntry, it should not be turned into a BlogPost.
if ($this->ClassName === 'BlogEntry') {
$this->ClassName = 'BlogPost';
$this->RecordClassName = 'BlogPost';
}
//Migrate these key data attributes
$this->PublishDate = $this->Date;
$this->AuthorNames = $this->Author;
$this->InheritSideBar = true;
//Write and additionally publish the item if it was published before.
$this->write();
if ($published) {
$this->publish('Stage', 'Live');
$message = "PUBLISHED: ";
} else {
$message = "DRAFT: ";
}
return $message . $this->Title;
}
/**
* Safely split and parse all distinct tags assigned to this BlogEntry.
*
* @deprecated since version 2.0
*
* @return array
*/
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;
}
}
/**
* @deprecated since version 2.0
*/
class BlogEntry_Controller extends BlogPost_Controller
{
}

View File

@ -1,77 +0,0 @@
<?php
/**
* @deprecated since version 2.0
*/
class BlogHolder extends BlogTree implements MigratableObject
{
/**
* @var string
*/
private static $hide_ancestor = 'BlogHolder';
/**
* @var array
*/
private static $db = array(
'AllowCustomAuthors' => 'Boolean',
'ShowFullEntry' => 'Boolean',
);
/**
* @var array
*/
private static $has_one = array(
'Owner' => 'Member',
);
/**
* {@inheritdoc}
*/
public function canCreate($member = null)
{
return false;
}
//Overload these to stop the Uncaught Exception: Object->__call(): the method 'parent' does not exist on 'BlogHolder' error.
public function validURLSegment()
{
return true;
}
public function syncLinkTracking()
{
return null;
}
/**
* {@inheritdoc}
*/
public function up()
{
$published = $this->IsPublished();
if ($this->ClassName === 'BlogHolder') {
$this->ClassName = 'Blog';
$this->RecordClassName = 'Blog';
$this->PostsPerPage = 10;
$this->write();
}
if ($published) {
$this->publish('Stage', 'Live');
$message = "PUBLISHED: ";
} else {
$message = "DRAFT: ";
}
return $message . $this->Title;
}
}
/**
* @deprecated since version 2.0
*/
class BlogHolder_Controller extends BlogTree_Controller
{
}

View File

@ -1,56 +0,0 @@
<?php
/**
* @deprecated since version 2.0
*/
class BlogTree extends Page implements MigratableObject
{
/**
* @var string
*/
private static $hide_ancestor = 'BlogTree';
/**
* @var array
*/
private static $db = array(
'Name' => 'Varchar(255)',
'LandingPageFreshness' => 'Varchar',
);
/**
* {@inheritdoc}
*/
public function canCreate($member = null)
{
return false;
}
/**
* {@inheritdoc}
*/
public function up()
{
$published = $this->IsPublished();
if ($this->ClassName === 'BlogTree') {
$this->ClassName = 'Page';
$this->RecordClassName = 'Page';
$this->write();
}
if ($published) {
$this->publish('Stage', 'Live');
$message = "PUBLISHED: ";
} else {
$message = "DRAFT: ";
}
return $message . $this->Title;
}
}
/**
* @deprecated since version 2.0
*/
class BlogTree_Controller extends Page_Controller
{
}

View File

@ -1,92 +0,0 @@
<?php
class BlogMigrationTask extends MigrationTask
{
/**
* Should this task be invoked automatically via dev/build?
*
* @config
*
* @var bool
*/
private static $run_during_dev_build = true;
/**
* {@inheritdoc}
*/
public function up()
{
$classes = ClassInfo::implementorsOf('MigratableObject');
$this->message('Migrating legacy blog records');
foreach ($classes as $class) {
$this->upClass($class);
}
}
/**
* @param string $text
*/
protected function message($text)
{
if (Controller::curr() instanceof DatabaseAdmin) {
DB::alteration_message($text, 'obsolete');
} else {
echo $text . "<br/>";
}
}
/**
* Migrate records of a single class
*
* @param string $class
* @param null|string $stage
*/
protected function upClass($class)
{
if (!class_exists($class)) {
return;
}
if (is_subclass_of($class, 'SiteTree')) {
$items = SiteTree::get()->filter('ClassName', $class);
} else {
$items = $class::get();
}
if ($count = $items->count()) {
$this->message(
sprintf(
'Migrating %s legacy %s records.',
$count,
$class
)
);
foreach ($items as $item) {
$cancel = $item->extend('onBeforeUp');
if ($cancel && min($cancel) === false) {
continue;
}
/**
* @var MigratableObject $item
*/
$result = $item->up();
$this->message($result);
$item->extend('onAfterUp');
}
}
}
/**
* {@inheritdoc}
*/
public function down()
{
$this->message('BlogMigrationTask::down() not implemented');
}
}

View File

@ -1,9 +0,0 @@
<?php
interface MigratableObject
{
/**
* Migrate the object up to the current version.
*/
public function up();
}

View File

@ -1,54 +0,0 @@
<?php
if (!class_exists('Widget')) {
return;
}
/**
* @deprecated since version 2.0
*
* @property string $DisplayMode
* @property string $ArchiveType
*/
class ArchiveWidget extends BlogArchiveWidget implements MigratableObject
{
/**
* @var array
*/
private static $db = array(
'DisplayMode' => 'Varchar',
);
/**
* @var array
*/
private static $only_available_in = array(
'none',
);
/**
* {@inheritdoc}
*/
public function canCreate($member = null)
{
return false;
}
/**
* {@inheritdoc}
*/
public function up()
{
if ($this->DisplayMode) {
$this->ArchiveType = 'Monthly';
if ($this->DisplayMode === 'year') {
$this->ArchiveType = 'Yearly';
}
}
$this->ClassName = 'BlogArchiveWidget';
$this->write();
return "Migrated " . $this->ArchiveType . " archive widget";
}
}

View File

@ -1,47 +0,0 @@
<?php
if (!class_exists('Widget')) {
return;
}
/**
* A list of tags associated with blog posts.
*
* @package blog
*/
class TagCloudWidget extends BlogTagsWidget implements MigratableObject
{
/**
* @var array
*/
private static $db = array(
'Title' => 'Varchar',
'Limit' => 'Int',
'Sortby' => 'Varchar',
);
/**
* @var array
*/
private static $only_available_in = array(
'none',
);
/**
* {@inheritdoc}
*/
public function canCreate($member = null)
{
return false;
}
/**
* {@inheritdoc}
*/
public function up()
{
$this->ClassName = 'BlogTagsWidget';
$this->write();
return "Migrated " . $this->Title . " widget";
}
}

View File

@ -1,45 +0,0 @@
<?php
/**
* This is responsible for filtering only published posts to users who do not have permission to
* view non-published posts.
*
* @package silverstripe
* @subpackage blog
*/
class BlogPostFilter extends DataExtension
{
/**
* Augment queries so that we don't fetch unpublished articles.
*
* @param SQLQuery $query
*/
public function augmentSQL(SQLQuery &$query)
{
$stage = Versioned::current_stage();
if (Controller::curr() instanceof LeftAndMain) {
return;
}
if ($stage == 'Live' || !Permission::check('VIEW_DRAFT_CONTENT')) {
$query->addWhere(sprintf('"PublishDate" < \'%s\'', Convert::raw2sql(SS_Datetime::now())));
}
}
/**
* This is a fix so that when we try to fetch subclasses of BlogPost, lazy loading includes the
* BlogPost table in its query. Leaving this table out means the default sort order column
* PublishDate causes an error.
*
* @see https://github.com/silverstripe/silverstripe-framework/issues/1682
*
* @param SQLQuery $query
* @param mixed $dataQuery
* @param mixed $parent
*/
public function augmentLoadLazyFields(SQLQuery &$query, &$dataQuery, $parent)
{
$dataQuery->innerJoin('BlogPost', '"SiteTree"."ID" = "BlogPost"."ID"');
}
}

View File

@ -1,78 +0,0 @@
<?php
/**
* Adds URLSegment functionality to Tags & Categories.
*
* @package silverstripe
* @subpackage blog
*/
class URLSegmentExtension extends DataExtension
{
/**
* @var array
*/
private static $db = array(
'URLSegment' => 'Varchar(255)',
);
/**
* {@inheritdoc}
*/
public function onBeforeWrite()
{
if ($this->owner->BlogID) {
$this->owner->generateURLSegment();
}
}
/**
* Generates a unique URLSegment from the title.
*
* @param int $increment
*
* @return string
*/
public function generateURLSegment($increment = null)
{
$filter = new URLSegmentFilter();
// Setting this to on. Because of the UI flow, it would be quite a lot of work
// to support turning this off. (ie. the add by title flow would not work).
// If this becomes a problem we can approach it then.
// @see https://github.com/silverstripe/silverstripe-blog/issues/376
$filter->setAllowMultibyte(true);
$this->owner->URLSegment = $filter->filter($this->owner->Title);
if (is_int($increment)) {
$this->owner->URLSegment .= '-' . $increment;
}
// Postgres use '' instead of 0 as an emtpy blog ID
// Without this all the tests fail
if (!$this->owner->BlogID) {
$this->owner->BlogID = 0;
}
$duplicate = DataList::create($this->owner->ClassName)->filter(array(
'URLSegment' => $this->owner->URLSegment,
'BlogID' => $this->owner->BlogID,
));
if ($this->owner->ID) {
$duplicate = $duplicate->exclude('ID', $this->owner->ID);
}
if ($duplicate->count() > 0) {
if (is_int($increment)) {
$increment += 1;
} else {
$increment = 0;
}
$this->owner->generateURLSegment((int) $increment);
}
return $this->owner->URLSegment;
}
}

View File

@ -1,188 +0,0 @@
<?php
/**
* A blog category for generalising blog posts.
*
* @package silverstripe
* @subpackage blog
*
* @method Blog Blog()
*
* @property string $URLSegment
* @property int $BlogID
*/
class BlogCategory extends DataObject implements CategorisationObject
{
/**
* Use an exception code so that attempted writes can continue on
* duplicate errors.
*
* @const string
* This must be a string because ValidationException has decided we can't use int
*/
const DUPLICATE_EXCEPTION = "DUPLICATE";
/**
* @var array
*/
private static $db = array(
'Title' => 'Varchar(255)',
);
/**
* @var array
*/
private static $has_one = array(
'Blog' => 'Blog',
);
/**
* @var array
*/
private static $belongs_many_many = array(
'BlogPosts' => 'BlogPost',
);
/**
* @var array
*/
private static $extensions = array(
'URLSegmentExtension',
);
/**
* @return DataList
*/
public function BlogPosts()
{
$blogPosts = parent::BlogPosts();
$this->extend("updateGetBlogPosts", $blogPosts);
return $blogPosts;
}
/**
* {@inheritdoc}
*/
public function getCMSFields()
{
$fields = new FieldList(
TextField::create('Title', _t('BlogCategory.Title', 'Title'))
);
$this->extend('updateCMSFields', $fields);
return $fields;
}
/**
* {@inheritdoc}
*/
protected function validate()
{
$validation = parent::validate();
if($validation->valid()) {
// Check for duplicate categories
$blog = $this->Blog();
if($blog && $blog->exists()) {
$existing = $blog->Categories()->filter('Title', $this->Title);
if($this->ID) {
$existing = $existing->exclude('ID', $this->ID);
}
if($existing->count() > 0) {
$validation->error(_t(
'BlogCategory.Duplicate',
'A blog category already exists with that name'
), BlogCategory::DUPLICATE_EXCEPTION);
}
}
}
return $validation;
}
/**
* Returns a relative link to this category.
*
* @return string
*/
public function getLink()
{
return Controller::join_links($this->Blog()->Link(), 'category', $this->URLSegment);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canView($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canView($member);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canCreate($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
$permission = Blog::config()->grant_user_permission;
return Permission::checkMember($member, $permission);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canDelete($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canEdit($member);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canEdit($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canEdit($member);
}
}

View File

@ -1,189 +0,0 @@
<?php
/**
* A blog tag for keyword descriptions of a blog post.
*
* @package silverstripe
* @subpackage blog
*
* @method Blog Blog()
*
* @property string $Title
* @property string $URLSegment
* @property int $BlogID
*/
class BlogTag extends DataObject implements CategorisationObject
{
/**
* Use an exception code so that attempted writes can continue on
* duplicate errors.
*
* @const string
* This must be a string because ValidationException has decided we can't use int
*/
const DUPLICATE_EXCEPTION = "DUPLICATE";
/**
* @var array
*/
private static $db = array(
'Title' => 'Varchar(255)',
);
/**
* @var array
*/
private static $has_one = array(
'Blog' => 'Blog',
);
/**
* @var array
*/
private static $belongs_many_many = array(
'BlogPosts' => 'BlogPost',
);
/**
* @var array
*/
private static $extensions = array(
'URLSegmentExtension',
);
/**
* @return DataList
*/
public function BlogPosts()
{
$blogPosts = parent::BlogPosts();
$this->extend("updateGetBlogPosts", $blogPosts);
return $blogPosts;
}
/**
* {@inheritdoc}
*/
public function getCMSFields()
{
$fields = new FieldList(
TextField::create('Title', _t('BlogTag.Title', 'Title'))
);
$this->extend('updateCMSFields', $fields);
return $fields;
}
/**
* {@inheritdoc}
*/
protected function validate()
{
$validation = parent::validate();
if($validation->valid()) {
// Check for duplicate tags
$blog = $this->Blog();
if($blog && $blog->exists()) {
$existing = $blog->Tags()->filter('Title', $this->Title);
if($this->ID) {
$existing = $existing->exclude('ID', $this->ID);
}
if($existing->count() > 0) {
$validation->error(_t(
'BlogTag.Duplicate',
'A blog tags already exists with that name'
), BlogTag::DUPLICATE_EXCEPTION);
}
}
}
return $validation;
}
/**
* Returns a relative URL for the tag link.
*
* @return string
*/
public function getLink()
{
return Controller::join_links($this->Blog()->Link(), 'tag', $this->URLSegment);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canView($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canView($member);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canCreate($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
$permission = Blog::config()->grant_user_permission;
return Permission::checkMember($member, $permission);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canDelete($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canEdit($member);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canEdit($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canEdit($member);
}
}

View File

@ -1,100 +0,0 @@
<?php
if (!class_exists("Widget")) {
return;
}
/**
* @method Blog Blog()
*/
class BlogCategoriesWidget extends Widget
{
/**
* @var string
*/
private static $title = 'Categories';
/**
* @var string
*/
private static $cmsTitle = 'Blog Categories';
/**
* @var string
*/
private static $description = 'Displays a list of blog categories.';
/**
* @var array
*/
private static $db = array(
'Limit' => 'Int',
'Order' => 'Varchar',
'Direction' => 'Varchar',
);
/**
* @var array
*/
private static $has_one = array(
'Blog' => 'Blog',
);
/**
* {@inheritdoc}
*/
public function getCMSFields()
{
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields[] = DropdownField::create(
'BlogID', _t('BlogCategoriesWidget.Blog', 'Blog'), Blog::get()->map()
);
$fields[] = NumericField::create(
'Limit', _t('BlogCategoriesWidget.Limit.Label', 'Limit'), 0
)
->setDescription(_t('BlogCategoriesWidget.Limit.Description', 'Limit the number of categories shown by this widget (set to 0 to show all categories).'))
->setMaxLength(3);
$fields[] = DropdownField::create(
'Order', _t('BlogCategoriesWidget.Sort.Label', 'Sort'), array('Title' => 'Title', 'Created' => 'Created', 'LastEdited' => 'Updated')
)
->setDescription(_t('BlogCategoriesWidget.Sort.Description', 'Change the order of categories shown by this widget.'));
$fields[] = DropdownField::create(
'Direction', _t('BlogCategoriesWidget.Direction.Label', 'Direction'), array('ASC' => 'Ascending', 'DESC' => 'Descending')
)
->setDescription(_t('BlogCategoriesWidget.Direction.Description', 'Change the direction of ordering of categories shown by this widget.'));
});
return parent::getCMSFields();
}
/**
* @return DataList
*/
public function getCategories()
{
$blog = $this->Blog();
if (!$blog) {
return array();
}
$query = $blog->Categories();
if ($this->Limit) {
$query = $query->limit(Convert::raw2sql($this->Limit));
}
if ($this->Order && $this->Direction) {
$query = $query->sort(Convert::raw2sql($this->Order), Convert::raw2sql($this->Direction));
}
return $query;
}
}
class BlogCategoriesWidget_Controller extends Widget_Controller
{
}

View File

@ -1,39 +1,45 @@
{ {
"name": "silverstripe/blog", "name": "silverstripe/blog",
"description": "A fresh take on blogging in Silverstripe set out to tackle the issue of a cluttered Site Tree.", "description": "A fresh take on blogging in Silverstripe set out to tackle the issue of a cluttered Site Tree.",
"keywords": [ "keywords": [
"silverstripe", "silverstripe",
"blog", "blog",
"news" "news"
], ],
"type": "silverstripe-module", "type": "silverstripe-module",
"require": { "require": {
"silverstripe/cms": "^3.1.0", "silverstripe/cms": "^4.0",
"silverstripe/lumberjack": "~1.1", "silverstripe/lumberjack": "^2.0",
"silverstripe/tagfield": "^1.0" "silverstripe/tagfield": "^2.0"
}, },
"require-dev": { "require-dev": {
"phpunit/PHPUnit": "~3.7@stable" "phpunit/PHPUnit": "~4.8"
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-master": "3.x-dev" "dev-master": "3.0.x-dev"
} }
}, },
"license": "BSD-2-Clause", "autoload": {
"authors": [ "psr-4": {
{ "SilverStripe\\Blog\\": "src/",
"name": "Michael Strong", "SilverStripe\\Blog\\Tests\\": "tests/"
"email": "github@michaelstrong.co.uk" }
} },
], "license": "BSD-2-Clause",
"suggest": { "authors": [
"silverstripe/widgets": "Some widgets come with the blog which are compatible with the widgets module.", {
"silverstripe/comments": "This module adds comments to your blog." "name": "Michael Strong",
}, "email": "github@michaelstrong.co.uk"
"replace": { }
"micmania1/silverstripe-blog": "*" ],
}, "suggest": {
"minimum-stability": "dev", "silverstripe/widgets": "Some widgets come with the blog which are compatible with the widgets module.",
"prefer-stable": true "silverstripe/comments": "This module adds comments to your blog."
},
"replace": {
"micmania1/silverstripe-blog": "*"
},
"minimum-stability": "dev",
"prefer-stable": true
} }

View File

@ -1,23 +0,0 @@
# Require any additional compass plugins here.
# Set this to the root of your project when deployed:
http_path = "/"
css_dir = "css"
sass_dir = "scss"
javascripts_dir = "javascript"
# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
# To enable relative paths to assets via compass helper functions. Uncomment:
relative_assets = true
# To disable debugging comments that display the original location of your selectors. Uncomment:
line_comments = false
# If you prefer the indented syntax, you might want to regenerate this
# project again passing --syntax sass, or you can uncomment this:
# preferred_syntax = :sass
# and then run:
# sass-convert -R --from scss --to sass scss scss && rm -rf sass && mv scss sass

View File

@ -1,58 +1,43 @@
.no-sidebar .content-container.size3of4 { .no-sidebar .content-container.size3of4 {
width: 75%; width: 75%; }
}
.blog-entry .post-image img { .blog-entry .post-image img {
width: 98.75%; width: 98.75%; }
}
.blog-sidebar .WidgetHolder ul { .blog-sidebar .WidgetHolder ul {
margin-left: 0; margin-left: 0; }
} .blog-sidebar .WidgetHolder ul li {
.blog-sidebar .WidgetHolder ul li { list-style-type: none; }
list-style-type: none;
}
ul.blogTagCloud { ul.blogTagCloud {
list-style-type: none; list-style-type: none;
clear: both; clear: both; }
} ul.blogTagCloud li {
ul.blogTagCloud li {
float: left;
display: inline;
padding-right: 8px;
}
ul.blogTagCloud li a span {
float: left; float: left;
line-height: 30px; text-align: center; display: inline;
padding: 0px; padding-right: 8px; }
} ul.blogTagCloud li a span {
ul.blogTagCloud .tagCount10 { float: left;
font-size: 26pt; line-height: 30px;
} text-align: center;
ul.blogTagCloud .tagCount9 { padding: 0px; }
font-size: 24pt; ul.blogTagCloud .tagCount10 {
} font-size: 26pt; }
ul.blogTagCloud .tagCount8 { ul.blogTagCloud .tagCount9 {
font-size: 22pt; font-size: 24pt; }
} ul.blogTagCloud .tagCount8 {
ul.blogTagCloud .tagCount7 { font-size: 22pt; }
font-size: 20pt; ul.blogTagCloud .tagCount7 {
} font-size: 20pt; }
ul.blogTagCloud .tagCount6 { ul.blogTagCloud .tagCount6 {
font-size: 18pt; font-size: 18pt; }
} ul.blogTagCloud .tagCount5 {
ul.blogTagCloud .tagCount5 { font-size: 16pt; }
font-size: 16pt; ul.blogTagCloud .tagCount4 {
} font-size: 14pt; }
ul.blogTagCloud .tagCount4 { ul.blogTagCloud .tagCount3 {
font-size: 14pt; font-size: 12pt; }
} ul.blogTagCloud .tagCount2 {
ul.blogTagCloud .tagCount3 { font-size: 10pt; }
font-size: 12pt; ul.blogTagCloud .tagCount1 {
} font-size: 8pt; }
ul.blogTagCloud .tagCount2 {
font-size: 10pt;
}
ul.blogTagCloud .tagCount1 {
font-size: 8pt;
}

View File

@ -7,81 +7,66 @@
/* /*
* Sprite maps & Icons * Sprite maps & Icons
*/ */
.blog-icon-sprite, .gridfield-icon .blog-icon-timer { .gridfield-icon.blog-icon-timer {
background-image: url('../images/blog-icon-s0a5ab5f851.png'); background: url("../images/blog-icon/timer.png") center no-repeat; }
background-repeat: no-repeat;
}
.gridfield-icon .blog-icon-timer {
background-position: 0 0;
}
#FeaturedImage .middleColumn { #FeaturedImage .middleColumn {
clear: none; clear: none;
float: left; float: left; }
}
.blog-admin-sidebar { .has-panel .cms-content-tools.blog-admin-sidebar {
width: 280px; width: 280px;
border-right: none; border-right: none;
border-left: 1px solid #C0C0C2; border-left: 1px solid #C0C0C2;
position: absolute; position: absolute !important;
/* overrides cms !imporant style */
right: 0px; right: 0px;
bottom: 0px; top: 0;
height: 100%; height: 100%; }
} .has-panel .cms-content-tools.blog-admin-sidebar .cms-panel-toggle a {
.blog-admin-sidebar .cms-panel-toggle a { text-align: left;
text-align: left; margin: 0; }
} .has-panel .cms-content-tools.blog-admin-sidebar .cms-panel-toggle.south {
.blog-admin-sidebar ~ .blog-admin-outer { border-top: 1px solid #aaaaaa; }
width: 100%; .has-panel .cms-content-tools.blog-admin-sidebar ~ .blog-admin-outer {
padding-right: 280px; width: 100%;
position: absolute; padding-right: 280px;
height: 100%; position: absolute;
overflow-y: hidden; height: 100%;
overflow-x: hidden; overflow-y: hidden;
box-sizing: border-box; overflow-x: hidden;
} box-sizing: border-box; }
.blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset { .has-panel .cms-content-tools.blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset {
position: relative; position: relative;
overflow: auto; overflow: auto;
height: 100%; height: 100%;
width: 100%; width: 100%; }
} .has-panel .cms-content-tools.blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset #Title label {
.blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset #Title label { float: none; }
float: none; .has-panel .cms-content-tools.blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset #Title .middleColumn, .has-panel .cms-content-tools.blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset #Title input {
} width: 100%;
.blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset #Title .middleColumn, .blog-admin-sidebar ~ .blog-admin-outer > .ss-tabset #Title input { max-width: 100%;
width: 100%; margin-left: 0; }
max-width: 100%; .has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view > .field + .field {
margin-left: 0; margin-top: 10px; }
} .has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view > .field.urlsegment .preview {
.blog-admin-sidebar .cms-content-view > .field + .field { padding-top: 0;
margin-top: 10px; line-height: 25px; }
} .has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view > .field.urlsegment .edit {
.blog-admin-sidebar .cms-content-view > .field.urlsegment .preview { float: right; }
padding-top: 0; .has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn > .date {
line-height: 25px; width: 60%; }
} .has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn > .time {
.blog-admin-sidebar .cms-content-view > .field.urlsegment .edit { width: 36%;
float: right; float: right; }
} .has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn .middleColumn, .has-panel .cms-content-tools.blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn input {
.blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn > .date { width: 100%; }
width: 60%; .has-panel .cms-content-tools.blog-admin-sidebar.collapsed ~ .blog-admin-outer {
} padding-right: 41px; }
.blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn > .time { .has-panel .cms-content-tools.blog-admin-sidebar.collapsed ~ .blog-admin-outer #Root_Main {
width: 36%; margin-right: 15px; }
float: right; .has-panel .cms-content-tools.blog-admin-sidebar.cms-content-tools .cms-panel-content {
} width: auto; }
.blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn .middleColumn, .blog-admin-sidebar .cms-content-view > .field.datetime > .middleColumn input {
width: 100%;
}
.blog-admin-sidebar.collapsed ~ .blog-admin-outer {
padding-right: 41px;
}
.blog-admin-sidebar.cms-content-tools .cms-panel-content {
width: auto;
}
.toggle-description { .toggle-description {
text-indent: -1000000px; text-indent: -1000000px;
@ -89,63 +74,59 @@
background: url("../images/information.png") no-repeat center center; background: url("../images/information.png") no-repeat center center;
width: 20px; width: 20px;
height: 20px; height: 20px;
margin-left: 4px; margin-left: 4px; }
}
.middleColumn.toggle-description-correct-middle { .middleColumn.toggle-description-correct-middle {
margin-left: 0; margin-left: 0;
float: left; float: left;
width: 416px; width: 416px; }
}
label.right.toggle-description-correct-right { label.right.toggle-description-correct-right {
display: inline-block; display: inline-block;
margin-left: 0; margin-left: 0;
clear: none; clear: none;
float: left; float: left; }
}
.description.toggle-description-correct-description { .description.toggle-description-correct-description {
width: 416px; width: 416px;
padding: 12px 0; padding: 12px 0; }
}
.custom-summary .ui-accordion-content .field { .custom-summary .ui-accordion-content .field {
margin: 0; margin: 0; }
}
.custom-summary .ui-accordion-content, .custom-summary .ui-accordion-content,
.custom-summary .ui-accordion-content .field { .custom-summary .ui-accordion-content .field {
padding: 0; padding: 0; }
}
.custom-summary .ui-icon-triangle-1-e { .custom-summary .ui-icon-triangle-1-e {
background-position: -16px -128px; background-position: -16px -128px; }
}
.cms table.ss-gridfield-table tr td.MergeAction { .cms table.ss-gridfield-table tr td.MergeAction {
width: 225px; width: 225px; }
} .cms table.ss-gridfield-table tr td.MergeAction a {
.cms table.ss-gridfield-table tr td.MergeAction a { display: block;
display: block; height: 100%;
height: 100%; width: 100%; }
width: 100%; .cms table.ss-gridfield-table tr td.MergeAction select {
} width: 150px; }
.cms table.ss-gridfield-table tr td.MergeAction select {
width: 150px;
}
.cms-content-actions, .cms-content-actions,
.cms-preview-controls { .cms-preview-controls {
z-index: 999; z-index: 999; }
}
.blog-cms-categorisation .MergeActionReveal { .blog-cms-categorisation .MergeActionReveal {
margin-left: 10px; margin-left: 10px; }
}
.blog-cms-categorisation .toolbar--content {
margin-top: 0; }
.blog-cms-categorisation .MergeActionReveal:after { .blog-cms-categorisation .MergeActionReveal:after {
content: ''; content: '';
background: url("../images/move-icon.png"); background: url("../images/move-icon.png");
display: inline-block; display: inline-block;
height: 16px; height: 16px;
width: 16px; width: 16px;
margin-left: 4px; margin-left: 4px; }
}
.blog-cms-categorisation button.action {
margin-left: 5px; }

17
gulpfile.js Normal file
View File

@ -0,0 +1,17 @@
var sass = require("gulp-sass");
var gulp = require("gulp");
var watch = require('gulp-watch');
gulp.task("scss", function () {
gulp.src("./scss/*.scss")
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest("./css"));
});
gulp.task('watch', ['scss'], function() {
gulp.watch('./scss/*.scss', ['scss']);
});
gulp.task('default', ['scss'], function() {
// noop
});

View File

@ -113,6 +113,10 @@
if(!this.hasClass('collapsed') && ($(".blog-admin-outer").width() < this.getMinInnerWidth())) { if(!this.hasClass('collapsed') && ($(".blog-admin-outer").width() < this.getMinInnerWidth())) {
this.collapsePanel(); this.collapsePanel();
} }
window.onresize = function() {
this.updateLayout();
}.bind(this);
}, },
togglePanel: function(bool, silent) { togglePanel: function(bool, silent) {
this._super(bool, silent); this._super(bool, silent);
@ -124,9 +128,16 @@
* @returns {undefined} * @returns {undefined}
*/ */
updateLayout: function() { updateLayout: function() {
$(this).css('height', '100%');
var currentHeight = $(this).outerHeight();
var bottomHeight = $('.cms-content-actions').eq(0).outerHeight();
$(this).css('height', (currentHeight - bottomHeight) + "px");
$(this).css('bottom', bottomHeight + "px");
$('.cms-container').updateLayoutOptions({ $('.cms-container').updateLayoutOptions({
minContentWidth: 820 + this.width() minContentWidth: 820 + this.width()
}); });
} }
}); });

View File

@ -1,20 +1,16 @@
(function ($) { (function ($) {
$.entwine('ss', function ($) { $.entwine('ss', function ($) {
/** /**
* Prevent the CMS hijacking the return key * Prevent the CMS hijacking the return key
*/ */
$('.add-existing-autocompleter input.text').entwine({ $('.add-existing-autocompleter input.text').entwine({
'onkeydown': function (e) { 'onkeydown': function (e) {
if(e.which == 13) { if (e.which == 13) {
$parent = $(this).parents('.add-existing-autocompleter'); $parent = $(this).parents('.add-existing-autocompleter');
$parent.find('button[type="submit"]').click(); $parent.find('button[type="submit"]').click();
return false; return false;
} }
} }
}); });
}); });
})(jQuery); })(jQuery);

View File

@ -87,7 +87,7 @@ en:
PLURALNAME: 'Blog Recent Posts Widgets' PLURALNAME: 'Blog Recent Posts Widgets'
SINGULARNAME: 'Blog Recent Posts Widget' SINGULARNAME: 'Blog Recent Posts Widget'
BlogTag: BlogTag:
Duplicate: 'A blog tags already exists with that name' Duplicate: 'A blog tag already exists with that name'
PLURALNAME: 'Blog Tags' PLURALNAME: 'Blog Tags'
SINGULARNAME: 'Blog Tag' SINGULARNAME: 'Blog Tag'
Title: Title Title: Title

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "silverstripe-blog",
"version": "3.0.0",
"description": "Silverstripe blog module",
"main": "index.js",
"directories": {
"doc": "docs",
"test": "tests"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/silverstripe/silverstripe-blog.git"
},
"author": "",
"license": "BSD-3",
"bugs": {
"url": "https://github.com/silverstripe/silverstripe-blog/issues"
},
"homepage": "https://github.com/silverstripe/silverstripe-blog#readme",
"devDependencies": {
"gulp": "^3.9.1",
"gulp-sass": "^2.3.1",
"gulp-watch": "^4.3.6"
}
}

18
phpunit.xml.dist Normal file
View File

@ -0,0 +1,18 @@
<phpunit bootstrap="framework/tests/bootstrap.php" colors="true">
<testsuite name="blog">
<directory>blog/tests</directory>
</testsuite>
<listeners>
<listener class="SilverStripe\Dev\TestListener" />
</listeners>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">blog/src/</directory>
<exclude>
<directory suffix=".php">blog/tests/</directory>
</exclude>
</whitelist>
</filter>
</phpunit>

View File

@ -4,188 +4,205 @@
/** /**
* Include Compass framework * Include Compass framework
*/ */
@import "compass"; // @import "compass";
/* /*
* Sprite maps & Icons * Sprite maps & Icons
*/ */
@import "compass/utilities/sprites/base"; // @import "compass/utilities/sprites/base";
@import "blog-icon/*.png"; // @import "blog-icon/*.png";
// buttons // buttons
.gridfield-icon { .gridfield-icon.blog-icon-timer {
@include all-blog-icon-sprites; background: url('../images/blog-icon/timer.png') center no-repeat;
} }
#FeaturedImage .middleColumn { #FeaturedImage .middleColumn {
clear: none; clear: none;
float: left; float: left;
} }
.blog-admin-sidebar { .has-panel .cms-content-tools.blog-admin-sidebar {
width: 280px; width: 280px;
border-right: none; border-right: none;
border-left: 1px solid #C0C0C2; border-left: 1px solid #C0C0C2;
position: absolute; position: absolute !important; /* overrides cms !imporant style */
right: 0px; right: 0px;
bottom: 0px; top: 0;
height: 100%; height: 100%;
.cms-panel-toggle a { .cms-panel-toggle a {
text-align: left; text-align: left;
} margin: 0;
}
~ .blog-admin-outer { .cms-panel-toggle.south {
width: 100%; border-top: 1px solid #aaaaaa;
padding-right: 280px; }
position: absolute;
height: 100%;
overflow-y: hidden;
overflow-x: hidden;
box-sizing: border-box;
> .ss-tabset { ~ .blog-admin-outer {
position: relative; width: 100%;
overflow: auto; padding-right: 280px;
height: 100%; position: absolute;
width: 100%; height: 100%;
overflow-y: hidden;
overflow-x: hidden;
box-sizing: border-box;
#Title { > .ss-tabset {
label { position: relative;
float: none; overflow: auto;
} height: 100%;
.middleColumn, input { width: 100%;
width: 100%;
max-width: 100%;
margin-left: 0;
}
}
}
}
.cms-content-view { #Title {
> .field { label {
+ .field { float: none;
margin-top: 10px; }
} .middleColumn, input {
width: 100%;
max-width: 100%;
margin-left: 0;
}
}
}
}
&.urlsegment { .cms-content-view {
.preview { > .field {
padding-top: 0; + .field {
line-height: 25px; margin-top: 10px;
} }
.edit { &.urlsegment {
float: right; .preview {
} padding-top: 0;
} line-height: 25px;
}
&.datetime { .edit {
> .middleColumn { float: right;
> .date { }
width: 60%; }
}
> .time { &.datetime {
width: 36%; > .middleColumn {
float: right; > .date {
} width: 60%;
}
.middleColumn, input { > .time {
width: 100%; width: 36%;
} float: right;
} }
}
}
}
&.collapsed { .middleColumn, input {
~ .blog-admin-outer { width: 100%;
padding-right: 41px; }
} }
} }
}
}
&.cms-content-tools { &.collapsed {
.cms-panel-content { ~ .blog-admin-outer {
width: auto; padding-right: 41px;
}
} #Root_Main {
margin-right: 15px;
}
}
}
&.cms-content-tools {
.cms-panel-content {
width: auto;
}
}
} }
.toggle-description { .toggle-description {
text-indent: -1000000px; text-indent: -1000000px;
display: inline-block; display: inline-block;
background: url("../images/information.png") no-repeat center center; background: url("../images/information.png") no-repeat center center;
width: 20px; width: 20px;
height: 20px; height: 20px;
margin-left: 4px; margin-left: 4px;
} }
.middleColumn.toggle-description-correct-middle { .middleColumn.toggle-description-correct-middle {
margin-left: 0; margin-left: 0;
float: left; float: left;
width: 416px; width: 416px;
} }
label.right.toggle-description-correct-right { label.right.toggle-description-correct-right {
display: inline-block; display: inline-block;
margin-left: 0; margin-left: 0;
clear: none; clear: none;
float: left; float: left;
} }
.description.toggle-description-correct-description { .description.toggle-description-correct-description {
width: 416px; width: 416px;
padding: 12px 0; padding: 12px 0;
} }
.custom-summary { .custom-summary {
.ui-accordion-content .field { .ui-accordion-content .field {
margin: 0; margin: 0;
} }
.ui-accordion-content, .ui-accordion-content,
.ui-accordion-content .field { .ui-accordion-content .field {
padding: 0; padding: 0;
} }
.ui-icon-triangle-1-e { .ui-icon-triangle-1-e {
background-position: -16px -128px; background-position: -16px -128px;
} }
} }
.cms table.ss-gridfield-table { .cms table.ss-gridfield-table {
tr td.MergeAction { tr td.MergeAction {
width: 225px; width: 225px;
a { a {
display: block; display: block;
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
select { select {
width: 150px; width: 150px;
} }
} }
} }
.cms-content-actions, .cms-content-actions,
.cms-preview-controls { .cms-preview-controls {
z-index: 999; z-index: 999;
} }
.blog-cms-categorisation { .blog-cms-categorisation {
.MergeActionReveal {
margin-left: 10px;
}
.MergeActionReveal { .toolbar--content {
margin-left: 10px; margin-top: 0;
} }
.MergeActionReveal:after { .MergeActionReveal:after {
content: ''; content: '';
background: url('../images/move-icon.png'); background: url('../images/move-icon.png');
display: inline-block; display: inline-block;
height: 16px; height: 16px;
width: 16px; width: 16px;
margin-left: 4px; margin-left: 4px;
} }
button.action {
margin-left: 5px;
}
} }

View File

@ -0,0 +1,68 @@
<?php
namespace SilverStripe\Blog\Admin;
use SilverStripe\Blog\Forms\GridField\GridFieldAddByDBField;
use SilverStripe\Blog\Admin\GridFieldMergeAction;
use SilverStripe\Blog\Model\CategorisationObject;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
class GridFieldCategorisationConfig extends GridFieldConfig_RecordEditor
{
/**
* @param int $itemsPerPage
* @param array|SS_List $mergeRecords
* @param string $parentType
* @param string $parentMethod
* @param string $childMethod
*/
public function __construct($itemsPerPage = 15, $mergeRecords, $parentType, $parentMethod, $childMethod)
{
parent::__construct($itemsPerPage);
$this->removeComponentsByType('SilverStripe\\Forms\\GridField\\GridFieldAddNewButton');
$this->addComponent(
new GridFieldAddByDBField('buttons-before-left')
);
$this->addComponent(
new GridFieldMergeAction($mergeRecords, $parentType, $parentMethod, $childMethod)
);
/**
* @var GridFieldDataColumns $columns
*/
$columns = $this->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
$columns->setFieldFormatting(
array(
'BlogPostsCount' => function ($value, CategorisationObject $item) {
return $item->BlogPosts()->Count();
}
)
);
$this->changeColumnOrder();
}
/**
* Reorders GridField columns so that Actions is last.
*/
protected function changeColumnOrder()
{
/**
* @var GridFieldDataColumns $columns
*/
$columns = $this->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
$columns->setDisplayFields(
array(
'Title' => 'Title',
'BlogPostsCount' => 'Posts',
'MergeAction' => 'MergeAction',
'Actions' => 'Actions'
)
);
}
}

View File

@ -1,5 +1,9 @@
<?php <?php
namespace SilverStripe\Blog\Admin;
use SilverStripe\Forms\GridField\GridField_FormAction;
class GridFieldFormAction extends GridField_FormAction class GridFieldFormAction extends GridField_FormAction
{ {
/** /**

View File

@ -1,5 +1,17 @@
<?php <?php
namespace SilverStripe\Blog\Admin;
use SilverStripe\Blog\Admin\GridFieldFormAction;
use SilverStripe\Control\Controller;
use Silverstripe\Forms\DropdownField;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_ActionProvider;
use SilverStripe\Forms\GridField\GridField_ColumnProvider;
/**
* @package blog
*/
class GridFieldMergeAction implements GridField_ColumnProvider, GridField_ActionProvider class GridFieldMergeAction implements GridField_ColumnProvider, GridField_ActionProvider
{ {
/** /**
@ -70,11 +82,11 @@ class GridFieldMergeAction implements GridField_ColumnProvider, GridField_Action
public function getColumnContent($gridField, $record, $columnName) public function getColumnContent($gridField, $record, $columnName)
{ {
if ($columnName === 'MergeAction' && $record->{$this->childMethod}()->Count() > 0) { if ($columnName === 'MergeAction' && $record->{$this->childMethod}()->Count() > 0) {
$dropdown = new DropdownField('Target', 'Target', $this->records->exclude('ID', $record->ID)->map()); $dropdown = DropdownField::create('Target', 'Target', $this->records->exclude('ID', $record->ID)->map());
$dropdown->setAttribute('id', 'Target_'.$record->ID); $dropdown->setAttribute('id', 'Target_'.$record->ID);
$prefix = strtolower($this->parentMethod . '-' . $this->childMethod); $prefix = strtolower($this->parentMethod . '-' . $this->childMethod);
$action = GridFieldFormAction::create( $action = new GridFieldFormAction(
$gridField, $gridField,
'MergeAction' . $record->ID, 'MergeAction' . $record->ID,
'Move', 'Move',

View File

@ -1,5 +1,10 @@
<?php <?php
namespace SilverStripe\Blog\Forms;
use SilverStripe\Control\Cookie;
use SilverStripe\Forms\FieldGroup;
class BlogAdminSidebar extends FieldGroup class BlogAdminSidebar extends FieldGroup
{ {
/** /**

View File

@ -1,5 +1,20 @@
<?php <?php
namespace SilverStripe\Blog\Forms\GridField;
use UnexpectedValueException;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_ActionProvider;
use SilverStripe\Forms\GridField\GridField_FormAction;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\Security\Security;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
/** /**
* Adds a component which allows a user to add a new DataObject by database field. * Adds a component which allows a user to add a new DataObject by database field.
* *
@ -79,7 +94,7 @@ class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLP
if ($obj->canCreate()) { if ($obj->canCreate()) {
$id = $gridField->getList()->add($obj); $id = $gridField->getList()->add($obj);
if (!$id) { if (!$id) {
$gridField->setError( $gridField->setCustomValidationMessage(
_t( _t(
'GridFieldAddByDBField.AddFail', 'GridFieldAddByDBField.AddFail',
'Unable to save {class} to the database.', 'Unable to save {class} to the database.',
@ -87,8 +102,7 @@ class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLP
array( array(
'class' => get_class($obj), 'class' => get_class($obj),
) )
), )
'error'
); );
} }
} else { } else {
@ -159,7 +173,7 @@ class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLP
$obj = singleton($dataClass); $obj = singleton($dataClass);
if (!$obj->canCreate()) { if (!$obj->canCreate()) {
return ""; return '';
} }
$dbField = $this->getDataObjectField(); $dbField = $this->getDataObjectField();
@ -177,16 +191,17 @@ class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLP
$addAction = new GridField_FormAction( $addAction = new GridField_FormAction(
$gridField, $gridField,
'add', 'add',
_t('GridFieldAddByDBField.Add', _t(
'Add {name}', "Add button text", 'GridFieldAddByDBField.Add',
array( 'Add {name}',
'name' => $obj->i18n_singular_name(), 'Add button text',
) ['name' => $obj->i18n_singular_name()]
), ),
'add', 'add',
'add' 'add'
); );
$addAction->setAttribute('data-icon', 'add'); $addAction->setAttribute('data-icon', 'add');
$addAction->addExtraClass('btn btn-primary');
$forTemplate = new ArrayData(array()); $forTemplate = new ArrayData(array());
@ -194,8 +209,6 @@ class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLP
$forTemplate->Fields->push($textField); $forTemplate->Fields->push($textField);
$forTemplate->Fields->push($addAction); $forTemplate->Fields->push($addAction);
return array( return array($this->targetFragment => $forTemplate->renderWith(self::class));
$this->targetFragment => $forTemplate->renderWith('GridFieldAddByDBField')
);
} }
} }

View File

@ -1,5 +1,12 @@
<?php <?php
namespace SilverStripe\Blog\Forms\GridField;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState;
use SilverStripe\View\Requirements;
/** /**
* Provides a component to the {@link GridField} which tells the user whether or not a blog post * Provides a component to the {@link GridField} which tells the user whether or not a blog post
* has been published and when. * has been published and when.

View File

@ -1,5 +1,10 @@
<?php <?php
namespace SilverStripe\Blog\Forms\GridField;
use SilverStripe\Lumberjack\Forms\GridFieldConfig_Lumberjack;
use SilverStripe\Lumberjack\Forms\GridFieldSiteTreeState;
/** /**
* GridField config necessary for managing a SiteTree object. * GridField config necessary for managing a SiteTree object.
* *
@ -15,7 +20,7 @@ class GridFieldConfig_BlogPost extends GridFieldConfig_Lumberjack
{ {
parent::__construct($itemsPerPage); parent::__construct($itemsPerPage);
$this->removeComponentsByType('GridFieldSiteTreeState'); $this->removeComponentsByType(GridFieldSiteTreeState::class);
$this->addComponent(new GridFieldBlogPostState()); $this->addComponent(new GridFieldBlogPostState());
} }
} }

View File

@ -1,5 +1,34 @@
<?php <?php
namespace SilverStripe\Blog\Model;
use Page;
use PageController;
use SilverStripe\Blog\Admin\GridFieldCategorisationConfig;
use SilverStripe\Blog\Forms\GridField\GridFieldConfig_BlogPost;
use SilverStripe\Blog\Model\BlogCategory;
use SilverStripe\Blog\Model\BlogFilter;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Blog\Model\BlogTag;
use SilverStripe\CMS\Controllers\RootURLController;
use SilverStripe\Control\Controller;
use SilverStripe\Control\RSS\RSSFeed;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\ListboxField;
use SilverStripe\Forms\NumericField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\PaginatedList;
use SilverStripe\ORM\UnsavedRelationList;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
use SilverStripe\Security\PermissionProvider;
use SilverStripe\View\Requirements;
/** /**
* Blog Holder * Blog Holder
* *
@ -50,6 +79,12 @@ class Blog extends Page implements PermissionProvider
*/ */
private static $grant_user_group = 'blog-users'; private static $grant_user_group = 'blog-users';
/**
* {@inheritDoc}
* @var string
*/
private static $table_name = 'Blog';
/** /**
* @var array * @var array
*/ */
@ -61,31 +96,31 @@ class Blog extends Page implements PermissionProvider
* @var array * @var array
*/ */
private static $has_many = array( private static $has_many = array(
'Tags' => 'BlogTag', 'Tags' => BlogTag::class,
'Categories' => 'BlogCategory', 'Categories' => BlogCategory::class,
); );
/** /**
* @var array * @var array
*/ */
private static $many_many = array( private static $many_many = array(
'Editors' => 'Member', 'Editors' => Member::class,
'Writers' => 'Member', 'Writers' => Member::class,
'Contributors' => 'Member', 'Contributors' => Member::class,
); );
/** /**
* @var array * @var array
*/ */
private static $allowed_children = array( private static $allowed_children = array(
'BlogPost', BlogPost::class,
); );
/** /**
* @var array * @var array
*/ */
private static $extensions = array( private static $extensions = array(
'BlogFilter', BlogFilter::class,
); );
/** /**
@ -93,7 +128,7 @@ class Blog extends Page implements PermissionProvider
*/ */
private static $defaults = array( private static $defaults = array(
'ProvideComments' => false, 'ProvideComments' => false,
'PostsPerPage' => 10, 'PostsPerPage' => 10
); );
/** /**
@ -111,34 +146,47 @@ class Blog extends Page implements PermissionProvider
Requirements::css(BLOGGER_DIR . '/css/cms.css'); Requirements::css(BLOGGER_DIR . '/css/cms.css');
Requirements::javascript(BLOGGER_DIR . '/js/cms.js'); Requirements::javascript(BLOGGER_DIR . '/js/cms.js');
$self =& $this; $this->beforeUpdateCMSFields(function ($fields) {
if (!$this->canEdit()) {
$this->beforeUpdateCMSFields(function ($fields) use ($self) {
if (!$self->canEdit()) {
return; return;
} }
$categories = GridField::create( $categories = GridField::create(
'Categories', 'Categories',
_t('Blog.Categories', 'Categories'), _t('Blog.Categories', 'Categories'),
$self->Categories(), $this->Categories(),
GridFieldCategorisationConfig::create(15, $self->Categories()->sort('Title'), 'BlogCategory', 'Categories', 'BlogPosts') GridFieldCategorisationConfig::create(
15,
$this->Categories()->sort('Title'),
BlogCategory::class,
'Categories',
'BlogPosts'
)
); );
$tags = GridField::create( $tags = GridField::create(
'Tags', 'Tags',
_t('Blog.Tags', 'Tags'), _t('Blog.Tags', 'Tags'),
$self->Tags(), $this->Tags(),
GridFieldCategorisationConfig::create(15, $self->Tags()->sort('Title'), 'BlogTag', 'Tags', 'BlogPosts') GridFieldCategorisationConfig::create(
15,
$this->Tags()->sort('Title'),
BlogTag::class,
'Tags',
'BlogPosts'
)
); );
/** /**
* @var FieldList $fields * @var FieldList $fields
*/ */
$fields->addFieldsToTab('Root.Categorisation', array( $fields->addFieldsToTab(
$categories, 'Root.Categorisation',
$tags array(
)); $categories,
$tags
)
);
$fields->findOrMakeTab('Root.Categorisation')->addExtraClass('blog-cms-categorisation'); $fields->findOrMakeTab('Root.Categorisation')->addExtraClass('blog-cms-categorisation');
}); });
@ -228,7 +276,7 @@ class Blog extends Page implements PermissionProvider
public function RoleOf($member) public function RoleOf($member)
{ {
if (is_numeric($member)) { if (is_numeric($member)) {
$member = DataObject::get_by_id('Member', $member); $member = Member::get()->byId($member);
} }
if (!$member) { if (!$member) {
@ -301,14 +349,15 @@ class Blog extends Page implements PermissionProvider
{ {
$fields = parent::getSettingsFields(); $fields = parent::getSettingsFields();
$fields->addFieldToTab('Root.Settings', $fields->addFieldToTab(
'Root.Settings',
NumericField::create('PostsPerPage', _t('Blog.PostsPerPage', 'Posts Per Page')) NumericField::create('PostsPerPage', _t('Blog.PostsPerPage', 'Posts Per Page'))
); );
$members = $this->getCandidateUsers()->map()->toArray(); $members = $this->getCandidateUsers()->map()->toArray();
$editorField = ListboxField::create('Editors', 'Editors', $members) $editorField = ListboxField::create('Editors', 'Editors', $members)
->setMultiple(true) // ->setMultiple(true)
->setRightTitle('<a class="toggle-description">help</a>') ->setRightTitle('<a class="toggle-description">help</a>')
->setDescription(' ->setDescription('
An editor has control over specific Blogs, and all posts included within it. Short of being able to assign other editors to a blog, they are able to handle most changes to their assigned blog.<br /> An editor has control over specific Blogs, and all posts included within it. Short of being able to assign other editors to a blog, they are able to handle most changes to their assigned blog.<br />
@ -327,7 +376,7 @@ class Blog extends Page implements PermissionProvider
} }
$writerField = ListboxField::create('Writers', 'Writers', $members) $writerField = ListboxField::create('Writers', 'Writers', $members)
->setMultiple(true) // ->setMultiple(true)
->setRightTitle('<a class="toggle-description">help</a>') ->setRightTitle('<a class="toggle-description">help</a>')
->setDescription(' ->setDescription('
A writer has full control over creating, editing and publishing BlogPosts they have authored or have been assigned to. Writers are unable to edit BlogPosts to which they are not assigned.<br /> A writer has full control over creating, editing and publishing BlogPosts they have authored or have been assigned to. Writers are unable to edit BlogPosts to which they are not assigned.<br />
@ -343,7 +392,7 @@ class Blog extends Page implements PermissionProvider
} }
$contributorField = ListboxField::create('Contributors', 'Contributors', $members) $contributorField = ListboxField::create('Contributors', 'Contributors', $members)
->setMultiple(true) // ->setMultiple(true)
->setRightTitle('<a class="toggle-description">help</a>') ->setRightTitle('<a class="toggle-description">help</a>')
->setDescription(' ->setDescription('
Contributors have the ability to create or edit BlogPosts, but are unable to publish without authorisation of an editor. They are also unable to assign other contributing authors to any of their BlogPosts.<br /> Contributors have the ability to create or edit BlogPosts, but are unable to publish without authorisation of an editor. They are also unable to assign other contributing authors to any of their BlogPosts.<br />
@ -357,11 +406,14 @@ class Blog extends Page implements PermissionProvider
$contributorField = $contributorField->performDisabledTransformation(); $contributorField = $contributorField->performDisabledTransformation();
} }
$fields->addFieldsToTab('Root.Users', array( $fields->addFieldsToTab(
$editorField, 'Root.Users',
$writerField, array(
$contributorField $editorField,
)); $writerField,
$contributorField
)
);
return $fields; return $fields;
} }
@ -471,7 +523,10 @@ class Blog extends Page implements PermissionProvider
$stage = '_' . $stage; $stage = '_' . $stage;
} }
$query->innerJoin('BlogPost', sprintf('"SiteTree%s"."ID" = "BlogPost%s"."ID"', $stage, $stage)); $query->innerJoin(
DataObject::getSchema()->tableName(BlogPost::class),
sprintf('"SiteTree%s"."ID" = "BlogPost%s"."ID"', $stage, $stage)
);
$conn = DB::getConn(); $conn = DB::getConn();
@ -517,7 +572,13 @@ class Blog extends Page implements PermissionProvider
*/ */
public function ProfileLink($urlSegment) public function ProfileLink($urlSegment)
{ {
return Controller::join_links($this->Link(), 'profile', $urlSegment); $baseLink = $this->Link();
if ($baseLink === '/') {
// Handle homepage blogs
$baseLink = RootURLController::get_homepage_link();
}
return Controller::join_links($baseLink, 'profile', $urlSegment);
} }
/** /**
@ -608,13 +669,13 @@ class Blog extends Page implements PermissionProvider
return $group; return $group;
} }
$group = new Group(); $group = Group::create();
$group->Title = 'Blog users'; $group->Title = 'Blog users';
$group->Code = $code; $group->Code = $code;
$group->write(); $group->write();
$permission = new Permission(); $permission = Permission::create();
$permission->Code = $this->config()->grant_user_permission; $permission->Code = $this->config()->grant_user_permission;
$group->Permissions()->add($permission); $group->Permissions()->add($permission);
@ -622,510 +683,3 @@ class Blog extends Page implements PermissionProvider
return $group; return $group;
} }
} }
/**
* @package silverstripe
* @subpackage blog
*/
class Blog_Controller extends Page_Controller
{
/**
* @var array
*/
private static $allowed_actions = array(
'archive',
'tag',
'category',
'rss',
'profile',
);
/**
* @var array
*/
private static $url_handlers = array(
'tag/$Tag!/$Rss' => 'tag',
'category/$Category!/$Rss' => 'category',
'archive/$Year!/$Month/$Day' => 'archive',
'profile/$URLSegment!' => 'profile',
);
/**
* @var array
*/
private static $casting = array(
'MetaTitle' => 'Text',
'FilterDescription' => 'Text',
);
/**
* The current Blog Post DataList query.
*
* @var DataList
*/
protected $blogPosts;
/**
* @return string
*/
public function index()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$this->blogPosts = $dataRecord->getBlogPosts();
return $this->render();
}
/**
* Renders a Blog Member's profile.
*
* @return SS_HTTPResponse
*/
public function profile()
{
$profile = $this->getCurrentProfile();
if (!$profile) {
return $this->httpError(404, 'Not Found');
}
$this->blogPosts = $this->getCurrentProfilePosts();
return $this->render();
}
/**
* Get the Member associated with the current URL segment.
*
* @return null|Member
*/
public function getCurrentProfile()
{
$urlSegment = $this->request->param('URLSegment');
if ($urlSegment) {
return Member::get()
->filter('URLSegment', $urlSegment)
->first();
}
return null;
}
/**
* Get posts related to the current Member profile.
*
* @return null|DataList
*/
public function getCurrentProfilePosts()
{
$profile = $this->getCurrentProfile();
if ($profile) {
return $profile->BlogPosts()->filter('ParentID', $this->ID);
}
return null;
}
/**
* Renders an archive for a specified date. This can be by year or year/month.
*
* @return null|SS_HTTPResponse
*/
public function archive()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$year = $this->getArchiveYear();
$month = $this->getArchiveMonth();
$day = $this->getArchiveDay();
if ($this->request->param('Month') && !$month) {
$this->httpError(404, 'Not Found');
}
if ($month && $this->request->param('Day') && !$day) {
$this->httpError(404, 'Not Found');
}
if ($year) {
$this->blogPosts = $dataRecord->getArchivedBlogPosts($year, $month, $day);
return $this->render();
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Fetches the archive year from the url.
*
* @return int
*/
public function getArchiveYear()
{
if ($this->request->param('Year')) {
if (preg_match('/^[0-9]{4}$/', $year = $this->request->param('Year'))) {
return (int) $year;
}
} elseif ($this->request->param('Action') == 'archive') {
return SS_Datetime::now()->Year();
}
return null;
}
/**
* Fetches the archive money from the url.
*
* @return null|int
*/
public function getArchiveMonth()
{
$month = $this->request->param('Month');
if (preg_match('/^[0-9]{1,2}$/', $month)) {
if ($month > 0 && $month < 13) {
if (checkdate($month, 01, $this->getArchiveYear())) {
return (int) $month;
}
}
}
return null;
}
/**
* Fetches the archive day from the url.
*
* @return null|int
*/
public function getArchiveDay()
{
$day = $this->request->param('Day');
if (preg_match('/^[0-9]{1,2}$/', $day)) {
if (checkdate($this->getArchiveMonth(), $day, $this->getArchiveYear())) {
return (int) $day;
}
}
return null;
}
/**
* Renders the blog posts for a given tag.
*
* @return null|SS_HTTPResponse
*/
public function tag()
{
$tag = $this->getCurrentTag();
if ($tag) {
$this->blogPosts = $tag->BlogPosts();
if($this->isRSS()) {
return $this->rssFeed($this->blogPosts, $tag->getLink());
} else {
return $this->render();
}
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Tag Getter for use in templates.
*
* @return null|BlogTag
*/
public function getCurrentTag()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$tag = $this->request->param('Tag');
if ($tag) {
return $dataRecord->Tags()
->filter('URLSegment', array($tag, rawurlencode($tag)))
->first();
}
return null;
}
/**
* Renders the blog posts for a given category.
*
* @return null|SS_HTTPResponse
*/
public function category()
{
$category = $this->getCurrentCategory();
if ($category) {
$this->blogPosts = $category->BlogPosts();
if($this->isRSS()) {
return $this->rssFeed($this->blogPosts, $category->getLink());
} else {
return $this->render();
}
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Category Getter for use in templates.
*
* @return null|BlogCategory
*/
public function getCurrentCategory()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$category = $this->request->param('Category');
if ($category) {
return $dataRecord->Categories()
->filter('URLSegment', array($category, rawurlencode($category)))
->first();
}
return null;
}
/**
* Get the meta title for the current action.
*
* @return string
*/
public function getMetaTitle()
{
$title = $this->data()->getTitle();
$filter = $this->getFilterDescription();
if ($filter) {
$title = sprintf('%s - %s', $title, $filter);
}
$this->extend('updateMetaTitle', $title);
return $title;
}
/**
* Returns a description of the current filter.
*
* @return string
*/
public function getFilterDescription()
{
$items = array();
$list = $this->PaginatedList();
$currentPage = $list->CurrentPage();
if ($currentPage > 1) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_PAGE',
'Page {page}',
null,
array(
'page' => $currentPage,
)
);
}
if ($author = $this->getCurrentProfile()) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_AUTHOR',
'By {author}',
null,
array(
'author' => $author->Title,
)
);
}
if ($tag = $this->getCurrentTag()) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_TAG',
'Tagged with {tag}',
null,
array(
'tag' => $tag->Title,
)
);
}
if ($category = $this->getCurrentCategory()) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_CATEGORY',
'In category {category}',
null,
array(
'category' => $category->Title,
)
);
}
if ($this->owner->getArchiveYear()) {
if ($this->owner->getArchiveDay()) {
$date = $this->owner->getArchiveDate()->Nice();
} elseif ($this->owner->getArchiveMonth()) {
$date = $this->owner->getArchiveDate()->format('F, Y');
} else {
$date = $this->owner->getArchiveDate()->format('Y');
}
$items[] = _t(
'Blog.FILTERDESCRIPTION_DATE',
'In {date}',
null,
array(
'date' => $date,
)
);
}
$result = '';
if ($items) {
$result = implode(', ', $items);
}
$this->extend('updateFilterDescription', $result);
return $result;
}
/**
* Returns a list of paginated blog posts based on the BlogPost dataList.
*
* @return PaginatedList
*/
public function PaginatedList()
{
$allPosts = $this->blogPosts ?: new ArrayList();
$posts = new PaginatedList($allPosts);
// Set appropriate page size
if ($this->PostsPerPage > 0) {
$pageSize = $this->PostsPerPage;
} elseif ($count = $allPosts->count()) {
$pageSize = $count;
} else {
$pageSize = 99999;
}
$posts->setPageLength($pageSize);
// Set current page
$start = $this->request->getVar($posts->getPaginationGetVar());
$posts->setPageStart($start);
return $posts;
}
/**
* Displays an RSS feed of blog posts.
*
* @return string
*/
public function rss()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$this->blogPosts = $dataRecord->getBlogPosts();
return $this->rssFeed($this->blogPosts, $this->Link());
}
/**
* Returns the current archive date.
*
* @return null|Date
*/
public function getArchiveDate()
{
$year = $this->getArchiveYear();
$month = $this->getArchiveMonth();
$day = $this->getArchiveDay();
if ($year) {
if ($month) {
$date = sprintf('%s-%s-01', $year, $month);
if ($day) {
$date = sprintf('%s-%s-%s', $year, $month, $day);
}
} else {
$date = sprintf('%s-01-01', $year);
}
return DBField::create_field('Date', $date);
}
return null;
}
/**
* Returns a link to the RSS feed.
*
* @return string
*/
public function getRSSLink()
{
return $this->Link('rss');
}
/**
* Displays an RSS feed of the given blog posts.
*
* @param DataList $blogPosts
* @param string $link
*
* @return string
*/
protected function rssFeed($blogPosts, $link)
{
$rss = new RSSFeed($blogPosts, $link, $this->MetaTitle, $this->MetaDescription);
$this->extend('updateRss', $rss);
return $rss->outputToBrowser();
}
/**
* Returns true if the $Rss sub-action for categories/tags has been set to "rss"
*/
private function isRSS()
{
$rss = $this->request->param('Rss');
if(is_string($rss) && strcasecmp($rss, "rss") == 0) {
return true;
} else {
return false;
}
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace SilverStripe\Blog\Model;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogObject;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Blog\Model\CategorisationObject;
use SilverStripe\ORM\DataObject;
/**
* A blog category for generalising blog posts.
*
* @package silverstripe
* @subpackage blog
*
* @method Blog Blog()
*
* @property string $Title
* @property string $URLSegment
* @property int $BlogID
*/
class BlogCategory extends DataObject implements CategorisationObject
{
use BlogObject;
/**
* Use an exception code so that attempted writes can continue on
* duplicate errors.
*
* @const string
* This must be a string because ValidationException has decided we can't use int
*/
const DUPLICATE_EXCEPTION = 'DUPLICATE';
/**
* {@inheritDoc}
* @var string
*/
private static $table_name = 'BlogCategory';
/**
* @var array
*/
private static $db = array(
'Title' => 'Varchar(255)',
'URLSegment' => 'Varchar(255)'
);
/**
* @var array
*/
private static $has_one = array(
'Blog' => Blog::class,
);
/**
* @var array
*/
private static $belongs_many_many = array(
'BlogPosts' => BlogPost::class,
);
/**
* {@inheritdoc}
*/
protected function getListUrlSegment()
{
return 'category';
}
/**
* {@inheritdoc}
*/
protected function getDuplicateError()
{
return _t('BlogCategory.Duplicate', 'A blog category already exists with that name.');
}
}

View File

@ -1,5 +1,10 @@
<?php <?php
namespace SilverStripe\Blog\Model;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\ORM\DataExtension;
/** /**
* Adds Blog specific behaviour to Comment. * Adds Blog specific behaviour to Comment.
*/ */

View File

@ -0,0 +1,516 @@
<?php
namespace SilverStripe\Blog\Model;
use PageController;
use SilverStripe\Control\RSS\RSSFeed;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\PaginatedList;
use SilverStripe\Security\Member;
/**
* @package silverstripe
* @subpackage blog
*/
class BlogController extends PageController
{
/**
* @var array
*/
private static $allowed_actions = array(
'archive',
'tag',
'category',
'rss',
'profile'
);
/**
* @var array
*/
private static $url_handlers = array(
'tag/$Tag!/$Rss' => 'tag',
'category/$Category!/$Rss' => 'category',
'archive/$Year!/$Month/$Day' => 'archive',
'profile/$URLSegment!' => 'profile'
);
/**
* @var array
*/
private static $casting = array(
'MetaTitle' => 'Text',
'FilterDescription' => 'Text'
);
/**
* The current Blog Post DataList query.
*
* @var DataList
*/
protected $blogPosts;
/**
* @return string
*/
public function index()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$this->blogPosts = $dataRecord->getBlogPosts();
return $this->render();
}
/**
* Renders a Blog Member's profile.
*
* @return HTTPResponse
*/
public function profile()
{
$profile = $this->getCurrentProfile();
if (!$profile) {
return $this->httpError(404, 'Not Found');
}
$this->blogPosts = $this->getCurrentProfilePosts();
return $this->render();
}
/**
* Get the Member associated with the current URL segment.
*
* @return null|Member
*/
public function getCurrentProfile()
{
$urlSegment = $this->request->param('URLSegment');
if ($urlSegment) {
return Member::get()
->filter('URLSegment', $urlSegment)
->first();
}
return null;
}
/**
* Get posts related to the current Member profile.
*
* @return null|DataList
*/
public function getCurrentProfilePosts()
{
$profile = $this->getCurrentProfile();
if ($profile) {
return $profile->BlogPosts()->filter('ParentID', $this->ID);
}
return null;
}
/**
* Renders an archive for a specified date. This can be by year or year/month.
*
* @return null|HTTPResponse
*/
public function archive()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$year = $this->getArchiveYear();
$month = $this->getArchiveMonth();
$day = $this->getArchiveDay();
if ($this->request->param('Month') && !$month) {
$this->httpError(404, 'Not Found');
}
if ($month && $this->request->param('Day') && !$day) {
$this->httpError(404, 'Not Found');
}
if ($year) {
$this->blogPosts = $dataRecord->getArchivedBlogPosts($year, $month, $day);
return $this->render();
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Fetches the archive year from the url.
*
* @return int
*/
public function getArchiveYear()
{
if ($this->request->param('Year')) {
if (preg_match('/^[0-9]{4}$/', $year = $this->request->param('Year'))) {
return (int) $year;
}
} elseif ($this->request->param('Action') == 'archive') {
return DBDatetime::now()->Year();
}
return null;
}
/**
* Fetches the archive money from the url.
*
* @return null|int
*/
public function getArchiveMonth()
{
$month = $this->request->param('Month');
if (preg_match('/^[0-9]{1,2}$/', $month)) {
if ($month > 0 && $month < 13) {
if (checkdate($month, 01, $this->getArchiveYear())) {
return (int) $month;
}
}
}
return null;
}
/**
* Fetches the archive day from the url.
*
* @return null|int
*/
public function getArchiveDay()
{
$day = $this->request->param('Day');
if (preg_match('/^[0-9]{1,2}$/', $day)) {
if (checkdate($this->getArchiveMonth(), $day, $this->getArchiveYear())) {
return (int) $day;
}
}
return null;
}
/**
* Renders the blog posts for a given tag.
*
* @return null|HTTPResponse
*/
public function tag()
{
$tag = $this->getCurrentTag();
if ($tag) {
$this->blogPosts = $tag->BlogPosts();
if($this->isRSS()) {
return $this->rssFeed($this->blogPosts, $tag->getLink());
} else {
return $this->render();
}
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Tag Getter for use in templates.
*
* @return null|BlogTag
*/
public function getCurrentTag()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$tag = $this->request->param('Tag');
if ($tag) {
return $dataRecord->Tags()
->filter('URLSegment', array($tag, rawurlencode($tag)))
->first();
}
return null;
}
/**
* Renders the blog posts for a given category.
*
* @return null|HTTPResponse
*/
public function category()
{
$category = $this->getCurrentCategory();
if ($category) {
$this->blogPosts = $category->BlogPosts();
if($this->isRSS()) {
return $this->rssFeed($this->blogPosts, $category->getLink());
} else {
return $this->render();
}
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Category Getter for use in templates.
*
* @return null|BlogCategory
*/
public function getCurrentCategory()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$category = $this->request->param('Category');
if ($category) {
return $dataRecord->Categories()
->filter('URLSegment', array($category, rawurlencode($category)))
->first();
}
return null;
}
/**
* Get the meta title for the current action.
*
* @return string
*/
public function getMetaTitle()
{
$title = $this->data()->getTitle();
$filter = $this->getFilterDescription();
if ($filter) {
$title = sprintf('%s - %s', $title, $filter);
}
$this->extend('updateMetaTitle', $title);
return $title;
}
/**
* Returns a description of the current filter.
*
* @return string
*/
public function getFilterDescription()
{
$items = array();
$list = $this->PaginatedList();
$currentPage = $list->CurrentPage();
if ($currentPage > 1) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_PAGE',
'Page {page}',
null,
array(
'page' => $currentPage
)
);
}
if ($author = $this->getCurrentProfile()) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_AUTHOR',
'By {author}',
null,
array(
'author' => $author->Title
)
);
}
if ($tag = $this->getCurrentTag()) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_TAG',
'Tagged with {tag}',
null,
array(
'tag' => $tag->Title
)
);
}
if ($category = $this->getCurrentCategory()) {
$items[] = _t(
'Blog.FILTERDESCRIPTION_CATEGORY',
'In category {category}',
null,
array(
'category' => $category->Title
)
);
}
if ($this->owner->getArchiveYear()) {
if ($this->owner->getArchiveDay()) {
$date = $this->owner->getArchiveDate()->Nice();
} elseif ($this->owner->getArchiveMonth()) {
$date = $this->owner->getArchiveDate()->format('F, Y');
} else {
$date = $this->owner->getArchiveDate()->format('Y');
}
$items[] = _t(
'Blog.FILTERDESCRIPTION_DATE',
'In {date}',
null,
array(
'date' => $date,
)
);
}
$result = '';
if ($items) {
$result = implode(', ', $items);
}
$this->extend('updateFilterDescription', $result);
return $result;
}
/**
* Returns a list of paginated blog posts based on the BlogPost dataList.
*
* @return PaginatedList
*/
public function PaginatedList()
{
$allPosts = $this->blogPosts ?: ArrayList::create();
$posts = PaginatedList::create($allPosts);
// Set appropriate page size
if ($this->PostsPerPage > 0) {
$pageSize = $this->PostsPerPage;
} elseif ($count = $allPosts->count()) {
$pageSize = $count;
} else {
$pageSize = 99999;
}
$posts->setPageLength($pageSize);
// Set current page
$start = $this->request->getVar($posts->getPaginationGetVar());
$posts->setPageStart($start);
return $posts;
}
/**
* Displays an RSS feed of blog posts.
*
* @return string
*/
public function rss()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$this->blogPosts = $dataRecord->getBlogPosts();
return $this->rssFeed($this->blogPosts, $this->Link());
}
/**
* Returns the current archive date.
*
* @return null|Date
*/
public function getArchiveDate()
{
$year = $this->getArchiveYear();
$month = $this->getArchiveMonth();
$day = $this->getArchiveDay();
if ($year) {
if ($month) {
$date = sprintf('%s-%s-01', $year, $month);
if ($day) {
$date = sprintf('%s-%s-%s', $year, $month, $day);
}
} else {
$date = sprintf('%s-01-01', $year);
}
$obj = DBDatetime::create('date');
$obj->setValue($date);
return $obj;
}
return null;
}
/**
* Returns a link to the RSS feed.
*
* @return string
*/
public function getRSSLink()
{
return $this->Link('rss');
}
/**
* Displays an RSS feed of the given blog posts.
*
* @param DataList $blogPosts
* @param string $link
*
* @return string
*/
protected function rssFeed($blogPosts, $link)
{
$rss = new RSSFeed($blogPosts, $link, $this->MetaTitle, $this->MetaDescription);
$this->extend('updateRss', $rss);
return $rss->outputToBrowser();
}
/**
* Returns true if the $Rss sub-action for categories/tags has been set to "rss"
*
* @return bool
*/
protected function isRSS()
{
$rss = $this->request->param('Rss');
return (is_string($rss) && strcasecmp($rss, 'rss') == 0);
}
}

View File

@ -1,5 +1,20 @@
<?php <?php
namespace SilverStripe\Blog\Model;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogFilter\BlogFilterGridField;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Tab;
use SilverStripe\Lumberjack\Model\Lumberjack;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\Versioning\Versioned;
use SilverStripe\Security\Permission;
/** /**
* This class is responsible for filtering the SiteTree when necessary and also overlaps into * This class is responsible for filtering the SiteTree when necessary and also overlaps into
* filtering only published posts. * filtering only published posts.
@ -17,7 +32,7 @@ class BlogFilter extends Lumberjack
$staged = parent::stageChildren($showAll); $staged = parent::stageChildren($showAll);
if (!$this->shouldFilter() && $this->subclassForBlog() && !Permission::check('VIEW_DRAFT_CONTENT')) { if (!$this->shouldFilter() && $this->subclassForBlog() && !Permission::check('VIEW_DRAFT_CONTENT')) {
$stage = Versioned::current_stage(); $stage = Versioned::get_stage();
if ($stage == 'Stage') { if ($stage == 'Stage') {
$stage = ''; $stage = '';
@ -26,8 +41,11 @@ class BlogFilter extends Lumberjack
} }
$dataQuery = $staged->dataQuery() $dataQuery = $staged->dataQuery()
->innerJoin('BlogPost', sprintf('"BlogPost%s"."ID" = "SiteTree%s"."ID"', $stage, $stage)) ->innerJoin(
->where(sprintf('"PublishDate" < \'%s\'', Convert::raw2sql(SS_Datetime::now()))); DataObject::getSchema()->tableName(BlogPost::class),
sprintf('"BlogPost%s"."ID" = "SiteTree%s"."ID"', $stage, $stage)
)
->where(sprintf('"PublishDate" < \'%s\'', Convert::raw2sql(DBDatetime::now())));
$staged = $staged->setDataQuery($dataQuery); $staged = $staged->setDataQuery($dataQuery);
} }
@ -40,7 +58,7 @@ class BlogFilter extends Lumberjack
*/ */
protected function subclassForBlog() protected function subclassForBlog()
{ {
return in_array(get_class($this->owner), ClassInfo::subClassesFor('Blog')); return in_array(get_class($this->owner), ClassInfo::subclassesFor(Blog::class));
} }
/** /**
@ -52,8 +70,11 @@ class BlogFilter extends Lumberjack
if (!$this->shouldFilter() && $this->isBlog() && !Permission::check('VIEW_DRAFT_CONTENT')) { if (!$this->shouldFilter() && $this->isBlog() && !Permission::check('VIEW_DRAFT_CONTENT')) {
$dataQuery = $staged->dataQuery() $dataQuery = $staged->dataQuery()
->innerJoin('BlogPost', '"BlogPost_Live"."ID" = "SiteTree_Live"."ID"') ->innerJoin(
->where(sprintf('"PublishDate" < \'%s\'', Convert::raw2sql(SS_Datetime::now()))); DataObject::getSchema()->tableName(BlogPost::class),
'"BlogPost_Live"."ID" = "SiteTree_Live"."ID"'
)
->where(sprintf('"PublishDate" < \'%s\'', Convert::raw2sql(DBDatetime::now())));
$staged = $staged->setDataQuery($dataQuery); $staged = $staged->setDataQuery($dataQuery);
} }
@ -82,33 +103,16 @@ class BlogFilter extends Lumberjack
'ClassName' => $excluded 'ClassName' => $excluded
)); ));
$gridField = new BlogFilter_GridField( $gridField = BlogFilterGridField::create(
'ChildPages', 'ChildPages',
$this->getLumberjackTitle(), $this->getLumberjackTitle(),
$pages, $pages,
$this->getLumberjackGridFieldConfig() $this->getLumberjackGridFieldConfig()
); );
$tab = new Tab('ChildPages', $this->getLumberjackTitle(), $gridField); $tab = Tab::create('ChildPages', $this->getLumberjackTitle(), $gridField);
$fields->insertBefore($tab, 'Main'); $fields->insertBefore($tab, 'Main');
} }
} }
} }
/**
* Enables children of non-editable pages to be edited.
*/
class BlogFilter_GridField extends GridField
{
/**
* @param FormTransformation $transformation
*
* @return $this
*/
public function transform(FormTransformation $transformation)
{
return $this;
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace SilverStripe\Blog\Model\BlogFilter;
use SilverStripe\Forms\FormTransformation;
use SilverStripe\Forms\GridField\GridField;
/**
* Enables children of non-editable pages to be edited.
*/
class BlogFilterGridField extends GridField
{
/**
* @param FormTransformation $transformation
*
* @return $this
*/
public function transform(FormTransformation $transformation)
{
return $this;
}
}

View File

@ -1,5 +1,18 @@
<?php <?php
namespace SilverStripe\Blog\Model;
use SilverStripe\Assets\Image;
use SilverStripe\Blog\Forms\GridField\GridFieldConfig_BlogPost;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\Tab;
use SilverStripe\ORM\DataExtension;
use SilverStripe\Security\Member;
use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\View\Requirements;
/** /**
* This class is responsible for add Blog specific behaviour to Members. * This class is responsible for add Blog specific behaviour to Members.
* *
@ -12,22 +25,22 @@ class BlogMemberExtension extends DataExtension
* @var array * @var array
*/ */
private static $db = array( private static $db = array(
'URLSegment' => 'Varchar', 'URLSegment' => 'Varchar',
'BlogProfileSummary' => 'Text', 'BlogProfileSummary' => 'Text'
); );
/** /**
* @var array * @var array
*/ */
private static $has_one = array( private static $has_one = array(
'BlogProfileImage' => 'Image', 'BlogProfileImage' => Image::class
); );
/** /**
* @var array * @var array
*/ */
private static $belongs_many_many = array( private static $belongs_many_many = array(
'BlogPosts' => 'BlogPost', 'BlogPosts' => BlogPost::class
); );
/** /**
@ -80,7 +93,6 @@ class BlogMemberExtension extends DataExtension
return $conflict->count() == 0; return $conflict->count() == 0;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -97,13 +109,13 @@ class BlogMemberExtension extends DataExtension
Requirements::css(BLOGGER_DIR . '/css/cms.css'); Requirements::css(BLOGGER_DIR . '/css/cms.css');
Requirements::javascript(BLOGGER_DIR . '/js/cms.js'); Requirements::javascript(BLOGGER_DIR . '/js/cms.js');
$tab = new Tab('BlogPosts', 'Blog Posts'); $tab = Tab::create('BlogPosts', 'Blog Posts');
$gridField = new GridField( $gridField = GridField::create(
'BlogPosts', 'BlogPosts',
'Blog Posts', 'Blog Posts',
$this->owner->BlogPosts(), $this->owner->BlogPosts(),
new GridFieldConfig_BlogPost() GridFieldConfig_BlogPost::create()
); );
$tab->Fields()->add($gridField); $tab->Fields()->add($gridField);

246
src/Model/BlogObject.php Normal file
View File

@ -0,0 +1,246 @@
<?php
namespace SilverStripe\Blog\Model;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Tab;
use SilverStripe\Forms\TabSet;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataList;
use SilverStripe\Security\Permission;
use SilverStripe\View\Parsers\URLSegmentFilter;
/**
* An object shared by BlogTag and BlogCategory.
*
* @package silverstripe
* @subpackage blog
*/
trait BlogObject
{
/**
* @return DataList
*/
public function BlogPosts()
{
$blogPosts = parent::BlogPosts();
$this->extend('updateGetBlogPosts', $blogPosts);
return $blogPosts;
}
/**
* {@inheritdoc}
*/
public function getCMSFields()
{
$fields = TabSet::create(
'Root',
Tab::create(
'Main',
TextField::create('Title', _t(self::class . '.Title', 'Title'))
)
);
$fields = FieldList::create($fields);
$this->extend('updateCMSFields', $fields);
return $fields;
}
/**
* {@inheritdoc}
* @return ValidationResult
*/
public function validate()
{
/** @var ValidationResult $validation */
$validation = parent::validate();
if (!$validation->isValid()) {
return $validation;
}
$blog = $this->Blog();
if (!$blog || !$blog->exists()) {
return $validation;
}
if ($this->getDuplicatesByField('Title')->count() > 0) {
$validation->addError($this->getDuplicateError(), self::DUPLICATE_EXCEPTION);
}
return $validation;
}
/**
* Returns a relative link to this category.
*
* @return string
*/
public function getLink()
{
return Controller::join_links(
$this->Blog()->Link(),
$this->getListUrlSegment(),
$this->URLSegment
);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canView($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canView($member);
}
/**
* {@inheritdoc}
*/
public function canCreate($member = null, $context = array())
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
$permission = Blog::config()->grant_user_permission;
return Permission::checkMember($member, $permission);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canDelete($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canDelete($member);
}
/**
* Inherits from the parent blog or can be overwritten using a DataExtension.
*
* @param null|Member $member
*
* @return bool
*/
public function canEdit($member = null)
{
$extended = $this->extendedCan(__FUNCTION__, $member);
if ($extended !== null) {
return $extended;
}
return $this->Blog()->canEdit($member);
}
/**
* {@inheritdoc}
*/
protected function onBeforeWrite()
{
parent::onBeforeWrite();
if ($this->exists() || empty($this->URLSegment)) {
return $this->generateURLSegment();
}
}
/**
* Generates a unique URLSegment from the title.
*
* @param int $increment
*
* @return string
*/
public function generateURLSegment($increment = 0)
{
$increment = (int) $increment;
$filter = URLSegmentFilter::create();
// Setting this to on. Because of the UI flow, it would be quite a lot of work
// to support turning this off. (ie. the add by title flow would not work).
// If this becomes a problem we can approach it then.
// @see https://github.com/silverstripe/silverstripe-blog/issues/376
$filter->setAllowMultibyte(true);
$this->URLSegment = $filter->filter($this->Title);
if ($increment > 0) {
$this->URLSegment .= '-' . $increment;
}
if ($this->getDuplicatesByField('URLSegment')->count() > 0) {
$this->generateURLSegment($increment + 1);
}
return $this->URLSegment;
}
/**
* Looks for objects o the same type and the same value by the given Field
*
* @param string $field E.g. URLSegment or Title
* @return DataList
*/
protected function getDuplicatesByField($field)
{
$duplicates = DataList::create(self::class)
->filter(
[
$field => $this->$field,
'BlogID' => (int) $this->BlogID
]
);
if ($this->ID) {
$duplicates = $duplicates->exclude('ID', $this->ID);
}
return $duplicates;
}
/**
* This returns the url segment for the listing page.
* eg. 'categories' in /my-blog/categories/category-url
*
* This is not editable at the moment, but a method is being used incase we want
* to make it editable in the future. We can use this method to provide logic
* without replacing multiple areas of the code base. We're also not being opinionated
* about how the segment should be obtained at the moment and allowing for the
* implementation to decide.
*
* @return string
*/
abstract protected function getListUrlSegment();
/**
* Returns an error message for this object when it tries to write a duplicate.
*
* @return string
*/
abstract protected function getDuplicateError();
}

View File

@ -1,5 +1,31 @@
<?php <?php
namespace SilverStripe\Blog\Model;
use Page;
use SilverStripe\Assets\Image;
use SilverStripe\Blog\Forms\BlogAdminSidebar;
use SilverStripe\Blog\Model\BlogCategory;
use SilverStripe\Blog\Model\BlogPostFilter;
use SilverStripe\Blog\Model\BlogTag;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\DatetimeField;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\ListboxField;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\ToggleCompositeField;
use SilverStripe\Forms\UploadField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\UnsavedRelationList;
use SilverStripe\Security\Group;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
use SilverStripe\TagField\TagField;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
/** /**
* An individual blog post. * An individual blog post.
* *
@ -24,59 +50,65 @@ class BlogPost extends Page
*/ */
private static $restrict_authors_to_group = false; private static $restrict_authors_to_group = false;
/**
* {@inheritDoc}
* @var string
*/
private static $table_name = 'BlogPost';
/** /**
* @var array * @var array
*/ */
private static $db = array( private static $db = array(
'PublishDate' => 'SS_Datetime', 'PublishDate' => 'Datetime',
'AuthorNames' => 'Varchar(1024)', 'AuthorNames' => 'Varchar(1024)',
'Summary' => 'HTMLText', 'Summary' => 'HTMLText'
); );
/** /**
* @var array * @var array
*/ */
private static $has_one = array( private static $has_one = array(
'FeaturedImage' => 'Image', 'FeaturedImage' => Image::class
); );
/** /**
* @var array * @var array
*/ */
private static $many_many = array( private static $many_many = array(
'Categories' => 'BlogCategory', 'Categories' => BlogCategory::class,
'Tags' => 'BlogTag', 'Tags' => BlogTag::class,
'Authors' => 'Member', 'Authors' => Member::class
); );
/** /**
* @var array * @var array
*/ */
private static $defaults = array( private static $defaults = array(
'ShowInMenus' => false, 'ShowInMenus' => false,
'InheritSideBar' => true, 'InheritSideBar' => true,
'ProvideComments' => true, 'ProvideComments' => true
); );
/** /**
* @var array * @var array
*/ */
private static $extensions = array( private static $extensions = array(
'BlogPostFilter', BlogPostFilter::class
); );
/** /**
* @var array * @var array
*/ */
private static $searchable_fields = array( private static $searchable_fields = array(
'Title', 'Title'
); );
/** /**
* @var array * @var array
*/ */
private static $summary_fields = array( private static $summary_fields = array(
'Title', 'Title'
); );
/** /**
@ -84,7 +116,7 @@ class BlogPost extends Page
*/ */
private static $casting = array( private static $casting = array(
'Excerpt' => 'HTMLText', 'Excerpt' => 'HTMLText',
'Date' => 'SS_Datetime', 'Date' => 'DBDatetime'
); );
/** /**
@ -174,9 +206,7 @@ class BlogPost extends Page
Requirements::css(BLOGGER_DIR . '/css/cms.css'); Requirements::css(BLOGGER_DIR . '/css/cms.css');
Requirements::javascript(BLOGGER_DIR . '/js/cms.js'); Requirements::javascript(BLOGGER_DIR . '/js/cms.js');
$self =& $this; $this->beforeUpdateCMSFields(function ($fields) {
$this->beforeUpdateCMSFields(function ($fields) use ($self) {
$uploadField = UploadField::create('FeaturedImage', _t('BlogPost.FeaturedImage', 'Featured Image')); $uploadField = UploadField::create('FeaturedImage', _t('BlogPost.FeaturedImage', 'Featured Image'));
$uploadField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif')); $uploadField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif'));
@ -204,10 +234,8 @@ class BlogPost extends Page
$fields->insertAfter($summaryHolder, 'FeaturedImage'); $fields->insertAfter($summaryHolder, 'FeaturedImage');
$fields->push(HiddenField::create('MenuTitle'));
$urlSegment = $fields->dataFieldByName('URLSegment'); $urlSegment = $fields->dataFieldByName('URLSegment');
$urlSegment->setURLPrefix($self->Parent()->RelativeLink()); $urlSegment->setURLPrefix($this->Parent()->RelativeLink());
$fields->removeFieldsFromTab('Root.Main', array( $fields->removeFieldsFromTab('Root.Main', array(
'MenuTitle', 'MenuTitle',
@ -217,35 +245,39 @@ class BlogPost extends Page
$authorField = ListboxField::create( $authorField = ListboxField::create(
'Authors', 'Authors',
_t('BlogPost.Authors', 'Authors'), _t('BlogPost.Authors', 'Authors'),
$self->getCandidateAuthors()->map()->toArray() $this->getCandidateAuthors()->map()->toArray()
)->setMultiple(true); );
$authorNames = TextField::create( $authorNames = TextField::create(
'AuthorNames', 'AuthorNames',
_t('BlogPost.AdditionalCredits', 'Additional Credits'), _t('BlogPost.AdditionalCredits', 'Additional Credits'),
null, null,
1024 1024
)->setDescription(_t( )->setDescription(
_t(
'BlogPost.AdditionalCredits_Description', 'BlogPost.AdditionalCredits_Description',
'If some authors of this post don\'t have CMS access, enter their name(s) here. You can separate multiple names with a comma.') 'If some authors of this post don\'t have CMS access, enter their name(s) here. You can separate multiple names with a comma.'
)
); );
if (!$self->canEditAuthors()) { if (!$this->canEditAuthors()) {
$authorField = $authorField->performDisabledTransformation(); $authorField = $authorField->performDisabledTransformation();
$authorNames = $authorNames->performDisabledTransformation(); $authorNames = $authorNames->performDisabledTransformation();
} }
$publishDate = DatetimeField::create('PublishDate', _t('BlogPost.PublishDate', 'Publish Date')); $publishDate = DatetimeField::create('PublishDate', _t('BlogPost.PublishDate', 'Publish Date'));
$publishDate->getDateField()->setConfig('showcalendar', true); $publishDate->getDateField()->setConfig('showcalendar', true);
if (!$self->PublishDate) { if (!$this->PublishDate) {
$publishDate->setDescription(_t( $publishDate->setDescription(
_t(
'BlogPost.PublishDate_Description', 'BlogPost.PublishDate_Description',
'Will be set to "now" if published without a value.') 'Will be set to "now" if published without a value.'
)
); );
} }
// Get categories and tags // Get categories and tags
$parent = $self->Parent(); $parent = $this->Parent();
$categories = $parent instanceof Blog $categories = $parent instanceof Blog
? $parent->Categories() ? $parent->Categories()
: BlogCategory::get(); : BlogCategory::get();
@ -253,32 +285,36 @@ class BlogPost extends Page
? $parent->Tags() ? $parent->Tags()
: BlogTag::get(); : BlogTag::get();
$options = BlogAdminSidebar::create( // @todo: Reimplement the sidebar
$publishDate, // $options = BlogAdminSidebar::create(
$urlSegment, $fields->addFieldsToTab(
TagField::create( 'Root.PostOptions',
'Categories', [
_t('BlogPost.Categories', 'Categories'), $publishDate,
$categories, $urlSegment,
$self->Categories() TagField::create(
) 'Categories',
->setCanCreate($self->canCreateCategories()) _t('BlogPost.Categories', 'Categories'),
->setShouldLazyLoad(true), $categories,
TagField::create( $this->Categories()
'Tags', )
_t('BlogPost.Tags', 'Tags'), ->setCanCreate($this->canCreateCategories())
$tags, ->setShouldLazyLoad(true),
$self->Tags() TagField::create(
) 'Tags',
->setCanCreate($self->canCreateTags()) _t('BlogPost.Tags', 'Tags'),
->setShouldLazyLoad(true), $tags,
$authorField, $this->Tags()
$authorNames )
)->setTitle('Post Options'); ->setCanCreate($this->canCreateTags())
->setShouldLazyLoad(true),
$options->setName('blog-admin-sidebar'); $authorField,
$authorNames
$fields->insertBefore($options, 'Root'); ]
);
// )->setTitle('Post Options');
// $options->setName('blog-admin-sidebar');
// $fields->insertBefore($options, 'Root');
}); });
$fields = parent::getCMSFields(); $fields = parent::getCMSFields();
@ -297,11 +333,11 @@ class BlogPost extends Page
{ {
if ($this->config()->restrict_authors_to_group) { if ($this->config()->restrict_authors_to_group) {
return Group::get()->filter('Code', $this->config()->restrict_authors_to_group)->first()->Members(); return Group::get()->filter('Code', $this->config()->restrict_authors_to_group)->first()->Members();
} else {
$list = Member::get();
$this->extend('updateCandidateAuthors', $list);
return $list;
} }
$list = Member::get();
$this->extend('updateCandidateAuthors', $list);
return $list;
} }
/** /**
@ -414,12 +450,12 @@ class BlogPost extends Page
public function onBeforePublish() public function onBeforePublish()
{ {
/** /**
* @var SS_Datetime $publishDate * @var DBDatetime $publishDate
*/ */
$publishDate = $this->dbObject('PublishDate'); $publishDate = $this->dbObject('PublishDate');
if (!$publishDate->getValue()) { if (!$publishDate->getValue()) {
$this->PublishDate = SS_Datetime::now()->getValue(); $this->PublishDate = DBDatetime::now()->getValue();
$this->write(); $this->write();
} }
} }
@ -461,15 +497,15 @@ class BlogPost extends Page
return false; return false;
} }
if($this->canEdit($member)) { if ($this->canEdit($member)) {
return true; return true;
} }
/** /**
* @var SS_Datetime $publishDate * @var DBDatetime $publishDate
*/ */
$publishDate = $this->dbObject('PublishDate'); $publishDate = $this->dbObject('PublishDate');
if(!$publishDate->exists()) { if (!$publishDate->exists()) {
return false; return false;
} }
@ -565,7 +601,7 @@ class BlogPost extends Page
public function getMonthlyArchiveLink($type = 'day') public function getMonthlyArchiveLink($type = 'day')
{ {
/** /**
* @var SS_Datetime $date * @var DBDatetime $date
*/ */
$date = $this->dbObject('PublishDate'); $date = $this->dbObject('PublishDate');
@ -593,7 +629,7 @@ class BlogPost extends Page
public function getYearlyArchiveLink() public function getYearlyArchiveLink()
{ {
/** /**
* @var SS_Datetime $date * @var DBDatetime $date
*/ */
$date = $this->dbObject('PublishDate'); $date = $this->dbObject('PublishDate');
@ -607,7 +643,7 @@ class BlogPost extends Page
*/ */
public function getCredits() public function getCredits()
{ {
$list = new ArrayList(); $list = ArrayList::create();
$list->merge($this->getDynamicCredits()); $list->merge($this->getDynamicCredits());
$list->merge($this->getStaticCredits()); $list->merge($this->getStaticCredits());
@ -708,11 +744,3 @@ class BlogPost extends Page
} }
} }
} }
/**
* @package silverstripe
* @subpackage blog
*/
class BlogPost_Controller extends Page_Controller
{
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\Blog\Model;
use PageController;
/**
* @package silverstripe
* @subpackage blog
*/
class BlogPostController extends PageController
{
}

View File

@ -0,0 +1,66 @@
<?php
namespace SilverStripe\Blog\Model;
use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Convert;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataQuery;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\Queries\SQLSelect;
use SilverStripe\ORM\Versioning\Versioned;
use SilverStripe\Security\Permission;
/**
* This is responsible for filtering only published posts to users who do not have permission to
* view non-published posts.
*
* @package silverstripe
* @subpackage blog
*/
class BlogPostFilter extends DataExtension
{
/**
* Augment queries so that we don't fetch unpublished articles.
*
* @param SQLQuery $query
*/
public function augmentSQL(SQLSelect $query, DataQuery $dataQuery = null)
{
$stage = Versioned::get_stage();
if (Controller::curr() instanceof LeftAndMain) {
return;
}
if ($stage == 'Live' || !Permission::check('VIEW_DRAFT_CONTENT')) {
$query->addWhere(sprintf(
'"PublishDate" < \'%s\'',
Convert::raw2sql(DBDatetime::now())
));
}
}
/**
* {@inheritDoc}
*
* This is a fix so that when we try to fetch subclasses of BlogPost, lazy loading includes the
* BlogPost table in its query. Leaving this table out means the default sort order column
* PublishDate causes an error.
*
* @see https://github.com/silverstripe/silverstripe-framework/issues/1682
*
* @param SQLSelect $query
* @param DataQuery $dataQuery
* @param DataObject $dataObject
*/
public function augmentLoadLazyFields(SQLSelect &$query, DataQuery &$dataQuery = null, $dataObject)
{
$dataQuery->innerJoin(
DataObject::getSchema()->tableName(BlogPost::class),
'"SiteTree"."ID" = "BlogPost"."ID"'
);
}
}

View File

@ -1,5 +1,9 @@
<?php <?php
namespace SilverStripe\Blog\Model;
use SilverStripe\ORM\DataExtension;
/** /**
* Customise blog post to support comment notifications. * Customise blog post to support comment notifications.
* *

79
src/Model/BlogTag.php Normal file
View File

@ -0,0 +1,79 @@
<?php
namespace SilverStripe\Blog\Model;
use SilverStripe\ORM\DataObject;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogObject;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Blog\Model\CategorisationObject;
/**
* A blog tag for keyword descriptions of a blog post.
*
* @package silverstripe
* @subpackage blog
*
* @method Blog Blog()
*
* @property string $Title
* @property string $URLSegment
* @property int $BlogID
*/
class BlogTag extends DataObject implements CategorisationObject
{
use BlogObject;
/**
* Use an exception code so that attempted writes can continue on
* duplicate errors.
*
* @const string
* This must be a string because ValidationException has decided we can't use int
*/
const DUPLICATE_EXCEPTION = 'DUPLICATE';
/**
* {@inheritDoc}
* @var string
*/
private static $table_name = 'BlogTag';
/**
* @var array
*/
private static $db = array(
'Title' => 'Varchar(255)',
'URLSegment' => 'Varchar(255)'
);
/**
* @var array
*/
private static $has_one = array(
'Blog' => Blog::class
);
/**
* @var array
*/
private static $belongs_many_many = array(
'BlogPosts' => BlogPost::class
);
/**
* {@inheritdoc}
*/
protected function getListUrlSegment()
{
return 'tag';
}
/**
* {@inheritdoc}
*/
protected function getDuplicateError()
{
return _t('BlogTag.Duplicate', 'A blog tag already exists with that name.');
}
}

View File

@ -1,8 +1,11 @@
<?php <?php
namespace SilverStripe\Blog\Model;
/** /**
* @method ManyManyList BlogPosts * @method ManyManyList BlogPosts
*/ */
interface CategorisationObject interface CategorisationObject
{ {
} }

View File

@ -1,9 +1,17 @@
<?php <?php
if (!class_exists('Widget')) { namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return; return;
} }
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\NumericField;
use SilverStripe\Widgets\Model\Widget;
/** /**
* @method Blog Blog() * @method Blog Blog()
* *
@ -46,7 +54,7 @@ class BlogArchiveWidget extends Widget
* @var array * @var array
*/ */
private static $has_one = array( private static $has_one = array(
'Blog' => 'Blog', 'Blog' => Blog::class,
); );
/** /**
@ -54,13 +62,11 @@ class BlogArchiveWidget extends Widget
*/ */
public function getCMSFields() public function getCMSFields()
{ {
$self =& $this; $this->beforeUpdateCMSFields(function ($fields) {
$this->beforeUpdateCMSFields(function ($fields) use ($self) {
/** /**
* @var Enum $archiveType * @var Enum $archiveType
*/ */
$archiveType = $self->dbObject('ArchiveType'); $archiveType = $this->dbObject('ArchiveType');
$type = $archiveType->enumValues(); $type = $archiveType->enumValues();
@ -72,7 +78,11 @@ class BlogArchiveWidget extends Widget
* @var FieldList $fields * @var FieldList $fields
*/ */
$fields->merge(array( $fields->merge(array(
DropdownField::create('BlogID', _t('BlogArchiveWidget.Blog', 'Blog'), Blog::get()->map()), DropdownField::create(
'BlogID',
_t('BlogArchiveWidget.Blog', 'Blog'),
Blog::get()->map()
),
DropdownField::create('ArchiveType', _t('BlogArchiveWidget.ArchiveType', 'ArchiveType'), $type), DropdownField::create('ArchiveType', _t('BlogArchiveWidget.ArchiveType', 'ArchiveType'), $type),
NumericField::create('NumberToDisplay', _t('BlogArchiveWidget.NumberToDisplay', 'No. to Display')) NumericField::create('NumberToDisplay', _t('BlogArchiveWidget.NumberToDisplay', 'No. to Display'))
)); ));
@ -132,7 +142,3 @@ class BlogArchiveWidget extends Widget
return $archive; return $archive;
} }
} }
class BlogArchiveWidget_Controller extends Widget_Controller
{
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return;
}
use SilverStripe\Widgets\Controllers\WidgetController;
class BlogArchiveWidgetController extends WidgetController
{
}

View File

@ -0,0 +1,127 @@
<?php
namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return;
}
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\NumericField;
use SilverStripe\Widgets\Model\Widget;
/**
* @method Blog Blog()
*/
class BlogCategoriesWidget extends Widget
{
/**
* @var string
*/
private static $title = 'Categories';
/**
* @var string
*/
private static $cmsTitle = 'Blog Categories';
/**
* @var string
*/
private static $description = 'Displays a list of blog categories.';
/**
* @var array
*/
private static $db = array(
'Limit' => 'Int',
'Order' => 'Varchar',
'Direction' => 'Varchar',
);
/**
* @var array
*/
private static $has_one = array(
'Blog' => Blog::class,
);
/**
* {@inheritdoc}
*/
public function getCMSFields()
{
$this->beforeUpdateCMSFields(function (FieldList $fields) {
$fields[] = DropdownField::create(
'BlogID',
_t('BlogCategoriesWidget.Blog', 'Blog'),
Blog::get()->map()
);
$fields[] = NumericField::create(
'Limit',
_t('BlogCategoriesWidget.Limit.Label', 'Limit'),
0
)
->setDescription(
_t(
'BlogCategoriesWidget.Limit.Description',
'Limit the number of categories shown by this widget (set to 0 to show all categories).'
)
)
->setMaxLength(3);
$fields[] = DropdownField::create(
'Order',
_t('BlogCategoriesWidget.Sort.Label', 'Sort'),
array('Title' => 'Title', 'Created' => 'Created', 'LastEdited' => 'Updated')
)
->setDescription(
_t('BlogCategoriesWidget.Sort.Description', 'Change the order of categories shown by this widget.')
);
$fields[] = DropdownField::create(
'Direction',
_t('BlogCategoriesWidget.Direction.Label', 'Direction'),
array('ASC' => 'Ascending', 'DESC' => 'Descending')
)
->setDescription(
_t(
'BlogCategoriesWidget.Direction.Description',
'Change the direction of ordering of categories shown by this widget.'
)
);
});
return parent::getCMSFields();
}
/**
* @return DataList
*/
public function getCategories()
{
$blog = $this->Blog();
if (!$blog) {
return array();
}
$query = $blog->Categories();
if ($this->Limit) {
$query = $query->limit(Convert::raw2sql($this->Limit));
}
if ($this->Order && $this->Direction) {
$query = $query->sort(Convert::raw2sql($this->Order), Convert::raw2sql($this->Direction));
}
return $query;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return;
}
use SilverStripe\Widgets\Controllers\WidgetController;
class BlogCategoriesWidgetController extends WidgetController
{
}

View File

@ -1,9 +1,16 @@
<?php <?php
if (!class_exists("Widget")) { namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return; return;
} }
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\NumericField;
use SilverStripe\Widgets\Model\Widget;
/** /**
* @method Blog Blog() * @method Blog Blog()
* *
@ -37,7 +44,7 @@ class BlogRecentPostsWidget extends Widget
* @var array * @var array
*/ */
private static $has_one = array( private static $has_one = array(
'Blog' => 'Blog', 'Blog' => Blog::class,
); );
/** /**
@ -74,7 +81,3 @@ class BlogRecentPostsWidget extends Widget
return array(); return array();
} }
} }
class BlogRecentPostsWidget_Controller extends Widget_Controller
{
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return;
}
use SilverStripe\Widgets\Controllers\WidgetController;
class BlogRecentPostsWidgetController extends WidgetController
{
}

View File

@ -1,9 +1,19 @@
<?php <?php
if (!class_exists('Widget')) { namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return; return;
} }
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\DropdownField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\Widgets\Model\Widget;
/** /**
* @method Blog Blog() * @method Blog Blog()
*/ */
@ -33,7 +43,7 @@ class BlogTagsCloudWidget extends Widget
* @var array * @var array
*/ */
private static $has_one = array( private static $has_one = array(
'Blog' => 'Blog', 'Blog' => Blog::class,
); );
/** /**
@ -46,8 +56,11 @@ class BlogTagsCloudWidget extends Widget
* @var FieldList $fields * @var FieldList $fields
*/ */
$fields->push( $fields->push(
DropdownField::create('BlogID', _t('BlogTagsCloudWidget.Blog', DropdownField::create(
'Blog'), Blog::get()->map()) 'BlogID',
_t('BlogTagsCloudWidget.Blog', 'Blog'),
Blog::get()->map()
)
); );
}); });
@ -105,7 +118,3 @@ class BlogTagsCloudWidget extends Widget
return array(); return array();
} }
} }
class BlogTagsCloudWidget_Controller extends Widget_Controller
{
}

View File

@ -0,0 +1,13 @@
<?php
namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return;
}
use SilverStripe\Widgets\Controllers\WidgetController;
class BlogTagsCloudWidgetController extends WidgetController
{
}

View File

@ -1,9 +1,18 @@
<?php <?php
if (!class_exists("Widget")) { namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return; return;
} }
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\NumericField;
use SilverStripe\Widgets\Model\Widget;
/** /**
* @method Blog Blog() * @method Blog Blog()
*/ */
@ -37,7 +46,7 @@ class BlogTagsWidget extends Widget
* @var array * @var array
*/ */
private static $has_one = array( private static $has_one = array(
'Blog' => 'Blog', 'Blog' => Blog::class
); );
/** /**
@ -47,24 +56,44 @@ class BlogTagsWidget extends Widget
{ {
$this->beforeUpdateCMSFields(function (Fieldlist $fields) { $this->beforeUpdateCMSFields(function (Fieldlist $fields) {
$fields[] = DropdownField::create( $fields[] = DropdownField::create(
'BlogID', _t('BlogTagsWidget.Blog', 'Blog'), Blog::get()->map() 'BlogID',
_t('BlogTagsWidget.Blog', 'Blog'),
Blog::get()->map()
); );
$fields[] = NumericField::create( $fields[] = NumericField::create(
'Limit', _t('BlogTagsWidget.Limit.Label', 'Limit'), 0 'Limit',
_t('BlogTagsWidget.Limit.Label', 'Limit'),
0
) )
->setDescription(_t('BlogTagsWidget.Limit.Description', 'Limit the number of tags shown by this widget (set to 0 to show all tags).')) ->setDescription(
_t(
'BlogTagsWidget.Limit.Description',
'Limit the number of tags shown by this widget (set to 0 to show all tags).'
)
)
->setMaxLength(3); ->setMaxLength(3);
$fields[] = DropdownField::create( $fields[] = DropdownField::create(
'Order', _t('BlogTagsWidget.Sort.Label', 'Sort'), array('Title' => 'Title', 'Created' => 'Created', 'LastEdited' => 'Updated') 'Order',
_t('BlogTagsWidget.Sort.Label', 'Sort'),
array('Title' => 'Title', 'Created' => 'Created', 'LastEdited' => 'Updated')
) )
->setDescription(_t('BlogTagsWidget.Sort.Description', 'Change the order of tags shown by this widget.')); ->setDescription(
_t('BlogTagsWidget.Sort.Description', 'Change the order of tags shown by this widget.')
);
$fields[] = DropdownField::create( $fields[] = DropdownField::create(
'Direction', _t('BlogTagsWidget.Direction.Label', 'Direction'), array('ASC' => 'Ascending', 'DESC' => 'Descending') 'Direction',
_t('BlogTagsWidget.Direction.Label', 'Direction'),
array('ASC' => 'Ascending', 'DESC' => 'Descending')
) )
->setDescription(_t('BlogTagsWidget.Direction.Description', 'Change the direction of ordering of tags shown by this widget.')); ->setDescription(
_t(
'BlogTagsWidget.Direction.Description',
'Change the direction of ordering of tags shown by this widget.'
)
);
}); });
return parent::getCMSFields(); return parent::getCMSFields();
@ -94,7 +123,3 @@ class BlogTagsWidget extends Widget
return $query; return $query;
} }
} }
class BlogTagsWidget_Controller extends Widget_Controller
{
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\Blog\Widgets;
if (!class_exists('\\SilverStripe\\Widgets\\Model\\Widget')) {
return;
}
use SilverStripe\Widgets\Controllers\WidgetController;
class BlogTagsWidgetController extends WidgetController
{
}

View File

@ -1,31 +1,39 @@
<p class="blog-post-meta"> <p class="blog-post-meta">
<% if $Categories.exists %> <% if $Categories.exists %>
<%t Blog.PostedIn "Posted in" %> <%t Blog.PostedIn "Posted in" %>
<% loop $Categories %> <% loop $Categories %>
<a href="$Link" title="$Title">$Title</a><% if not Last %>, <% else %>;<% end_if %> <a href="$Link" title="$Title">$Title</a><% if not Last %>, <% else %>;<% end_if %>
<% end_loop %> <% end_loop %>
<% end_if %> <% end_if %>
<% if $Tags.exists %> <% if $Tags.exists %>
<%t Blog.Tagged "Tagged" %> <%t Blog.Tagged "Tagged" %>
<% loop $Tags %> <% loop $Tags %>
<a href="$Link" title="$Title">$Title</a><% if not Last %>, <% else %>;<% end_if %> <a href="$Link" title="$Title">$Title</a><% if not Last %>, <% else %>;<% end_if %>
<% end_loop %> <% end_loop %>
<% end_if %> <% end_if %>
<% if $Comments.exists %> <% if $Comments.exists %>
<a href="{$Link}#comments-holder"> <a href="{$Link}#comments-holder">
<%t Blog.Comments "Comments" %> <%t Blog.Comments "Comments" %>
$Comments.count $Comments.count
</a>; </a>;
<% end_if %> <% end_if %>
<%t Blog.Posted "Posted" %> <%t Blog.Posted "Posted" %>
<a href="$MonthlyArchiveLink">$PublishDate.ago</a> <a href="$MonthlyArchiveLink">$PublishDate.ago</a>
<% if $Credits %> <% if $Credits %>
<%t Blog.By "by" %> <%t Blog.By "by" %>
<% loop $Credits %><% if not $First && not $Last %>, <% end_if %><% if not $First && $Last %> <%t Blog.AND "and" %> <% end_if %><% if $URLSegment %><a href="$URL">$Name.XML</a><% else %>$Name.XML<% end_if %><% end_loop %>
<% end_if %>
<% loop $Credits %>
<% if not $First && not $Last %>, <% end_if %>
<% if not $First && $Last %> <%t Blog.AND "and" %> <% end_if %>
<% if $URLSegment %>
<a href="$URL">$Name.XML</a>
<% else %>
$Name.XML
<% end_if %>
<% end_loop %>
<% end_if %>
</p> </p>

View File

@ -3,7 +3,7 @@
<div> <div>
<% if $CurrentProfile.BlogProfileImage %> <% if $CurrentProfile.BlogProfileImage %>
<div class="profile-image"> <div class="profile-image">
$CurrentProfile.BlogProfileImage.setWidth(180) $CurrentProfile.BlogProfileImage.ScaleWidth(180)
</div> </div>
<% end_if %> <% end_if %>
<div class="profile-summary"> <div class="profile-summary">

View File

@ -8,7 +8,7 @@
<p class="post-image"> <p class="post-image">
<a href="$Link" title="<%t Blog.ReadMoreAbout "Read more about '{title}'..." title=$Title %>"> <a href="$Link" title="<%t Blog.ReadMoreAbout "Read more about '{title}'..." title=$Title %>">
$FeaturedImage.setWidth(795) $FeaturedImage.ScaleWidth(795)
</a> </a>
</p> </p>

View File

@ -5,7 +5,7 @@
<h1>$Title</h1> <h1>$Title</h1>
<% if $FeaturedImage %> <% if $FeaturedImage %>
<p class="post-image">$FeaturedImage.setWidth(795)</p> <p class="post-image">$FeaturedImage.ScaleWidth(795)</p>
<% end_if %> <% end_if %>
<div class="content">$Content</div> <div class="content">$Content</div>

View File

@ -1,5 +1,17 @@
<?php <?php
namespace SilverStripe\Blog\Tests;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogCategory;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Blog\Model\BlogTag;
use SilverStripe\Control\Controller;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\ValidationException;
use SilverStripe\Security\Member;
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
@ -8,7 +20,7 @@ class BlogCategoryTest extends FunctionalTest
/** /**
* @var string * @var string
*/ */
public static $fixture_file = 'blog.yml'; protected static $fixture_file = 'blog.yml';
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -17,7 +29,7 @@ class BlogCategoryTest extends FunctionalTest
{ {
parent::setUp(); parent::setUp();
SS_Datetime::set_mock_now('2013-10-10 20:00:00'); DBDatetime::set_mock_now('2013-10-10 20:00:00');
} }
/** /**
@ -25,7 +37,7 @@ class BlogCategoryTest extends FunctionalTest
*/ */
public function tearDown() public function tearDown()
{ {
SS_Datetime::clear_mock_now(); DBDatetime::clear_mock_now();
parent::tearDown(); parent::tearDown();
} }
@ -42,12 +54,12 @@ class BlogCategoryTest extends FunctionalTest
$member->logout(); $member->logout();
} }
$this->objFromFixture('BlogPost', 'FirstBlogPost'); $this->objFromFixture(BlogPost::class, 'FirstBlogPost');
/** /**
* @var BlogCategory $category * @var BlogCategory $category
*/ */
$category = $this->objFromFixture('BlogCategory', 'FirstCategory'); $category = $this->objFromFixture(BlogCategory::class, 'FirstCategory');
$this->assertEquals(5, $category->BlogPosts()->count(), 'Category blog post count'); $this->assertEquals(5, $category->BlogPosts()->count(), 'Category blog post count');
} }
@ -57,7 +69,7 @@ class BlogCategoryTest extends FunctionalTest
*/ */
public function testAllowMultibyteUrlSegment() public function testAllowMultibyteUrlSegment()
{ {
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$cat = new BlogCategory(); $cat = new BlogCategory();
$cat->BlogID = $blog->ID; $cat->BlogID = $blog->ID;
$cat->Title = 'تست'; $cat->Title = 'تست';
@ -72,10 +84,10 @@ class BlogCategoryTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$this->objFromFixture('Member', 'Admin'); $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$category = $this->objFromFixture('BlogCategory', 'SecondCategory'); $category = $this->objFromFixture(BlogCategory::class, 'SecondCategory');
$this->assertFalse($category->canView($editor), 'Editor should not be able to view category.'); $this->assertFalse($category->canView($editor), 'Editor should not be able to view category.');
} }
@ -87,20 +99,20 @@ class BlogCategoryTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$admin = $this->objFromFixture('Member', 'Admin'); $admin = $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$category = $this->objFromFixture('BlogCategory', 'FirstCategory'); $category = $this->objFromFixture(BlogCategory::class, 'FirstCategory');
$this->assertTrue($category->canEdit($admin), 'Admin should be able to edit category.'); $this->assertTrue($category->canEdit($admin), 'Admin should be able to edit category.');
$this->assertTrue($category->canEdit($editor), 'Editor should be able to edit category.'); $this->assertTrue($category->canEdit($editor), 'Editor should be able to edit category.');
$category = $this->objFromFixture('BlogCategory', 'SecondCategory'); $category = $this->objFromFixture(BlogCategory::class, 'SecondCategory');
$this->assertTrue($category->canEdit($admin), 'Admin should be able to edit category.'); $this->assertTrue($category->canEdit($admin), 'Admin should be able to edit category.');
$this->assertFalse($category->canEdit($editor), 'Editor should not be able to edit category.'); $this->assertFalse($category->canEdit($editor), 'Editor should not be able to edit category.');
$category = $this->objFromFixture('BlogCategory', 'ThirdCategory'); $category = $this->objFromFixture(BlogCategory::class, 'ThirdCategory');
$this->assertTrue($category->canEdit($admin), 'Admin should always be able to edit category.'); $this->assertTrue($category->canEdit($admin), 'Admin should always be able to edit category.');
$this->assertTrue($category->canEdit($editor), 'Editor should be able to edit category.'); $this->assertTrue($category->canEdit($editor), 'Editor should be able to edit category.');
@ -110,10 +122,10 @@ class BlogCategoryTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$admin = $this->objFromFixture('Member', 'Admin'); $admin = $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$category = singleton('BlogCategory'); $category = singleton(BlogCategory::class);
$this->assertTrue($category->canCreate($admin), 'Admin should be able to create category.'); $this->assertTrue($category->canCreate($admin), 'Admin should be able to create category.');
$this->assertTrue($category->canCreate($editor), 'Editor should be able to create category.'); $this->assertTrue($category->canCreate($editor), 'Editor should be able to create category.');
@ -123,24 +135,25 @@ class BlogCategoryTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$admin = $this->objFromFixture('Member', 'Admin'); $admin = $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$category = $this->objFromFixture('BlogCategory', 'FirstCategory'); $category = $this->objFromFixture(BlogCategory::class, 'FirstCategory');
$this->assertTrue($category->canDelete($admin), 'Admin should be able to delete category.'); $this->assertTrue($category->canDelete($admin), 'Admin should be able to delete category.');
$this->assertTrue($category->canDelete($editor), 'Editor should be able to category category.'); $this->assertTrue($category->canDelete($editor), 'Editor should be able to category category.');
$category = $this->objFromFixture('BlogCategory', 'SecondCategory'); $category = $this->objFromFixture(BlogCategory::class, 'SecondCategory');
$this->assertTrue($category->canDelete($admin), 'Admin should be able to delete category.'); $this->assertTrue($category->canDelete($admin), 'Admin should be able to delete category.');
$this->assertFalse($category->canDelete($editor), 'Editor should not be able to delete category.'); $this->assertFalse($category->canDelete($editor), 'Editor should not be able to delete category.');
$category = $this->objFromFixture('BlogCategory', 'ThirdCategory'); $category = $this->objFromFixture(BlogCategory::class, 'ThirdCategory');
$this->assertTrue($category->canDelete($admin), 'Admin should always be able to delete category.'); $this->assertTrue($category->canDelete($admin), 'Admin should always be able to delete category.');
$this->assertTrue($category->canDelete($editor), 'Editor should be able to delete category.'); $this->assertTrue($category->canDelete($editor), 'Editor should be able to delete category.');
} }
public function testDuplicateCategories() { public function testDuplicateCategories()
{
$blog = new Blog(); $blog = new Blog();
$blog->Title = 'Testing for duplicate categories'; $blog->Title = 'Testing for duplicate categories';
$blog->write(); $blog->write();
@ -148,18 +161,20 @@ class BlogCategoryTest extends FunctionalTest
$category = new BlogCategory(); $category = new BlogCategory();
$category->Title = 'Test'; $category->Title = 'Test';
$category->BlogID = $blog->ID; $category->BlogID = $blog->ID;
$category->URLSegment = 'test';
$category->write(); $category->write();
$category = new BlogCategory(); $category = new BlogCategory();
$category->Title = 'Test'; $category->Title = 'Test';
$category->URLSegment = 'test';
$category->BlogID = $blog->ID; $category->BlogID = $blog->ID;
try { try {
$category->write(); $category->write();
$this->fail('Duplicate BlogCategory written'); $this->fail('Duplicate BlogCategory written');
} catch (ValidationException $e) { } catch (ValidationException $e) {
$codeList = $e->getResult()->codeList(); $messages = $e->getResult()->getMessages();
$this->assertCount(1, $codeList); $this->assertCount(1, $messages);
$this->assertEquals(BlogTag::DUPLICATE_EXCEPTION, $codeList[0]); $this->assertEquals(BlogTag::DUPLICATE_EXCEPTION, $messages[0]['messageType']);
} }
} }
} }

View File

@ -1,29 +1,41 @@
<?php <?php
namespace SilverStripe\Blog\Tests;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Security\Member;
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
* @coversDefaultClass \SilverStripe\Blog\Model\BlogPostFilter
*/ */
class BlogPostFilterTest extends SapphireTest class BlogPostFilterTest extends SapphireTest
{ {
/** /**
* @var string * @var string
*/ */
public static $fixture_file = 'blog.yml'; protected static $fixture_file = 'blog.yml';
public function setUp() public function setUp()
{ {
parent::setUp(); parent::setUp();
SS_Datetime::set_mock_now('2013-10-10 20:00:00'); DBDatetime::set_mock_now('2013-10-10 20:00:00');
} }
public function tearDown() public function tearDown()
{ {
SS_Datetime::clear_mock_now(); DBDatetime::clear_mock_now();
parent::tearDown(); parent::tearDown();
} }
/**
* Tests that unpublished articles are not returned
* @covers ::augmentSQL
*/
public function testFilter() public function testFilter()
{ {
$member = Member::currentUser(); $member = Member::currentUser();
@ -35,11 +47,11 @@ class BlogPostFilterTest extends SapphireTest
/** /**
* @var Blog $blog * @var Blog $blog
*/ */
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$this->assertEquals(3, $blog->AllChildren()->Count(), 'Filtered blog posts'); $this->assertEquals(3, $blog->AllChildren()->Count(), 'Filtered blog posts');
SS_Datetime::set_mock_now('2020-01-01 00:00:00'); DBDatetime::set_mock_now('2020-01-01 00:00:00');
$this->assertEquals(5, $blog->AllChildren()->Count(), 'Unfiltered blog posts'); $this->assertEquals(5, $blog->AllChildren()->Count(), 'Unfiltered blog posts');
} }

View File

@ -1,11 +1,17 @@
<?php <?php
namespace SilverStripe\Blog\Tests;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Dev\SapphireTest;
class BlogPostNotificationsTest extends SapphireTest class BlogPostNotificationsTest extends SapphireTest
{ {
/** /**
* {@inheritDoc}
* @var string * @var string
*/ */
public static $fixture_file = 'blog.yml'; protected static $fixture_file = 'blog.yml';
public function testUpdateNotificationRecipients() public function testUpdateNotificationRecipients()
{ {
@ -13,8 +19,8 @@ class BlogPostNotificationsTest extends SapphireTest
$this->markTestSkipped('Comments Notification module is not installed'); $this->markTestSkipped('Comments Notification module is not installed');
} }
$blogPost = $this->objFromFixture('BlogPost', 'PostC'); $blogPost = $this->objFromFixture(BlogPost::class, 'PostC');
$comment = new Comment(); $comment = new \SilverStripe\Comments\Model\Comment();
$comment->Comment = 'This is a comment'; $comment->Comment = 'This is a comment';
$comment->write(); $comment->write();
$recipients = $blogPost->notificationRecipients( $recipients = $blogPost->notificationRecipients(
@ -27,8 +33,10 @@ class BlogPostNotificationsTest extends SapphireTest
} }
sort($segments); sort($segments);
$this->assertEquals(array('blog-contributor', 'blog-editor', $this->assertEquals(
'blog-writer', ), $segments); array('blog-contributor', 'blog-editor', 'blog-writer'),
$segments
);
} }
public function testUpdateNotificationSubject() public function testUpdateNotificationSubject()
@ -36,8 +44,8 @@ class BlogPostNotificationsTest extends SapphireTest
if (!class_exists('CommentNotifier')) { if (!class_exists('CommentNotifier')) {
$this->markTestSkipped('Comments Notification module is not installed'); $this->markTestSkipped('Comments Notification module is not installed');
} }
$blogPost = $this->objFromFixture('BlogPost', 'PostC'); $blogPost = $this->objFromFixture(BlogPost::class, 'PostC');
$comment = new Comment(); $comment = new SilverStripe\Comments\Model\Comment();
$comment->Comment = 'This is a comment'; $comment->Comment = 'This is a comment';
$comment->write(); $comment->write();
$recipients = $blogPost->notificationRecipients( $recipients = $blogPost->notificationRecipients(

View File

@ -1,26 +1,27 @@
<?php <?php
namespace SilverStripe\Blog\Tests;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Security\Member;
class BlogPostTest extends SapphireTest class BlogPostTest extends SapphireTest
{ {
/** /**
* {@inheritDoc}
* @var string * @var string
*/ */
public static $fixture_file = 'blog.yml'; protected static $fixture_file = 'blog.yml';
/**
* {@inheritdoc}
*/
public function setUp()
{
parent::setUp();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function tearDown() public function tearDown()
{ {
SS_Datetime::clear_mock_now(); DBDatetime::clear_mock_now();
parent::tearDown(); parent::tearDown();
} }
@ -29,12 +30,15 @@ class BlogPostTest extends SapphireTest
*/ */
public function testCanView($date, $user, $page, $canView) public function testCanView($date, $user, $page, $canView)
{ {
$userRecord = $this->objFromFixture('Member', $user); $userRecord = $this->objFromFixture(Member::class, $user);
$pageRecord = $this->objFromFixture('BlogPost', $page); $pageRecord = $this->objFromFixture(BlogPost::class, $page);
SS_Datetime::set_mock_now($date); DBDatetime::set_mock_now($date);
$this->assertEquals($canView, $pageRecord->canView($userRecord)); $this->assertEquals($canView, $pageRecord->canView($userRecord));
} }
/**
* @return array
*/
public function canViewProvider() public function canViewProvider()
{ {
$someFutureDate = '2013-10-10 20:00:00'; $someFutureDate = '2013-10-10 20:00:00';
@ -70,12 +74,12 @@ class BlogPostTest extends SapphireTest
public function testCandidateAuthors() public function testCandidateAuthors()
{ {
$blogpost = $this->objFromFixture('BlogPost', 'PostC'); $blogpost = $this->objFromFixture(BlogPost::class, 'PostC');
$this->assertEquals(7, $blogpost->getCandidateAuthors()->count()); $this->assertEquals(7, $blogpost->getCandidateAuthors()->count());
//Set the group to draw Members from //Set the group to draw Members from
Config::inst()->update('BlogPost', 'restrict_authors_to_group', 'blogusers'); Config::inst()->update(BlogPost::class, 'restrict_authors_to_group', 'blogusers');
$this->assertEquals(3, $blogpost->getCandidateAuthors()->count()); $this->assertEquals(3, $blogpost->getCandidateAuthors()->count());
@ -86,12 +90,12 @@ class BlogPostTest extends SapphireTest
public function testCanViewFuturePost() public function testCanViewFuturePost()
{ {
$blogPost = $this->objFromFixture('BlogPost', 'NullPublishDate'); $blogPost = $this->objFromFixture(BlogPost::class, 'NullPublishDate');
$editor = $this->objFromFixture('Member', 'BlogEditor'); $editor = $this->objFromFixture(Member::class, 'BlogEditor');
$this->assertTrue($blogPost->canView($editor)); $this->assertTrue($blogPost->canView($editor));
$visitor = $this->objFromFixture('Member', 'Visitor'); $visitor = $this->objFromFixture(Member::class, 'Visitor');
$this->assertFalse($blogPost->canView($visitor)); $this->assertFalse($blogPost->canView($visitor));
} }
@ -101,10 +105,10 @@ class BlogPostTest extends SapphireTest
*/ */
public function testGetDate() public function testGetDate()
{ {
$blogPost = $this->objFromFixture('BlogPost', 'NullPublishDate'); $blogPost = $this->objFromFixture(BlogPost::class, 'NullPublishDate');
$this->assertNull($blogPost->getDate()); $this->assertNull($blogPost->getDate());
$blogPost = $this->objFromFixture('BlogPost', 'PostA'); $blogPost = $this->objFromFixture(BlogPost::class, 'PostA');
$this->assertEquals('2012-01-09 15:00:00', $blogPost->getDate()); $this->assertEquals('2012-01-09 15:00:00', $blogPost->getDate());
} }
} }

View File

@ -1,14 +1,26 @@
<?php <?php
namespace SilverStripe\Blog\Tests;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\Blog\Model\BlogTag;
use SilverStripe\Control\Controller;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\ValidationException;
use SilverStripe\Security\Member;
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class BlogTagTest extends FunctionalTest class BlogTagTest extends FunctionalTest
{ {
/** /**
* {@inheritDoc}
* @var string * @var string
*/ */
public static $fixture_file = 'blog.yml'; protected static $fixture_file = 'blog.yml';
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -17,7 +29,7 @@ class BlogTagTest extends FunctionalTest
{ {
parent::setUp(); parent::setUp();
SS_Datetime::set_mock_now('2013-10-10 20:00:00'); DBDatetime::set_mock_now('2013-10-10 20:00:00');
} }
/** /**
@ -25,7 +37,7 @@ class BlogTagTest extends FunctionalTest
*/ */
public function tearDown() public function tearDown()
{ {
SS_Datetime::clear_mock_now(); DBDatetime::clear_mock_now();
parent::tearDown(); parent::tearDown();
} }
@ -42,12 +54,12 @@ class BlogTagTest extends FunctionalTest
$member->logout(); $member->logout();
} }
$this->objFromFixture('BlogPost', 'FirstBlogPost'); $this->objFromFixture(BlogPost::class, 'FirstBlogPost');
/** /**
* @var BlogTag $tag * @var BlogTag $tag
*/ */
$tag = $this->objFromFixture('BlogTag', 'FirstTag'); $tag = $this->objFromFixture(BlogTag::class, 'FirstTag');
$this->assertEquals(1, $tag->BlogPosts()->count(), 'Tag blog post count'); $this->assertEquals(1, $tag->BlogPosts()->count(), 'Tag blog post count');
} }
@ -57,7 +69,7 @@ class BlogTagTest extends FunctionalTest
*/ */
public function testAllowMultibyteUrlSegment() public function testAllowMultibyteUrlSegment()
{ {
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$tag = new BlogTag(); $tag = new BlogTag();
$tag->BlogID = $blog->ID; $tag->BlogID = $blog->ID;
$tag->Title = 'تست'; $tag->Title = 'تست';
@ -75,15 +87,15 @@ class BlogTagTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$admin = $this->objFromFixture('Member', 'Admin'); $admin = $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$tag = $this->objFromFixture('BlogTag', 'FirstTag'); $tag = $this->objFromFixture(BlogTag::class, 'FirstTag');
$this->assertTrue($tag->canView($admin), 'Admin should be able to view tag.'); $this->assertTrue($tag->canView($admin), 'Admin should be able to view tag.');
$this->assertTrue($tag->canView($editor), 'Editor should be able to view tag.'); $this->assertTrue($tag->canView($editor), 'Editor should be able to view tag.');
$tag = $this->objFromFixture('BlogTag', 'SecondTag'); $tag = $this->objFromFixture(BlogTag::class, 'SecondTag');
$this->assertTrue($tag->canView($admin), 'Admin should be able to view tag.'); $this->assertTrue($tag->canView($admin), 'Admin should be able to view tag.');
$this->assertFalse($tag->canView($editor), 'Editor should not be able to view tag.'); $this->assertFalse($tag->canView($editor), 'Editor should not be able to view tag.');
@ -93,20 +105,20 @@ class BlogTagTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$admin = $this->objFromFixture('Member', 'Admin'); $admin = $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$tag = $this->objFromFixture('BlogTag', 'FirstTag'); $tag = $this->objFromFixture(BlogTag::class, 'FirstTag');
$this->assertTrue($tag->canEdit($admin), 'Admin should be able to edit tag.'); $this->assertTrue($tag->canEdit($admin), 'Admin should be able to edit tag.');
$this->assertTrue($tag->canEdit($editor), 'Editor should be able to edit tag.'); $this->assertTrue($tag->canEdit($editor), 'Editor should be able to edit tag.');
$tag = $this->objFromFixture('BlogTag', 'SecondTag'); $tag = $this->objFromFixture(BlogTag::class, 'SecondTag');
$this->assertTrue($tag->canEdit($admin), 'Admin should be able to edit tag.'); $this->assertTrue($tag->canEdit($admin), 'Admin should be able to edit tag.');
$this->assertFalse($tag->canEdit($editor), 'Editor should not be able to edit tag.'); $this->assertFalse($tag->canEdit($editor), 'Editor should not be able to edit tag.');
$tag = $this->objFromFixture('BlogTag', 'ThirdTag'); $tag = $this->objFromFixture(BlogTag::class, 'ThirdTag');
$this->assertTrue($tag->canEdit($admin), 'Admin should always be able to edit tags.'); $this->assertTrue($tag->canEdit($admin), 'Admin should always be able to edit tags.');
$this->assertTrue($tag->canEdit($editor), 'Editor should be able to edit tag.'); $this->assertTrue($tag->canEdit($editor), 'Editor should be able to edit tag.');
@ -116,10 +128,10 @@ class BlogTagTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$admin = $this->objFromFixture('Member', 'Admin'); $admin = $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$tag = singleton('BlogTag'); $tag = singleton(BlogTag::class);
$this->assertTrue($tag->canCreate($admin), 'Admin should be able to create tag.'); $this->assertTrue($tag->canCreate($admin), 'Admin should be able to create tag.');
$this->assertTrue($tag->canCreate($editor), 'Editor should be able to create tag.'); $this->assertTrue($tag->canCreate($editor), 'Editor should be able to create tag.');
@ -129,26 +141,27 @@ class BlogTagTest extends FunctionalTest
{ {
$this->useDraftSite(); $this->useDraftSite();
$admin = $this->objFromFixture('Member', 'Admin'); $admin = $this->objFromFixture(Member::class, 'Admin');
$editor = $this->objFromFixture('Member', 'Editor'); $editor = $this->objFromFixture(Member::class, 'Editor');
$tag = $this->objFromFixture('BlogTag', 'FirstTag'); $tag = $this->objFromFixture(BlogTag::class, 'FirstTag');
$this->assertTrue($tag->canDelete($admin), 'Admin should be able to delete tag.'); $this->assertTrue($tag->canDelete($admin), 'Admin should be able to delete tag.');
$this->assertTrue($tag->canDelete($editor), 'Editor should be able to delete tag.'); $this->assertTrue($tag->canDelete($editor), 'Editor should be able to delete tag.');
$tag = $this->objFromFixture('BlogTag', 'SecondTag'); $tag = $this->objFromFixture(BlogTag::class, 'SecondTag');
$this->assertTrue($tag->canDelete($admin), 'Admin should be able to delete tag.'); $this->assertTrue($tag->canDelete($admin), 'Admin should be able to delete tag.');
$this->assertFalse($tag->canDelete($editor), 'Editor should not be able to delete tag.'); $this->assertFalse($tag->canDelete($editor), 'Editor should not be able to delete tag.');
$tag = $this->objFromFixture('BlogTag', 'ThirdTag'); $tag = $this->objFromFixture(BlogTag::class, 'ThirdTag');
$this->assertTrue($tag->canDelete($admin), 'Admin should always be able to delete tags.'); $this->assertTrue($tag->canDelete($admin), 'Admin should always be able to delete tags.');
$this->assertTrue($tag->canDelete($editor), 'Editor should be able to delete tag.'); $this->assertTrue($tag->canDelete($editor), 'Editor should be able to delete tag.');
} }
public function testDuplicateTagsForURLSegment() { public function testDuplicateTagsForURLSegment()
{
$blog = new Blog(); $blog = new Blog();
$blog->Title = 'Testing for duplicates blog'; $blog->Title = 'Testing for duplicates blog';
$blog->write(); $blog->write();
@ -162,11 +175,11 @@ class BlogTagTest extends FunctionalTest
$tag2->Title = 'cat test'; $tag2->Title = 'cat test';
$tag2->BlogID = $blog->ID; $tag2->BlogID = $blog->ID;
$tag2->write(); $tag2->write();
$this->assertEquals('cat-test-0', $tag2->URLSegment); $this->assertEquals('cat-test-1', $tag2->URLSegment);
} }
public function testDuplicateTags() { public function testDuplicateTags()
{
$blog = new Blog(); $blog = new Blog();
$blog->Title = 'Testing for duplicate tags'; $blog->Title = 'Testing for duplicate tags';
$blog->write(); $blog->write();
@ -174,19 +187,20 @@ class BlogTagTest extends FunctionalTest
$tag = new BlogTag(); $tag = new BlogTag();
$tag->Title = 'Test'; $tag->Title = 'Test';
$tag->BlogID = $blog->ID; $tag->BlogID = $blog->ID;
$tag->URLSegment = 'test';
$tag->write(); $tag->write();
$tag = new BlogTag(); $tag = new BlogTag();
$tag->Title = 'Test'; $tag->Title = 'Test';
$tag->URLSegment = 'test';
$tag->BlogID = $blog->ID; $tag->BlogID = $blog->ID;
try { try {
$tag->write(); $tag->write();
$this->fail('Duplicate BlogTag written'); $this->fail('Duplicate BlogTag written');
} catch (ValidationException $e) { } catch (ValidationException $e) {
$codeList = $e->getResult()->codeList(); $messages = $e->getResult()->getMessages();
$this->assertCount(1, $codeList); $this->assertCount(1, $messages);
$this->assertEquals(BlogTag::DUPLICATE_EXCEPTION, $codeList[0]); $this->assertEquals(BlogTag::DUPLICATE_EXCEPTION, $messages[0]['messageType']);
} }
} }
} }

View File

@ -1,14 +1,23 @@
<?php <?php
class BlogTagsCloudWidgetTest extends SapphireTest { namespace SilverStripe\Blog\Tests;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Widgets\BlogTagsCloudWidget;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
class BlogTagsCloudWidgetTest extends SapphireTest
{
/** /**
* @var string * @var string
*/ */
public static $fixture_file = 'blog.yml'; protected static $fixture_file = 'blog.yml';
public function testGetCMSFields() { public function testGetCMSFields()
if (!class_exists('Widget')) { {
if (!class_exists('SilverStripe\\Widgets\\Model\\Widget')) {
$this->markTestSkipped('Widgets module not installed'); $this->markTestSkipped('Widgets module not installed');
} }
@ -23,12 +32,13 @@ class BlogTagsCloudWidgetTest extends SapphireTest {
$this->assertEquals($expected, $names); $this->assertEquals($expected, $names);
} }
public function testGetTags() { public function testGetTags()
if (!class_exists('Widget')) { {
if (!class_exists('SilverStripe\\Widgets\\Model\\Widget')) {
$this->markTestSkipped('Widgets module not installed'); $this->markTestSkipped('Widgets module not installed');
} }
$widget = new BlogTagsCloudWidget(); $widget = new BlogTagsCloudWidget();
$blog = $this->objFromFixture('Blog', 'FourthBlog'); $blog = $this->objFromFixture(Blog::class, 'FourthBlog');
$widget->BlogID = $blog->ID; $widget->BlogID = $blog->ID;
$widget->write(); $widget->write();
$tags = $widget->getTags()->toArray(); $tags = $widget->getTags()->toArray();

View File

@ -1,5 +1,21 @@
<?php <?php
namespace SilverStripe\Blog\Tests;
use SilverStripe\Blog\Model\Blog;
use SilverStripe\Blog\Model\BlogController;
use SilverStripe\Blog\Model\BlogPost;
use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\DataModel;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\SS_List;
use SilverStripe\Security\Member;
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
@ -8,7 +24,7 @@ class BlogTest extends SapphireTest
/** /**
* @var string * @var string
*/ */
public static $fixture_file = 'blog.yml'; protected static $fixture_file = 'blog.yml';
/** /**
* {@inheritdoc} * {@inheritdoc}
@ -18,12 +34,12 @@ class BlogTest extends SapphireTest
parent::setUp(); parent::setUp();
Config::nest(); Config::nest();
SS_Datetime::set_mock_now('2013-10-10 20:00:00'); DBDatetime::set_mock_now('2013-10-10 20:00:00');
/** /**
* @var Blog $blog * @var Blog $blog
*/ */
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$blog->publish('Stage', 'Live'); $blog->publish('Stage', 'Live');
} }
@ -33,7 +49,7 @@ class BlogTest extends SapphireTest
*/ */
public function tearDown() public function tearDown()
{ {
SS_Datetime::clear_mock_now(); DBDatetime::clear_mock_now();
Config::unnest(); Config::unnest();
parent::tearDown(); parent::tearDown();
@ -50,17 +66,17 @@ class BlogTest extends SapphireTest
/** /**
* @var Blog $blog * @var Blog $blog
*/ */
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
Config::inst()->update('BlogPost', 'show_in_sitetree', true); Config::inst()->update(BlogPost::class, 'show_in_sitetree', true);
$classes = $blog->getExcludedSiteTreeClassNames(); $classes = $blog->getExcludedSiteTreeClassNames();
$this->assertNotContains('BlogPost', $classes, 'BlogPost class should be hidden.'); $this->assertNotContains(BlogPost::class, $classes, 'BlogPost class should be hidden.');
Config::inst()->update('BlogPost', 'show_in_sitetree', false); Config::inst()->update(BlogPost::class, 'show_in_sitetree', false);
$classes = $blog->getExcludedSiteTreeClassNames(); $classes = $blog->getExcludedSiteTreeClassNames();
$this->assertContains('BlogPost', $classes, 'BlogPost class should be hidden.'); $this->assertContains(BlogPost::class, $classes, 'BlogPost class should be hidden.');
} }
public function testGetArchivedBlogPosts() public function testGetArchivedBlogPosts()
@ -74,7 +90,7 @@ class BlogTest extends SapphireTest
/** /**
* @var Blog $blog * @var Blog $blog
*/ */
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$archive = $blog->getArchivedBlogPosts(2013); $archive = $blog->getArchivedBlogPosts(2013);
@ -96,7 +112,7 @@ class BlogTest extends SapphireTest
/** /**
* @var Blog $blog * @var Blog $blog
*/ */
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$link = Controller::join_links($blog->Link('archive'), '2013', '10', '01'); $link = Controller::join_links($blog->Link('archive'), '2013', '10', '01');
@ -135,8 +151,8 @@ class BlogTest extends SapphireTest
*/ */
public function testArchiveYear() public function testArchiveYear()
{ {
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$controller = new Blog_Controller($blog); $controller = new BlogController($blog);
$this->requestURL($controller, 'first-post/archive/'); $this->requestURL($controller, 'first-post/archive/');
$this->assertEquals(2013, $controller->getArchiveYear(), 'getArchiveYear should return 2013'); $this->assertEquals(2013, $controller->getArchiveYear(), 'getArchiveYear should return 2013');
} }
@ -156,47 +172,47 @@ class BlogTest extends SapphireTest
/** /**
* @var Blog $firstBlog * @var Blog $firstBlog
*/ */
$firstBlog = $this->objFromFixture('Blog', 'FirstBlog'); $firstBlog = $this->objFromFixture(Blog::class, 'FirstBlog');
/** /**
* @var Blog $fourthBlog * @var Blog $fourthBlog
*/ */
$fourthBlog = $this->objFromFixture('Blog', 'FourthBlog'); $fourthBlog = $this->objFromFixture(Blog::class, 'FourthBlog');
/** /**
* @var BlogPost $postA * @var BlogPost $postA
*/ */
$postA = $this->objFromFixture('BlogPost', 'PostA'); $postA = $this->objFromFixture(BlogPost::class, 'PostA');
/** /**
* @var BlogPost $postB * @var BlogPost $postB
*/ */
$postB = $this->objFromFixture('BlogPost', 'PostB'); $postB = $this->objFromFixture(BlogPost::class, 'PostB');
/** /**
* @var BlogPost $postC * @var BlogPost $postC
*/ */
$postC = $this->objFromFixture('BlogPost', 'PostC'); $postC = $this->objFromFixture(BlogPost::class, 'PostC');
/** /**
* @var Member $editor * @var Member $editor
*/ */
$editor = $this->objFromFixture('Member', 'BlogEditor'); $editor = $this->objFromFixture(Member::class, 'BlogEditor');
/** /**
* @var Member $writer * @var Member $writer
*/ */
$writer = $this->objFromFixture('Member', 'Writer'); $writer = $this->objFromFixture(Member::class, 'Writer');
/** /**
* @var Member $contributor * @var Member $contributor
*/ */
$contributor = $this->objFromFixture('Member', 'Contributor'); $contributor = $this->objFromFixture(Member::class, 'Contributor');
/** /**
* @var Member $visitor * @var Member $visitor
*/ */
$visitor = $this->objFromFixture('Member', 'Visitor'); $visitor = $this->objFromFixture(Member::class, 'Visitor');
$this->assertEquals('Editor', $fourthBlog->RoleOf($editor)); $this->assertEquals('Editor', $fourthBlog->RoleOf($editor));
$this->assertEquals('Contributor', $fourthBlog->RoleOf($contributor)); $this->assertEquals('Contributor', $fourthBlog->RoleOf($contributor));
@ -274,8 +290,8 @@ class BlogTest extends SapphireTest
public function testFilteredCategories() public function testFilteredCategories()
{ {
$blog = $this->objFromFixture('Blog', 'FirstBlog'); $blog = $this->objFromFixture(Blog::class, 'FirstBlog');
$controller = new Blog_Controller($blog); $controller = new BlogController($blog);
// Root url // Root url
$this->requestURL($controller, 'first-post'); $this->requestURL($controller, 'first-post');
@ -293,10 +309,10 @@ class BlogTest extends SapphireTest
); );
// Posts // Posts
$firstPostID = $this->idFromFixture('BlogPost', 'FirstBlogPost'); $firstPostID = $this->idFromFixture(BlogPost::class, 'FirstBlogPost');
$secondPostID = $this->idFromFixture('BlogPost', 'SecondBlogPost'); $secondPostID = $this->idFromFixture(BlogPost::class, 'SecondBlogPost');
$firstFuturePostID = $this->idFromFixture('BlogPost', 'FirstFutureBlogPost'); $firstFuturePostID = $this->idFromFixture(BlogPost::class, 'FirstFutureBlogPost');
$secondFuturePostID = $this->idFromFixture('BlogPost', 'SecondFutureBlogPost'); $secondFuturePostID = $this->idFromFixture(BlogPost::class, 'SecondFutureBlogPost');
// Request first tag // Request first tag
$this->requestURL($controller, 'first-post/tag/first-tag'); $this->requestURL($controller, 'first-post/tag/first-tag');
@ -321,10 +337,10 @@ class BlogTest extends SapphireTest
*/ */
protected function requestURL(ContentController $controller, $url) protected function requestURL(ContentController $controller, $url)
{ {
$request = new SS_HTTPRequest('get', $url); $request = new HTTPRequest('get', $url);
$request->match('$URLSegment//$Action/$ID/$OtherID'); $request->match('$URLSegment//$Action/$ID/$OtherID');
$request->shift(); $request->shift();
$controller->init(); $controller->doInit();
$controller->handleRequest($request, new DataModel()); $controller->handleRequest($request, new DataModel());
} }

View File

@ -1,6 +1,6 @@
# Mock date is set to 2013-10-01 20:00:00 # Mock date is set to 2013-10-01 20:00:00
Group: SilverStripe\Security\Group:
Administrators: Administrators:
Title: Administrators Title: Administrators
Editors: Editors:
@ -9,193 +9,193 @@ Group:
Title: Blog Users Title: Blog Users
Code: blogusers Code: blogusers
Permission: SilverStripe\Security\Permission:
Administrators: Administrators:
Code: ADMIN Code: ADMIN
Group: =>Group.Administrators Group: =>SilverStripe\Security\Group.Administrators
Editors: Editors:
Code: CMS_ACCESS_CMSMain Code: CMS_ACCESS_CMSMain
Group: =>Group.Editors Group: =>SilverStripe\Security\Group.Editors
BlogUsers: BlogUsers:
Code: CMS_ACCESS_CMSMain Code: CMS_ACCESS_CMSMain
Group: =>Group.BlogUsers Group: =>SilverStripe\Security\Group.BlogUsers
SiteConfig: SilverStripe\SiteConfig\SiteConfig:
Default: Default:
CanEditType: 'OnlyTheseUsers' CanEditType: 'OnlyTheseUsers'
CanCreateTopLevelType: 'OnlyTheseUsers' CanCreateTopLevelType: 'OnlyTheseUsers'
EditorGroups: =>Group.Administrators,=>Group.Editors EditorGroups: =>SilverStripe\Security\Group.Administrators,=>SilverStripe\Security\Group.Editors
CreateTopLevelGroups: =>Group.Administrators,=>Group.Editors CreateTopLevelGroups: =>SilverStripe\Security\Group.Administrators,=>SilverStripe\Security\Group.Editors
Member: SilverStripe\Security\Member:
Admin: Admin:
FirstName: Test FirstName: Test
Surname: Administrator Surname: Administrator
Groups: =>Group.Administrators Groups: =>SilverStripe\Security\Group.Administrators
Editor: Editor:
FirstName: Test FirstName: Test
Surname: Editor Surname: Editor
Groups: =>Group.Editors Groups: =>SilverStripe\Security\Group.Editors
BlogEditor: BlogEditor:
FirstName: Blog FirstName: Blog
Surname: Editor Surname: Editor
Groups: =>Group.BlogUsers Groups: =>SilverStripe\Security\Group.BlogUsers
Writer: Writer:
FirstName: Blog FirstName: Blog
Surname: Writer Surname: Writer
Groups: =>Group.BlogUsers Groups: =>SilverStripe\Security\Group.BlogUsers
Contributor: Contributor:
FirstName: Blog FirstName: Blog
Surname: Contributor Surname: Contributor
Groups: =>Group.BlogUsers Groups: =>SilverStripe\Security\Group.BlogUsers
Visitor: Visitor:
FirstName: Blog FirstName: Blog
Surname: Visitor Surname: Visitor
Blog: SilverStripe\Blog\Model\Blog:
FirstBlog: FirstBlog:
Title: 'First Blog' Title: 'First Blog'
SecondBlog: SecondBlog:
Title: 'Second Blog' Title: 'Second Blog'
CanViewType: 'OnlyTheseUsers' CanViewType: 'OnlyTheseUsers'
CanEditType: 'OnlyTheseUsers' CanEditType: 'OnlyTheseUsers'
ViewerGroups: =>Group.Administrators ViewerGroups: =>SilverStripe\Security\Group.Administrators
EditorGroups: =>Group.Administrators EditorGroups: =>SilverStripe\Security\Group.Administrators
ThirdBlog: ThirdBlog:
Title: 'Third Blog' Title: 'Third Blog'
CanEditType: 'OnlyTheseUsers' CanEditType: 'OnlyTheseUsers'
EditorGroups: =>Group.Editors EditorGroups: =>SilverStripe\Security\Group.Editors
FourthBlog: FourthBlog:
Title: 'Fourth Blog' Title: 'Fourth Blog'
Editors: =>Member.BlogEditor Editors: =>SilverStripe\Security\Member.BlogEditor
Writers: =>Member.Writer Writers: =>SilverStripe\Security\Member.Writer
Contributors: =>Member.Contributor Contributors: =>SilverStripe\Security\Member.Contributor
BlogTag: SilverStripe\Blog\Model\BlogTag:
FirstTag: FirstTag:
Title: 'First Tag' Title: 'First Tag'
URLSegment: 'first-tag' URLSegment: 'first-tag'
Blog: =>Blog.FirstBlog Blog: =>SilverStripe\Blog\Model\Blog.FirstBlog
SecondTag: SecondTag:
Title: 'Second Tag' Title: 'Second Tag'
URLSegment: 'second-tag' URLSegment: 'second-tag'
Blog: =>Blog.SecondBlog Blog: =>SilverStripe\Blog\Model\Blog.SecondBlog
ThirdTag: ThirdTag:
Title: 'Third Tag' Title: 'Third Tag'
URLSegment: 'third-tag' URLSegment: 'third-tag'
Blog: =>Blog.ThirdBlog Blog: =>SilverStripe\Blog\Model\Blog.ThirdBlog
#Tags for Tag Cloud widget #Tags for Tag Cloud widget
PopularTag: PopularTag:
Title: 'Popular' Title: 'Popular'
URLSegment: 'popular-tag' URLSegment: 'popular-tag'
Blog: =>Blog.FourthBlog Blog: =>SilverStripe\Blog\Model\Blog.FourthBlog
CoolTag: CoolTag:
Title: 'Cool' Title: 'Cool'
URLSegment: 'cool-tag' URLSegment: 'cool-tag'
Blog: =>Blog.FourthBlog Blog: =>SilverStripe\Blog\Model\Blog.FourthBlog
CatTag: CatTag:
Title: 'Cat' Title: 'Cat'
URLSegment: 'cat-tag' URLSegment: 'cat-tag'
Blog: =>Blog.FourthBlog Blog: =>SilverStripe\Blog\Model\Blog.FourthBlog
KiwiTag: KiwiTag:
Title: 'Kiwi' Title: 'Kiwi'
URLSegment: 'kiwi-tag' URLSegment: 'kiwi-tag'
Blog: =>Blog.FourthBlog Blog: =>SilverStripe\Blog\Model\Blog.FourthBlog
BlogCategory: SilverStripe\Blog\Model\BlogCategory:
FirstCategory: FirstCategory:
Title: 'First Category' Title: 'First Category'
URLSegment: 'first-category' URLSegment: 'first-category'
Blog: =>Blog.FirstBlog Blog: =>SilverStripe\Blog\Model\Blog.FirstBlog
SecondCategory: SecondCategory:
Title: 'Second Category' Title: 'Second Category'
URLSegment: 'second-category' URLSegment: 'second-category'
Blog: =>Blog.SecondBlog Blog: =>SilverStripe\Blog\Model\Blog.SecondBlog
ThirdCategory: ThirdCategory:
Title: 'Third Category' Title: 'Third Category'
URLSegment: 'third-category' URLSegment: 'third-category'
Blog: =>Blog.ThirdBlog Blog: =>SilverStripe\Blog\Model\Blog.ThirdBlog
BlogPost: SilverStripe\Blog\Model\BlogPost:
FirstBlogPost: FirstBlogPost:
Title: 'First Post' Title: 'First Post'
URLSegment: first-post URLSegment: first-post
PublishDate: '2013-10-01 15:00:00' PublishDate: '2013-10-01 15:00:00'
Parent: =>Blog.FirstBlog Parent: =>SilverStripe\Blog\Model\Blog.FirstBlog
Tags: =>BlogTag.FirstTag Tags: =>SilverStripe\Blog\Model\BlogTag.FirstTag
Categories: =>BlogCategory.FirstCategory Categories: =>SilverStripe\Blog\Model\BlogCategory.FirstCategory
SecondBlogPost: SecondBlogPost:
Title: 'Second Post' Title: 'Second Post'
URLSegment: second-post URLSegment: second-post
PublishDate: '2013-09-01 15:00:00' PublishDate: '2013-09-01 15:00:00'
Parent: =>Blog.FirstBlog Parent: =>SilverStripe\Blog\Model\Blog.FirstBlog
ThirdBlogPost: ThirdBlogPost:
Title: 'Old Post' Title: 'Old Post'
URLSegment: old-post URLSegment: old-post
PublishDate: '2012-01-09 15:00:00' PublishDate: '2012-01-09 15:00:00'
Parent: =>Blog.FirstBlog Parent: =>SilverStripe\Blog\Model\Blog.FirstBlog
FirstFutureBlogPost: FirstFutureBlogPost:
Title: 'Future Post' Title: 'Future Post'
URLSegment: future-post URLSegment: future-post
PublishDate: '2015-01-01 00:00:00' PublishDate: '2015-01-01 00:00:00'
Tags: =>BlogTag.FirstTag Tags: =>SilverStripe\Blog\Model\BlogTag.FirstTag
Categories: =>BlogCategory.FirstCategory Categories: =>SilverStripe\Blog\Model\BlogCategory.FirstCategory
Parent: =>Blog.FirstBlog Parent: =>SilverStripe\Blog\Model\Blog.FirstBlog
SecondFutureBlogPost: SecondFutureBlogPost:
Title: 'Future Post 2' Title: 'Future Post 2'
URLSegment: future-post-2 URLSegment: future-post-2
PublishDate: '2013-11-01 00:00:00' PublishDate: '2013-11-01 00:00:00'
Tags: =>BlogTag.FirstTag Tags: =>SilverStripe\Blog\Model\BlogTag.FirstTag
Categories: =>BlogCategory.FirstCategory Categories: =>SilverStripe\Blog\Model\BlogCategory.FirstCategory
Parent: =>Blog.FirstBlog Parent: =>SilverStripe\Blog\Model\Blog.FirstBlog
PostA: PostA:
Title: 'One Post' Title: 'One Post'
PublishDate: '2012-01-09 15:00:00' PublishDate: '2012-01-09 15:00:00'
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog
Authors: =>Member.Writer,=>Member.Contributor Authors: =>SilverStripe\Security\Member.Writer,=>SilverStripe\Security\Member.Contributor
PostB: PostB:
Title: 'Second Post' Title: 'Second Post'
PublishDate: '2012-01-09 15:00:00' PublishDate: '2012-01-09 15:00:00'
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog
Authors: =>Member.BlogEditor Authors: =>SilverStripe\Security\Member.BlogEditor
PostC: PostC:
Title: 'Third Post' Title: 'Third Post'
PublishDate: '2012-01-09 15:00:00' PublishDate: '2012-01-09 15:00:00'
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog
Authors: =>Member.BlogEditor,=>Member.Writer,=>Member.Contributor Authors: =>SilverStripe\Security\Member.BlogEditor,=>SilverStripe\Security\Member.Writer,=>SilverStripe\Security\Member.Contributor
NullPublishDate: NullPublishDate:
Title: 'No publish date' Title: 'No publish date'
PublishDate: 'NULL' PublishDate: ''
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog
Authors: =>Member.BlogEditor,=>Member.Writer,=>Member.Contributor Authors: =>SilverStripe\Security\Member.BlogEditor,=>SilverStripe\Security\Member.Writer,=>SilverStripe\Security\Member.Contributor
#Posts for the tag cloud widget test #Posts for the tag cloud widget test
TaggedPost1: TaggedPost1:
Title: 'Tagged Post 1' Title: 'Tagged Post 1'
URLSegment: tagged-post-1 URLSegment: tagged-post-1
PublishDate: '2012-01-09 15:00:00' PublishDate: '2012-01-09 15:00:00'
Tags: =>BlogTag.PopularTag,=>BlogTag.CoolTag Tags: =>SilverStripe\Blog\Model\BlogTag.PopularTag,=>SilverStripe\Blog\Model\BlogTag.CoolTag
Categories: =>BlogCategory.FirstCategory Categories: =>SilverStripe\Blog\Model\BlogCategory.FirstCategory
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog
TaggedPost2: TaggedPost2:
Title: 'Tagged Post 2' Title: 'Tagged Post 2'
URLSegment: tagged-post-2 URLSegment: tagged-post-2
PublishDate: '2012-01-09 15:00:00' PublishDate: '2012-01-09 15:00:00'
Tags: =>BlogTag.PopularTag,=>BlogTag.CoolTag,=>BlogTag.CatTag Tags: =>SilverStripe\Blog\Model\BlogTag.PopularTag,=>SilverStripe\Blog\Model\BlogTag.CoolTag,=>SilverStripe\Blog\Model\BlogTag.CatTag
Categories: =>BlogCategory.FirstCategory Categories: =>SilverStripe\Blog\Model\BlogCategory.FirstCategory
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog
TaggedPost3: TaggedPost3:
Title: 'Tagged Post 3' Title: 'Tagged Post 3'
URLSegment: tagged-post-3 URLSegment: tagged-post-3
PublishDate: '2012-01-09 17:20:00' PublishDate: '2012-01-09 17:20:00'
Tags: =>BlogTag.PopularTag,=>BlogTag.CoolTag,=>BlogTag.CatTag,=>BlogTag.KiwiTag Tags: =>SilverStripe\Blog\Model\BlogTag.PopularTag,=>SilverStripe\Blog\Model\BlogTag.CoolTag,=>SilverStripe\Blog\Model\BlogTag.CatTag,=>SilverStripe\Blog\Model\BlogTag.KiwiTag
Categories: =>BlogCategory.FirstCategory Categories: =>SilverStripe\Blog\Model\BlogCategory.FirstCategory
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog
TaggedPost4: TaggedPost4:
Title: 'Tagged Post 4' Title: 'Tagged Post 4'
URLSegment: tagged-post-4 URLSegment: tagged-post-4
PublishDate: '2012-04-09 15:00:00' PublishDate: '2012-04-09 15:00:00'
Tags: =>BlogTag.PopularTag Tags: =>SilverStripe\Blog\Model\BlogTag.PopularTag
Categories: =>BlogCategory.FirstCategory Categories: =>SilverStripe\Blog\Model\BlogCategory.FirstCategory
Parent: =>Blog.FourthBlog Parent: =>SilverStripe\Blog\Model\Blog.FourthBlog