mirror of
https://github.com/silverstripe/silverstripe-blog
synced 2024-10-22 11:05:58 +02:00
Merge pull request #594 from tractorcow/pull/4/categorisation-rewrite
Category / Tag Rewrite - Remove dependency on Blog
This commit is contained in:
commit
3472295f62
@ -12,11 +12,11 @@ use SilverStripe\ORM\SS_List;
|
||||
class GridFieldCategorisationConfig extends GridFieldConfig_RecordEditor
|
||||
{
|
||||
/**
|
||||
* @param int $itemsPerPage
|
||||
* @param int $itemsPerPage
|
||||
* @param array|SS_List $mergeRecords
|
||||
* @param string $parentType
|
||||
* @param string $parentMethod
|
||||
* @param string $childMethod
|
||||
* @param string $parentType
|
||||
* @param string $parentMethod
|
||||
* @param string $childMethod
|
||||
*/
|
||||
public function __construct($itemsPerPage, $mergeRecords, $parentType, $parentMethod, $childMethod)
|
||||
{
|
||||
@ -39,31 +39,21 @@ class GridFieldCategorisationConfig extends GridFieldConfig_RecordEditor
|
||||
|
||||
$columns->setFieldFormatting(
|
||||
[
|
||||
'BlogPostsCount' => function ($value, CategorisationObject $item) {
|
||||
'BlogPostsCount' => function ($value, CategorisationObject $item) {
|
||||
return $item->getBlogCount();
|
||||
},
|
||||
'BlogPostsAllCount' => 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::class);
|
||||
|
||||
$columns->setDisplayFields(
|
||||
[
|
||||
'Title' => _t(__CLASS__ . '.Title', 'Title'),
|
||||
'BlogPostsCount' => _t(__CLASS__ . '.Posts', 'Posts'),
|
||||
'MergeAction' => 'MergeAction',
|
||||
'Actions' => 'Actions'
|
||||
'Title' => _t(__CLASS__ . '.Title', 'Title'),
|
||||
'BlogPostsCount' => _t(__CLASS__ . '.PostsThisBlog', 'Posts (This Blog)'),
|
||||
'BlogPostsAllCount' => _t(__CLASS__ . '.PostsAllBlogs', 'Posts (All Blogs)'),
|
||||
'MergeAction' => 'MergeAction',
|
||||
'Actions' => 'Actions'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -99,6 +99,7 @@ class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLP
|
||||
$obj->setCastedField($dbField, $data['gridfieldaddbydbfield'][$obj->ClassName][$dbField]);
|
||||
|
||||
if ($obj->canCreate()) {
|
||||
$obj->write();
|
||||
$id = $gridField->getList()->add($obj);
|
||||
if (!$id) {
|
||||
$gridField->setCustomValidationMessage(
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
namespace SilverStripe\Blog\Model;
|
||||
|
||||
use Exception;
|
||||
use Page;
|
||||
use SilverStripe\Blog\Admin\GridFieldCategorisationConfig;
|
||||
use SilverStripe\Blog\Forms\GridField\GridFieldConfigBlogPost;
|
||||
use SilverStripe\CMS\Controllers\RootURLController;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
@ -14,13 +14,15 @@ use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\Forms\ListboxField;
|
||||
use SilverStripe\Forms\LiteralField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\Forms\Tab;
|
||||
use SilverStripe\Forms\TabSet;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\HasManyList;
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\ORM\UnsavedRelationList;
|
||||
use SilverStripe\ORM\ValidationException;
|
||||
use SilverStripe\Security\Group;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Permission;
|
||||
@ -31,8 +33,7 @@ use SilverStripe\View\Requirements;
|
||||
/**
|
||||
* Blog Holder
|
||||
*
|
||||
* @method HasManyList Tags() List of tags in this blog
|
||||
* @method HasManyList Categories() List of categories in this blog
|
||||
* @property int $PostsPerPage
|
||||
* @method ManyManyList Editors() List of editors
|
||||
* @method ManyManyList Writers() List of writers
|
||||
* @method ManyManyList Contributors() List of contributors
|
||||
@ -88,20 +89,12 @@ class Blog extends Page implements PermissionProvider
|
||||
'PostsPerPage' => 'Int',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $has_many = [
|
||||
'Tags' => BlogTag::class,
|
||||
'Categories' => BlogCategory::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $many_many = [
|
||||
'Editors' => Member::class,
|
||||
'Writers' => Member::class,
|
||||
'Editors' => Member::class,
|
||||
'Writers' => Member::class,
|
||||
'Contributors' => Member::class,
|
||||
];
|
||||
|
||||
@ -134,6 +127,48 @@ class Blog extends Page implements PermissionProvider
|
||||
|
||||
private static $icon_class = 'font-icon-p-posts';
|
||||
|
||||
/**
|
||||
* Gets the list of all tags attached to this blog
|
||||
*
|
||||
* @param bool $hideEmpty Set to false to include tags without posts
|
||||
* @return DataList|BlogTag[]
|
||||
*/
|
||||
public function Tags($hideEmpty = true)
|
||||
{
|
||||
$tags = BlogTag::get()->setDataQueryParam('BlogID', $this->ID);
|
||||
|
||||
// Conditionally hide empty tags
|
||||
if ($this->ID && $hideEmpty) {
|
||||
$tags = $tags->filter([
|
||||
'BlogPosts.ParentID' => $this->ID,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->extend('updateBlogTags', $tags);
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of all categories attached to this blog
|
||||
*
|
||||
* @param bool $hideEmpty Set to false to include categories without posts
|
||||
* @return DataList|BlogCategory[]
|
||||
*/
|
||||
public function Categories($hideEmpty = true)
|
||||
{
|
||||
$tags = BlogCategory::get()->setDataQueryParam('BlogID', $this->ID);
|
||||
|
||||
// Conditionally hide empty categories
|
||||
if ($this->ID && $hideEmpty) {
|
||||
$tags = $tags->filter([
|
||||
'BlogPosts.ParentID' => $this->ID,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->extend('updateBlogCategories', $tags);
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -141,18 +176,18 @@ class Blog extends Page implements PermissionProvider
|
||||
{
|
||||
$this->addCMSRequirements();
|
||||
|
||||
$this->beforeUpdateCMSFields(function ($fields) {
|
||||
$this->beforeUpdateCMSFields(function (FieldList $fields) {
|
||||
if (!$this->canEdit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$categories = GridField::create(
|
||||
'Categories',
|
||||
_t(__CLASS__ . '.Categories', 'Categories'),
|
||||
$this->Categories(),
|
||||
$this->Categories(false),
|
||||
GridFieldCategorisationConfig::create(
|
||||
15,
|
||||
$this->Categories()->sort('Title'),
|
||||
$this->Categories(false)->sort('Title'),
|
||||
BlogCategory::class,
|
||||
'Categories',
|
||||
'BlogPosts'
|
||||
@ -162,30 +197,32 @@ class Blog extends Page implements PermissionProvider
|
||||
$tags = GridField::create(
|
||||
'Tags',
|
||||
_t(__CLASS__ . '.Tags', 'Tags'),
|
||||
$this->Tags(),
|
||||
$this->Tags(false),
|
||||
GridFieldCategorisationConfig::create(
|
||||
15,
|
||||
$this->Tags()->sort('Title'),
|
||||
$this->Tags(false)->sort('Title'),
|
||||
BlogTag::class,
|
||||
'Tags',
|
||||
'BlogPosts'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* @var FieldList $fields
|
||||
*/
|
||||
$fields->addFieldsToTab(
|
||||
$fields->addFieldToTab(
|
||||
'Root',
|
||||
TabSet::create('Categorisation', _t(__CLASS__ . '.Categorisation', 'Categorisation'))
|
||||
->addExtraClass('blog-cms-categorisation')
|
||||
);
|
||||
$fields->addFieldToTab(
|
||||
'Root.Categorisation',
|
||||
[
|
||||
$categories,
|
||||
$tags
|
||||
]
|
||||
Tab::create('Categories', _t(__CLASS__ . '.Categories', 'Categories'))
|
||||
);
|
||||
$fields->addFieldToTab(
|
||||
'Root.Categorisation',
|
||||
Tab::create('Tags', _t(__CLASS__ . '.Tags', 'Tags'))
|
||||
);
|
||||
|
||||
$fields->fieldByName('Root.Categorisation')
|
||||
->addExtraClass('blog-cms-categorisation')
|
||||
->setTitle(_t(__CLASS__ . '.Categorisation', 'Categorisation'));
|
||||
$fields->addFieldToTab('Root.Categorisation.Categories', $categories);
|
||||
$fields->addFieldToTab('Root.Categorisation.Tags', $tags);
|
||||
});
|
||||
|
||||
return parent::getCMSFields();
|
||||
@ -199,6 +236,7 @@ class Blog extends Page implements PermissionProvider
|
||||
Requirements::css('silverstripe/blog:client/dist/styles/main.css');
|
||||
Requirements::javascript('silverstripe/blog:client/dist/js/main.bundle.js');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -249,7 +287,7 @@ class Blog extends Page implements PermissionProvider
|
||||
/**
|
||||
* Determine if the given member belongs to the given relation.
|
||||
*
|
||||
* @param Member $member
|
||||
* @param Member $member
|
||||
* @param DataList $relation
|
||||
*
|
||||
* @return bool
|
||||
@ -527,7 +565,7 @@ class Blog extends Page implements PermissionProvider
|
||||
/**
|
||||
* Returns BlogPosts for a given date period.
|
||||
*
|
||||
* @param int $year
|
||||
* @param int $year
|
||||
* @param null|int $month
|
||||
* @param null|int $day
|
||||
*
|
||||
@ -592,13 +630,7 @@ class Blog extends Page implements PermissionProvider
|
||||
*/
|
||||
public function ProfileLink($urlSegment)
|
||||
{
|
||||
$baseLink = $this->Link();
|
||||
if ($baseLink === '/') {
|
||||
// Handle homepage blogs
|
||||
$baseLink = RootURLController::get_homepage_link();
|
||||
}
|
||||
|
||||
return Controller::join_links($baseLink, 'profile', $urlSegment);
|
||||
return Controller::join_links($this->Link('Profile'), $urlSegment);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -628,22 +660,22 @@ class Blog extends Page implements PermissionProvider
|
||||
{
|
||||
return [
|
||||
Blog::MANAGE_USERS => [
|
||||
'name' => _t(
|
||||
'name' => _t(
|
||||
__CLASS__ . '.PERMISSION_MANAGE_USERS_DESCRIPTION',
|
||||
'Manage users for individual blogs'
|
||||
),
|
||||
'help' => _t(
|
||||
'help' => _t(
|
||||
__CLASS__ . '.PERMISSION_MANAGE_USERS_HELP',
|
||||
'Allow assignment of Editors, Writers, or Contributors to blogs'
|
||||
),
|
||||
'category' => _t(__CLASS__ . '.PERMISSIONS_CATEGORY', 'Blog permissions'),
|
||||
'sort' => 100
|
||||
'sort' => 100
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @throws ValidationException
|
||||
*/
|
||||
protected function onBeforeWrite()
|
||||
{
|
||||
@ -653,6 +685,9 @@ class Blog extends Page implements PermissionProvider
|
||||
|
||||
/**
|
||||
* Assign users as necessary to the blog group.
|
||||
*
|
||||
* @throws ValidationException
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function assignGroup()
|
||||
{
|
||||
@ -665,6 +700,7 @@ class Blog extends Page implements PermissionProvider
|
||||
// Must check if the method exists or else an error occurs when changing page type
|
||||
if ($this->hasMethod('Editors')) {
|
||||
foreach ([$this->Editors(), $this->Writers(), $this->Contributors()] as $levels) {
|
||||
/** @var Member $user */
|
||||
foreach ($levels as $user) {
|
||||
if (!$user->inGroup($group)) {
|
||||
$user->Groups()->add($group);
|
||||
@ -678,13 +714,14 @@ class Blog extends Page implements PermissionProvider
|
||||
* Gets or creates the group used to assign CMS access.
|
||||
*
|
||||
* @return Group
|
||||
* @throws ValidationException
|
||||
*/
|
||||
protected function getUserGroup()
|
||||
{
|
||||
$code = $this->config()->get('grant_user_group');
|
||||
|
||||
/** @var Group $group */
|
||||
$group = Group::get()->filter('Code', $code)->first();
|
||||
|
||||
if ($group) {
|
||||
return $group;
|
||||
}
|
||||
|
@ -3,16 +3,14 @@
|
||||
namespace SilverStripe\Blog\Model;
|
||||
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
|
||||
/**
|
||||
* A blog category for generalising blog posts.
|
||||
*
|
||||
*
|
||||
* @method Blog Blog()
|
||||
*
|
||||
* @method ManyManyList|BlogPost[] BlogPosts()
|
||||
* @property string $Title
|
||||
* @property string $URLSegment
|
||||
* @property int $BlogID
|
||||
*/
|
||||
class BlogCategory extends DataObject implements CategorisationObject
|
||||
{
|
||||
@ -44,8 +42,8 @@ class BlogCategory extends DataObject implements CategorisationObject
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $has_one = [
|
||||
'Blog' => Blog::class,
|
||||
private static $indexes = [
|
||||
'URLSegment' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -55,6 +53,11 @@ class BlogCategory extends DataObject implements CategorisationObject
|
||||
'BlogPosts' => BlogPost::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $default_sort = '"BlogCategory"."Title" ASC';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -6,14 +6,17 @@ use PageController;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPResponse_Exception;
|
||||
use SilverStripe\Control\RSS\RSSFeed;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\ORM\PaginatedList;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\View\Parsers\URLSegmentFilter;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
|
||||
/**
|
||||
* @method Blog data()
|
||||
*/
|
||||
class BlogController extends PageController
|
||||
{
|
||||
/**
|
||||
@ -31,17 +34,17 @@ class BlogController extends PageController
|
||||
* @var array
|
||||
*/
|
||||
private static $url_handlers = [
|
||||
'tag/$Tag!/$Rss' => 'tag',
|
||||
'category/$Category!/$Rss' => 'category',
|
||||
'tag/$Tag!/$Rss' => 'tag',
|
||||
'category/$Category!/$Rss' => 'category',
|
||||
'archive/$Year!/$Month/$Day' => 'archive',
|
||||
'profile/$URLSegment!' => 'profile'
|
||||
'profile/$Profile!' => 'profile'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $casting = [
|
||||
'MetaTitle' => 'Text',
|
||||
'MetaTitle' => 'Text',
|
||||
'FilterDescription' => 'Text'
|
||||
];
|
||||
|
||||
@ -60,27 +63,11 @@ class BlogController extends PageController
|
||||
*/
|
||||
protected $blogPosts;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function index(HTTPRequest $request)
|
||||
{
|
||||
/**
|
||||
* @var Blog $dataRecord
|
||||
*/
|
||||
$dataRecord = $this->dataRecord;
|
||||
|
||||
$this->blogPosts = $dataRecord->getBlogPosts();
|
||||
|
||||
return $this->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a Blog Member's profile.
|
||||
*
|
||||
* @throws HTTPResponse_Exception
|
||||
*
|
||||
* @return string
|
||||
* @return $this
|
||||
*/
|
||||
public function profile()
|
||||
{
|
||||
@ -88,45 +75,59 @@ class BlogController extends PageController
|
||||
$this->httpError(404, 'Not Found');
|
||||
}
|
||||
|
||||
$profile = $this->getCurrentProfile();
|
||||
|
||||
if (!$profile) {
|
||||
return $this->httpError(404, 'Not Found');
|
||||
// Get profile posts
|
||||
$posts = $this->getCurrentProfilePosts();
|
||||
if (!$posts) {
|
||||
$this->httpError(404, 'Not Found');
|
||||
}
|
||||
|
||||
$this->blogPosts = $this->getCurrentProfilePosts();
|
||||
|
||||
return $this->render();
|
||||
$this->setFilteredPosts($posts);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Member associated with the current URL segment.
|
||||
*
|
||||
* @return null|Member
|
||||
* @return null|Member|BlogMemberExtension
|
||||
*/
|
||||
public function getCurrentProfile()
|
||||
{
|
||||
$urlSegment = $this->request->param('URLSegment');
|
||||
if ($urlSegment) {
|
||||
$filter = URLSegmentFilter::create();
|
||||
// url encode unless it's multibyte (already pre-encoded in the database)
|
||||
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
|
||||
if (!$filter->getAllowMultibyte()) {
|
||||
$urlSegment = rawurlencode($urlSegment);
|
||||
}
|
||||
|
||||
return Member::get()
|
||||
->filter('URLSegment', $urlSegment)
|
||||
->first();
|
||||
$segment = $this->getCurrentProfileURLSegment();
|
||||
if (!$segment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
/** @var Member $profile */
|
||||
$profile = Member::get()
|
||||
->find('URLSegment', $segment);
|
||||
return $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL Segment of current profile
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getCurrentProfileURLSegment()
|
||||
{
|
||||
$segment = isset($this->urlParams['Profile'])
|
||||
? $this->urlParams['Profile']
|
||||
: null;
|
||||
if (!$segment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// url encode unless it's multibyte (already pre-encoded in the database)
|
||||
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
|
||||
return URLSegmentFilter::singleton()->getAllowMultibyte()
|
||||
? $segment
|
||||
: rawurlencode($segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get posts related to the current Member profile.
|
||||
*
|
||||
* @return null|DataList
|
||||
* @return null|DataList|BlogPost[]
|
||||
*/
|
||||
public function getCurrentProfilePosts()
|
||||
{
|
||||
@ -142,166 +143,200 @@ class BlogController extends PageController
|
||||
/**
|
||||
* Renders an archive for a specified date. This can be by year or year/month.
|
||||
*
|
||||
* @return null|string
|
||||
* @return $this
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
public function archive()
|
||||
{
|
||||
/**
|
||||
* @var Blog $dataRecord
|
||||
*/
|
||||
$dataRecord = $this->dataRecord;
|
||||
|
||||
$year = $this->getArchiveYear();
|
||||
$month = $this->getArchiveMonth();
|
||||
$day = $this->getArchiveDay();
|
||||
|
||||
if ($this->request->param('Month') && !$month) {
|
||||
// Validate all values
|
||||
if ($year === false || $month === false || $day === false) {
|
||||
$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;
|
||||
$posts = $this->data()->getArchivedBlogPosts($year, $month, $day);
|
||||
$this->setFilteredPosts($posts);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the archive year from the url.
|
||||
*
|
||||
* @return int
|
||||
* Returns int if valid, current year if not provided, false if invalid value
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
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') {
|
||||
if (isset($this->urlParams['Year'])
|
||||
&& preg_match('/^[0-9]{4}$/', $this->urlParams['Year'])
|
||||
) {
|
||||
return (int)$this->urlParams['Year'];
|
||||
}
|
||||
|
||||
if (empty($this->urlParams['Year']) &&
|
||||
$this->urlParams['Action'] === 'archive'
|
||||
) {
|
||||
return DBDatetime::now()->Year();
|
||||
}
|
||||
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the archive money from the url.
|
||||
*
|
||||
* @return null|int
|
||||
* Returns int if valid, null if not provided, false if invalid value
|
||||
*
|
||||
* @return null|int|false
|
||||
*/
|
||||
public function getArchiveMonth()
|
||||
{
|
||||
$month = $this->request->param('Month');
|
||||
$month = isset($this->urlParams['Month'])
|
||||
? $this->urlParams['Month']
|
||||
: null;
|
||||
|
||||
if (preg_match('/^[0-9]{1,2}$/', $month)) {
|
||||
if ($month > 0 && $month < 13) {
|
||||
if (checkdate($month, 01, $this->getArchiveYear())) {
|
||||
return (int) $month;
|
||||
}
|
||||
}
|
||||
if (!$month) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
if (preg_match('/^[0-9]{1,2}$/', $month)
|
||||
&& $month > 0
|
||||
&& $month < 13
|
||||
) {
|
||||
return (int)$month;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the archive day from the url.
|
||||
*
|
||||
* @return null|int
|
||||
* Returns int if valid, null if not provided, false if invalid value
|
||||
*
|
||||
* @return null|int|false
|
||||
*/
|
||||
public function getArchiveDay()
|
||||
{
|
||||
$day = $this->request->param('Day');
|
||||
$day = isset($this->urlParams['Day'])
|
||||
? $this->urlParams['Day']
|
||||
: null;
|
||||
|
||||
if (preg_match('/^[0-9]{1,2}$/', $day)) {
|
||||
if (checkdate($this->getArchiveMonth(), $day, $this->getArchiveYear())) {
|
||||
return (int) $day;
|
||||
}
|
||||
if (!$day) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
// Cannot calculate day without month and year
|
||||
$month = $this->getArchiveMonth();
|
||||
$year = $this->getArchiveYear();
|
||||
if (!$month || !$year) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/^[0-9]{1,2}$/', $day) && checkdate($month, $day, $year)) {
|
||||
return (int)$day;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the blog posts for a given tag.
|
||||
*
|
||||
* @return null|string
|
||||
* @return DBHTMLText|$this
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
public function tag()
|
||||
{
|
||||
// Ensure tag exists
|
||||
$tag = $this->getCurrentTag();
|
||||
|
||||
if ($tag) {
|
||||
$this->blogPosts = $tag->BlogPosts();
|
||||
|
||||
if ($this->isRSS()) {
|
||||
return $this->rssFeed($this->blogPosts, $tag->getLink());
|
||||
} else {
|
||||
return $this->render();
|
||||
}
|
||||
if (!$tag) {
|
||||
$this->httpError(404, 'Not Found');
|
||||
}
|
||||
|
||||
$this->httpError(404, 'Not Found');
|
||||
// Get posts with this tag
|
||||
$posts = $this
|
||||
->data()
|
||||
->getBlogPosts()
|
||||
->filter(['Tags.URLSegment' => $tag->URLSegment]); // Soft duplicate handling
|
||||
|
||||
return null;
|
||||
$this->setFilteredPosts($posts);
|
||||
|
||||
// Render as RSS if provided
|
||||
if ($this->isRSS()) {
|
||||
return $this->rssFeed($posts, $tag->getLink());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag Getter for use in templates.
|
||||
* Get BlogTag assigned to current filter
|
||||
*
|
||||
* @return null|BlogTag
|
||||
*/
|
||||
public function getCurrentTag()
|
||||
{
|
||||
/**
|
||||
* @var Blog $dataRecord
|
||||
*/
|
||||
$dataRecord = $this->dataRecord;
|
||||
$tag = $this->request->param('Tag');
|
||||
if ($tag) {
|
||||
$filter = URLSegmentFilter::create();
|
||||
// url encode unless it's multibyte (already pre-encoded in the database)
|
||||
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
|
||||
if (!$filter->getAllowMultibyte()) {
|
||||
$tag = rawurlencode($tag);
|
||||
}
|
||||
|
||||
return $dataRecord->Tags()
|
||||
->filter('URLSegment', $tag)
|
||||
->first();
|
||||
$segment = $this->getCurrentTagURLSegment();
|
||||
if (!$segment) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
/** @var BlogTag $tag */
|
||||
$tag = $this
|
||||
->data()
|
||||
->Tags(false)// Show "no results" instead of "404"
|
||||
->find('URLSegment', $segment);
|
||||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URLSegment of selected category (not: URLEncoded based on multibyte)
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentTagURLSegment()
|
||||
{
|
||||
$segment = isset($this->urlParams['Tag'])
|
||||
? $this->urlParams['Tag']
|
||||
: null;
|
||||
|
||||
// url encode unless it's multibyte (already pre-encoded in the database)
|
||||
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
|
||||
return URLSegmentFilter::singleton()->getAllowMultibyte()
|
||||
? $segment
|
||||
: rawurlencode($segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the blog posts for a given category.
|
||||
*
|
||||
* @return null|string
|
||||
* @return DBHTMLText|$this
|
||||
* @throws HTTPResponse_Exception
|
||||
*/
|
||||
public function category()
|
||||
{
|
||||
$category = $this->getCurrentCategory();
|
||||
|
||||
if ($category) {
|
||||
$this->blogPosts = $category->BlogPosts();
|
||||
|
||||
if ($this->isRSS()) {
|
||||
return $this->rssFeed($this->blogPosts, $category->getLink());
|
||||
}
|
||||
return $this->render();
|
||||
if (!$category) {
|
||||
$this->httpError(404, 'Not Found');
|
||||
}
|
||||
|
||||
$this->httpError(404, 'Not Found');
|
||||
// Get posts with this category
|
||||
$posts = $this
|
||||
->data()
|
||||
->getBlogPosts()
|
||||
->filter(['Categories.URLSegment' => $category->URLSegment]); // Soft duplicate handling
|
||||
$this->setFilteredPosts($posts);
|
||||
|
||||
return null;
|
||||
if ($this->isRSS()) {
|
||||
return $this->rssFeed($posts, $category->getLink());
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,24 +346,35 @@ class BlogController extends PageController
|
||||
*/
|
||||
public function getCurrentCategory()
|
||||
{
|
||||
/**
|
||||
* @var Blog $dataRecord
|
||||
*/
|
||||
$dataRecord = $this->dataRecord;
|
||||
$category = $this->request->param('Category');
|
||||
if ($category) {
|
||||
$filter = URLSegmentFilter::create();
|
||||
// url encode unless it's multibyte (already pre-encoded in the database)
|
||||
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
|
||||
if (!$filter->getAllowMultibyte()) {
|
||||
$category = rawurlencode($category);
|
||||
}
|
||||
|
||||
return $dataRecord->Categories()
|
||||
->filter('URLSegment', $category)
|
||||
->first();
|
||||
$segment = $this->getCurrentCategoryURLSegment();
|
||||
if (!$segment) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
/** @var BlogCategory $category */
|
||||
$category = $this
|
||||
->data()
|
||||
->Categories(false)// Show "no results" instead of "404"
|
||||
->find('URLSegment', $segment);
|
||||
return $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URLSegment of selected category
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCurrentCategoryURLSegment()
|
||||
{
|
||||
$segment = isset($this->urlParams['Category'])
|
||||
? $this->urlParams['Category']
|
||||
: null;
|
||||
|
||||
// url encode unless it's multibyte (already pre-encoded in the database)
|
||||
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
|
||||
return URLSegmentFilter::singleton()->getAllowMultibyte()
|
||||
? $segment
|
||||
: rawurlencode($segment);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -406,13 +452,13 @@ class BlogController extends PageController
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->owner->getArchiveYear()) {
|
||||
if ($this->owner->getArchiveDay()) {
|
||||
$date = $this->owner->getArchiveDate()->Nice();
|
||||
} elseif ($this->owner->getArchiveMonth()) {
|
||||
$date = $this->owner->getArchiveDate()->format('MMMM, y');
|
||||
if ($this->getArchiveYear()) {
|
||||
if ($this->getArchiveDay()) {
|
||||
$date = $this->getArchiveDate()->Nice();
|
||||
} elseif ($this->getArchiveMonth()) {
|
||||
$date = $this->getArchiveDate()->format('MMMM, y');
|
||||
} else {
|
||||
$date = $this->owner->getArchiveDate()->format('y');
|
||||
$date = $this->getArchiveDate()->format('y');
|
||||
}
|
||||
|
||||
$items[] = _t(
|
||||
@ -436,6 +482,28 @@ class BlogController extends PageController
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filtered blog posts
|
||||
*
|
||||
* @return DataList|BlogPost[]
|
||||
*/
|
||||
public function getFilteredPosts()
|
||||
{
|
||||
return $this->blogPosts ?: $this->data()->getBlogPosts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set filtered posts
|
||||
*
|
||||
* @param SS_List|BlogPost[] $posts
|
||||
* @return $this
|
||||
*/
|
||||
public function setFilteredPosts($posts)
|
||||
{
|
||||
$this->blogPosts = $posts;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of paginated blog posts based on the BlogPost dataList.
|
||||
*
|
||||
@ -443,12 +511,12 @@ class BlogController extends PageController
|
||||
*/
|
||||
public function PaginatedList()
|
||||
{
|
||||
$allPosts = $this->blogPosts ?: ArrayList::create();
|
||||
$allPosts = $this->getFilteredPosts();
|
||||
$posts = PaginatedList::create($allPosts);
|
||||
|
||||
// Set appropriate page size
|
||||
if ($this->PostsPerPage > 0) {
|
||||
$pageSize = $this->PostsPerPage;
|
||||
if ($this->data()->PostsPerPage > 0) {
|
||||
$pageSize = $this->data()->PostsPerPage;
|
||||
} elseif ($count = $allPosts->count()) {
|
||||
$pageSize = $count;
|
||||
} else {
|
||||
@ -482,7 +550,7 @@ class BlogController extends PageController
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the absolute link to the previous page for use in the page meta tags. This helps search engines
|
||||
* find the pagination and index all pages properly.
|
||||
*
|
||||
@ -507,14 +575,7 @@ class BlogController extends PageController
|
||||
*/
|
||||
public function rss()
|
||||
{
|
||||
/**
|
||||
* @var Blog $dataRecord
|
||||
*/
|
||||
$dataRecord = $this->dataRecord;
|
||||
|
||||
$this->blogPosts = $dataRecord->getBlogPosts();
|
||||
|
||||
return $this->rssFeed($this->blogPosts, $this->Link());
|
||||
return $this->rssFeed($this->getFilteredPosts(), $this->Link());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -561,13 +622,18 @@ class BlogController extends PageController
|
||||
* Displays an RSS feed of the given blog posts.
|
||||
*
|
||||
* @param DataList $blogPosts
|
||||
* @param string $link
|
||||
* @param string $link
|
||||
*
|
||||
* @return string
|
||||
* @return DBHTMLText
|
||||
*/
|
||||
protected function rssFeed($blogPosts, $link)
|
||||
{
|
||||
$rss = RSSFeed::create($blogPosts, $link, $this->MetaTitle, $this->MetaDescription);
|
||||
$rss = RSSFeed::create(
|
||||
$blogPosts,
|
||||
$link,
|
||||
$this->getMetaTitle(),
|
||||
$this->data()->MetaDescription
|
||||
);
|
||||
|
||||
$this->extend('updateRss', $rss);
|
||||
|
||||
@ -581,7 +647,6 @@ class BlogController extends PageController
|
||||
*/
|
||||
protected function isRSS()
|
||||
{
|
||||
$rss = $this->request->param('Rss');
|
||||
return (is_string($rss) && strcasecmp($rss, 'rss') == 0);
|
||||
return isset($this->urlParams['RSS']) && strcasecmp($this->urlParams['RSS'], 'rss') == 0;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\Forms\GridField\GridFieldAddNewButton;
|
||||
use SilverStripe\Forms\Tab;
|
||||
use SilverStripe\Forms\TextareaField;
|
||||
use SilverStripe\ORM\DataExtension;
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\View\Parsers\URLSegmentFilter;
|
||||
use SilverStripe\View\Requirements;
|
||||
@ -17,6 +18,10 @@ use SilverStripe\View\Requirements;
|
||||
/**
|
||||
* This class is responsible for add Blog specific behaviour to Members.
|
||||
*
|
||||
* @property string $URLSegment
|
||||
* @property string $BlogProfileSummary
|
||||
* @method Image BlogProfileImage()
|
||||
* @method ManyManyList|BlogPost[] BlogPosts()
|
||||
*/
|
||||
class BlogMemberExtension extends DataExtension
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ use SilverStripe\Forms\Tab;
|
||||
use SilverStripe\Forms\TabSet;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
use SilverStripe\ORM\ValidationResult;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Permission;
|
||||
@ -20,7 +21,7 @@ use SilverStripe\View\Parsers\URLSegmentFilter;
|
||||
trait BlogObject
|
||||
{
|
||||
/**
|
||||
* @return DataList
|
||||
* @return ManyManyList|BlogPost[]
|
||||
*/
|
||||
public function BlogPosts()
|
||||
{
|
||||
@ -31,6 +32,22 @@ trait BlogObject
|
||||
return $blogPosts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blog this tag was queried from
|
||||
*
|
||||
* @return Blog|null
|
||||
*/
|
||||
public function Blog()
|
||||
{
|
||||
$blogID = $this->getBlogID();
|
||||
if ($blogID) {
|
||||
/** @var Blog $blog */
|
||||
$blog = Blog::get()->byID($blogID);
|
||||
return $blog;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -50,6 +67,24 @@ trait BlogObject
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of times this object has blog posts in the current blog
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBlogCount()
|
||||
{
|
||||
$blog = $this->Blog();
|
||||
if (!$blog) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this
|
||||
->BlogPosts()
|
||||
->filter(['ParentID' => $blog->ID])
|
||||
->Count();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return ValidationResult
|
||||
@ -62,11 +97,6 @@ trait BlogObject
|
||||
return $validation;
|
||||
}
|
||||
|
||||
$blog = $this->Blog();
|
||||
if (!$blog || !$blog->exists()) {
|
||||
return $validation;
|
||||
}
|
||||
|
||||
if ($this->getDuplicatesByField('Title')->count() > 0) {
|
||||
$validation->addError($this->getDuplicateError(), self::DUPLICATE_EXCEPTION);
|
||||
}
|
||||
@ -75,14 +105,18 @@ trait BlogObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a relative link to this category.
|
||||
* Returns a relative link to this category or tag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLink()
|
||||
{
|
||||
$blog = $this->Blog();
|
||||
if (!$blog) {
|
||||
return null;
|
||||
}
|
||||
return Controller::join_links(
|
||||
$this->Blog()->Link(),
|
||||
$blog->Link(),
|
||||
$this->getListUrlSegment(),
|
||||
$this->URLSegment
|
||||
);
|
||||
@ -103,7 +137,8 @@ trait BlogObject
|
||||
return $extended;
|
||||
}
|
||||
|
||||
return $this->Blog()->canView($member);
|
||||
$blog = $this->Blog();
|
||||
return $blog && $blog->canView($member);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,7 +172,8 @@ trait BlogObject
|
||||
return $extended;
|
||||
}
|
||||
|
||||
return $this->Blog()->canDelete($member);
|
||||
$blog = $this->Blog();
|
||||
return $blog && $blog->canDelete($member);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,17 +191,36 @@ trait BlogObject
|
||||
return $extended;
|
||||
}
|
||||
|
||||
return $this->Blog()->canEdit($member);
|
||||
$blog = $this->Blog();
|
||||
return $blog && $blog->canEdit($member);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBlogID()
|
||||
{
|
||||
return $this->getSourceQueryParam('BlogID');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a blog ID for this record
|
||||
*
|
||||
* @param int $id
|
||||
* @return $this
|
||||
*/
|
||||
public function setBlogID($id)
|
||||
{
|
||||
$this->setSourceQueryParam('BlogID', $id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function onBeforeWrite()
|
||||
{
|
||||
parent::onBeforeWrite();
|
||||
|
||||
if ($this->exists() || empty($this->URLSegment)) {
|
||||
return $this->generateURLSegment();
|
||||
$this->generateURLSegment();
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,7 +233,7 @@ trait BlogObject
|
||||
*/
|
||||
public function generateURLSegment($increment = 0)
|
||||
{
|
||||
$increment = (int) $increment;
|
||||
$increment = (int)$increment;
|
||||
$filter = URLSegmentFilter::create();
|
||||
|
||||
// Setting this to on. Because of the UI flow, it would be quite a lot of work
|
||||
@ -209,12 +264,7 @@ trait BlogObject
|
||||
protected function getDuplicatesByField($field)
|
||||
{
|
||||
$duplicates = DataList::create(self::class)
|
||||
->filter(
|
||||
[
|
||||
$field => $this->$field,
|
||||
'BlogID' => (int) $this->BlogID
|
||||
]
|
||||
);
|
||||
->filter([$field => $this->$field]);
|
||||
|
||||
if ($this->ID) {
|
||||
$duplicates = $duplicates->exclude('ID', $this->ID);
|
||||
|
@ -313,14 +313,6 @@ class BlogPost extends Page
|
||||
}
|
||||
|
||||
// Get categories and tags
|
||||
$parent = $this->Parent();
|
||||
$categories = $parent instanceof Blog
|
||||
? $parent->Categories()
|
||||
: BlogCategory::get();
|
||||
$tags = $parent instanceof Blog
|
||||
? $parent->Tags()
|
||||
: BlogTag::get();
|
||||
|
||||
// @todo: Reimplement the sidebar
|
||||
// $options = BlogAdminSidebar::create(
|
||||
$fields->addFieldsToTab(
|
||||
@ -330,7 +322,7 @@ class BlogPost extends Page
|
||||
TagField::create(
|
||||
'Categories',
|
||||
_t(__CLASS__ . '.Categories', 'Categories'),
|
||||
$categories,
|
||||
BlogCategory::get(),
|
||||
$this->Categories()
|
||||
)
|
||||
->setCanCreate($this->canCreateCategories())
|
||||
@ -338,7 +330,7 @@ class BlogPost extends Page
|
||||
TagField::create(
|
||||
'Tags',
|
||||
_t(__CLASS__ . '.Tags', 'Tags'),
|
||||
$tags,
|
||||
BlogTag::get(),
|
||||
$this->Tags()
|
||||
)
|
||||
->setCanCreate($this->canCreateTags())
|
||||
@ -498,32 +490,6 @@ class BlogPost extends Page
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Sets blog relationship on all categories and tags assigned to this post.
|
||||
*/
|
||||
public function onAfterWrite()
|
||||
{
|
||||
parent::onAfterWrite();
|
||||
|
||||
foreach ($this->Categories() as $category) {
|
||||
/**
|
||||
* @var BlogCategory $category
|
||||
*/
|
||||
$category->BlogID = $this->ParentID;
|
||||
$category->write();
|
||||
}
|
||||
|
||||
foreach ($this->Tags() as $tag) {
|
||||
/**
|
||||
* @var BlogTag $tag
|
||||
*/
|
||||
$tag->BlogID = $this->ParentID;
|
||||
$tag->write();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -816,4 +782,16 @@ class BlogPost extends Page
|
||||
$this->Authors()->add($member);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* So that tags / categories queried through this post generate the correct Link()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getInheritableQueryParams()
|
||||
{
|
||||
$params = parent::getInheritableQueryParams();
|
||||
$params['BlogID'] = $this->ParentID;
|
||||
return $params;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace SilverStripe\Blog\Model;
|
||||
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
|
||||
/**
|
||||
* A blog tag for keyword descriptions of a blog post.
|
||||
@ -10,9 +11,9 @@ use SilverStripe\ORM\DataObject;
|
||||
*
|
||||
* @method Blog Blog()
|
||||
*
|
||||
* @method ManyManyList|BlogPost[] BlogPosts()
|
||||
* @property string $Title
|
||||
* @property string $URLSegment
|
||||
* @property int $BlogID
|
||||
*/
|
||||
class BlogTag extends DataObject implements CategorisationObject
|
||||
{
|
||||
@ -44,8 +45,8 @@ class BlogTag extends DataObject implements CategorisationObject
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $has_one = [
|
||||
'Blog' => Blog::class
|
||||
private static $indexes = [
|
||||
'URLSegment' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -55,6 +56,11 @@ class BlogTag extends DataObject implements CategorisationObject
|
||||
'BlogPosts' => BlogPost::class
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private static $default_sort = '"BlogTag"."Title" ASC';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -2,10 +2,17 @@
|
||||
|
||||
namespace SilverStripe\Blog\Model;
|
||||
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
|
||||
/**
|
||||
* @method ManyManyList BlogPosts
|
||||
* @method ManyManyList|BlogPost[] BlogPosts()
|
||||
*/
|
||||
interface CategorisationObject
|
||||
{
|
||||
|
||||
/**
|
||||
* Number of times this object has blog posts in the current blog
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getBlogCount();
|
||||
}
|
||||
|
140
src/Tasks/FixBlogDuplicatesTask.php
Normal file
140
src/Tasks/FixBlogDuplicatesTask.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Blog\Tasks;
|
||||
|
||||
use SilverStripe\Blog\Model\BlogCategory;
|
||||
use SilverStripe\Blog\Model\BlogTag;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Dev\BuildTask;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\View\HTML;
|
||||
|
||||
class FixBlogDuplicatesTask extends BuildTask
|
||||
{
|
||||
private static $segment = 'FixBlogDuplicatesTask';
|
||||
|
||||
protected $title = 'Fix blog duplicate categories / tags';
|
||||
|
||||
protected $description = 'Merge categories and tags with the same title';
|
||||
|
||||
public function run($request)
|
||||
{
|
||||
$this->dedupe(BlogTag::class, 'BlogPost_Tags', 'BlogTagID');
|
||||
$this->dedupe(BlogCategory::class, 'BlogPost_Categories', 'BlogCategoryID');
|
||||
}
|
||||
|
||||
/**
|
||||
* Log message to console / page
|
||||
*
|
||||
* @param string $message
|
||||
*/
|
||||
protected function message($message)
|
||||
{
|
||||
if (Director::is_cli()) {
|
||||
echo "{$message}\n";
|
||||
} else {
|
||||
echo HTML::createTag('p', [], Convert::raw2xml($message));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress used for CLI output
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $printedDots = 0;
|
||||
|
||||
/**
|
||||
* Render progress dots (20 dots per column)
|
||||
*
|
||||
* @param $current
|
||||
* @param int $total
|
||||
* @param string $character
|
||||
*/
|
||||
protected function progress($current, $total = 0, $character = '.')
|
||||
{
|
||||
if (!Director::is_cli()) {
|
||||
return;
|
||||
}
|
||||
while ($this->printedDots < $current) {
|
||||
echo $character;
|
||||
$this->printedDots++;
|
||||
if ($this->printedDots % 80 === 0) {
|
||||
if ($total) {
|
||||
$len = strlen($total);
|
||||
echo str_pad("{$this->printedDots}/{$total}", $len * 2 + 2, ' ', STR_PAD_LEFT);
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deduplicate the given class
|
||||
*
|
||||
* @param string $class Class name to dedupe
|
||||
* @param string $mappingTable Table name mapping
|
||||
* @param string $relationField Name of foreign key relation field on mapping table
|
||||
*/
|
||||
protected function dedupe($class, $mappingTable, $relationField)
|
||||
{
|
||||
$this->printedDots = 0;
|
||||
|
||||
// Find all duplicates
|
||||
$itemTable = DataObject::getSchema()->tableName($class);
|
||||
$duplicates = SQLSelect::create()
|
||||
->setSelect([
|
||||
'Title' => '"Title"',
|
||||
'Count' => 'COUNT(*)',
|
||||
'UseID' => 'MIN("ID")',
|
||||
])
|
||||
->setFrom($itemTable)
|
||||
->setGroupBy('"Title"')
|
||||
->setHaving('"Count" > 1');
|
||||
|
||||
$count = $duplicates->count();
|
||||
|
||||
$this->message("Found {$count} items with duplicates for type {$class}");
|
||||
|
||||
if (!$count) {
|
||||
return;
|
||||
}
|
||||
|
||||
$done = 0;
|
||||
foreach ($duplicates->execute() as $duplicate) {
|
||||
$title = $duplicate['Title'];
|
||||
$id = $duplicate['UseID'];
|
||||
|
||||
DB::prepared_query(
|
||||
<<<SQL
|
||||
UPDATE "{$mappingTable}"
|
||||
INNER JOIN "{$itemTable}" ON "{$mappingTable}"."{$relationField}" = "{$itemTable}"."ID"
|
||||
SET "{$mappingTable}"."{$relationField}" = ?
|
||||
WHERE "{$itemTable}"."Title" = ?
|
||||
SQL
|
||||
,
|
||||
[$id, $title]
|
||||
);
|
||||
|
||||
// Delete duplicates
|
||||
$duplicateItems = DataObject::get($class)->filter([
|
||||
'Title' => $title,
|
||||
'ID:not' => $id,
|
||||
]);
|
||||
/** @var DataObject $duplicateItem */
|
||||
foreach ($duplicateItems as $duplicateItem) {
|
||||
$duplicateItem->delete();
|
||||
}
|
||||
|
||||
// Update progress bar
|
||||
$done++;
|
||||
$this->progress($done, $count);
|
||||
}
|
||||
|
||||
$this->progress("");
|
||||
$this->progress("Completed cleaning duplicates for {$class}");
|
||||
}
|
||||
}
|
@ -3,11 +3,10 @@
|
||||
namespace SilverStripe\Blog\Widgets;
|
||||
|
||||
use SilverStripe\Blog\Model\Blog;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Blog\Model\BlogTag;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\Widgets\Model\Widget;
|
||||
|
||||
if (!class_exists(Widget::class)) {
|
||||
@ -73,53 +72,42 @@ class BlogTagsCloudWidget extends Widget
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
if ($blog = $this->Blog()) {
|
||||
$escapedID = Convert::raw2sql($blog->ID);
|
||||
$sql = 'SELECT DISTINCT "BlogTag"."URLSegment","BlogTag"."Title",Count("BlogTagID") AS "TagCount"
|
||||
from "BlogPost_Tags"
|
||||
INNER JOIN "BlogPost"
|
||||
ON "BlogPost"."ID" = "BlogPost_Tags"."BlogPostID"
|
||||
INNER JOIN "BlogTag"
|
||||
ON "BlogTag"."ID" = "BlogPost_Tags"."BlogTagID"
|
||||
WHERE "BlogID" = ' . $escapedID
|
||||
. ' GROUP By "BlogTag"."URLSegment","BlogTag"."Title"
|
||||
ORDER BY "Title"';
|
||||
|
||||
$records = DB::query($sql);
|
||||
$bloglink = $blog->Link();
|
||||
$maxTagCount = 0;
|
||||
|
||||
// create DataObjects that can be used to render the tag cloud
|
||||
$tags = ArrayList::create();
|
||||
foreach ($records as $record) {
|
||||
$tag = DataObject::create();
|
||||
$tag->TagName = $record['Title'];
|
||||
$link = $bloglink.'tag/'.$record['URLSegment'];
|
||||
$tag->Link = $link;
|
||||
if ($record['TagCount'] > $maxTagCount) {
|
||||
$maxTagCount = $record['TagCount'];
|
||||
}
|
||||
$tag->TagCount = $record['TagCount'];
|
||||
$tags->push($tag);
|
||||
}
|
||||
|
||||
// normalize the tag counts from 1 to 10
|
||||
if ($maxTagCount) {
|
||||
$tagfactor = 10 / $maxTagCount;
|
||||
foreach ($tags->getIterator() as $tag) {
|
||||
$normalized = round($tagfactor * ($tag->TagCount));
|
||||
$tag->NormalizedTag = $normalized;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $tags;
|
||||
// Check blog exists
|
||||
$blog = $this->Blog();
|
||||
if (!$blog) {
|
||||
return ArrayList::create([]);
|
||||
}
|
||||
|
||||
return [];
|
||||
// create ArrayData that can be used to render the tag cloud
|
||||
$maxTagCount = 0;
|
||||
$tags = ArrayList::create();
|
||||
/** @var BlogTag $record */
|
||||
foreach ($blog->Tags() as $record) {
|
||||
// Remember max count found
|
||||
$count = $record->getBlogCount();
|
||||
$maxTagCount = $maxTagCount > $count ? $maxTagCount : $count;
|
||||
|
||||
// Save
|
||||
$tags->push(ArrayData::create([
|
||||
'TagName' => $record->Title,
|
||||
'Link' => $record->getLink(),
|
||||
'TagCount' => $count,
|
||||
]));
|
||||
}
|
||||
|
||||
// normalize the tag counts from 1 to 10
|
||||
if ($maxTagCount) {
|
||||
$tagfactor = 10 / $maxTagCount;
|
||||
foreach ($tags->getIterator() as $tag) {
|
||||
$normalized = round($tagfactor * ($tag->TagCount));
|
||||
$tag->NormalizedTag = $normalized;
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ 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;
|
||||
@ -70,15 +69,19 @@ class BlogCategoryTest extends FunctionalTest
|
||||
*/
|
||||
public function testAllowMultibyteUrlSegment()
|
||||
{
|
||||
/** @var Blog $blog */
|
||||
$blog = $this->objFromFixture(Blog::class, 'FirstBlog');
|
||||
|
||||
$cat = new BlogCategory();
|
||||
$cat->BlogID = $blog->ID;
|
||||
$cat->Title = 'تست';
|
||||
$cat->write();
|
||||
|
||||
|
||||
// urlencoded
|
||||
$this->assertEquals('%D8%AA%D8%B3%D8%AA', $cat->URLSegment);
|
||||
$link = Controller::join_links($cat->Blog()->Link(), 'category', '%D8%AA%D8%B3%D8%AA');
|
||||
$this->assertEquals($link, $cat->getLink());
|
||||
$expectedLink = Controller::join_links($blog->Link('category'), '%D8%AA%D8%B3%D8%AA');
|
||||
$actualLink = $blog->Categories(false)->byID($cat->ID)->getLink();
|
||||
$this->assertEquals($expectedLink, $actualLink);
|
||||
}
|
||||
|
||||
public function testCanView()
|
||||
@ -88,8 +91,9 @@ class BlogCategoryTest extends FunctionalTest
|
||||
$this->objFromFixture(Member::class, 'Admin');
|
||||
|
||||
$editor = $this->objFromFixture(Member::class, 'Editor');
|
||||
$category = $this->objFromFixture(BlogCategory::class, 'SecondCategory');
|
||||
|
||||
/** @var Blog $secondBlog */
|
||||
$secondBlog = $this->objFromFixture(Blog::class, 'SecondBlog');
|
||||
$category = $secondBlog->Categories(false)->find('URLSegment', 'second-category');
|
||||
$this->assertFalse($category->canView($editor), 'Editor should not be able to view category.');
|
||||
}
|
||||
|
||||
@ -103,20 +107,26 @@ class BlogCategoryTest extends FunctionalTest
|
||||
$admin = $this->objFromFixture(Member::class, 'Admin');
|
||||
$editor = $this->objFromFixture(Member::class, 'Editor');
|
||||
|
||||
$category = $this->objFromFixture(BlogCategory::class, 'FirstCategory');
|
||||
/** @var Blog $firstBlog */
|
||||
$firstBlog = $this->objFromFixture(Blog::class, 'FirstBlog');
|
||||
$firstCategory = $firstBlog->Categories(false)->find('URLSegment', 'first-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($firstCategory->canEdit($admin), 'Admin should be able to edit category.');
|
||||
$this->assertTrue($firstCategory->canEdit($editor), 'Editor should be able to edit category.');
|
||||
|
||||
$category = $this->objFromFixture(BlogCategory::class, 'SecondCategory');
|
||||
/** @var Blog $secondBlog */
|
||||
$secondBlog = $this->objFromFixture(Blog::class, 'SecondBlog');
|
||||
$secondCategory = $secondBlog->Categories(false)->find('URLSegment', 'second-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->assertTrue($secondCategory->canEdit($admin), 'Admin should be able to edit category.');
|
||||
$this->assertFalse($secondCategory->canEdit($editor), 'Editor should not be able to edit category.');
|
||||
|
||||
$category = $this->objFromFixture(BlogCategory::class, 'ThirdCategory');
|
||||
/** @var Blog $secondBlog */
|
||||
$thirdBlog = $this->objFromFixture(Blog::class, 'ThirdBlog');
|
||||
$thirdCategory = $thirdBlog->Categories(false)->find('URLSegment', 'third-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($thirdCategory->canEdit($admin), 'Admin should always be able to edit category.');
|
||||
$this->assertTrue($thirdCategory->canEdit($editor), 'Editor should be able to edit category.');
|
||||
}
|
||||
|
||||
public function testCanCreate()
|
||||
@ -126,7 +136,7 @@ class BlogCategoryTest extends FunctionalTest
|
||||
$admin = $this->objFromFixture(Member::class, 'Admin');
|
||||
$editor = $this->objFromFixture(Member::class, 'Editor');
|
||||
|
||||
$category = singleton(BlogCategory::class);
|
||||
$category = BlogCategory::singleton();
|
||||
|
||||
$this->assertTrue($category->canCreate($admin), 'Admin should be able to create category.');
|
||||
$this->assertTrue($category->canCreate($editor), 'Editor should be able to create category.');
|
||||
@ -139,43 +149,45 @@ class BlogCategoryTest extends FunctionalTest
|
||||
$admin = $this->objFromFixture(Member::class, 'Admin');
|
||||
$editor = $this->objFromFixture(Member::class, 'Editor');
|
||||
|
||||
$category = $this->objFromFixture(BlogCategory::class, 'FirstCategory');
|
||||
/** @var Blog $firstBlog */
|
||||
$firstBlog = $this->objFromFixture(Blog::class, 'FirstBlog');
|
||||
$firstCategory = $firstBlog->Categories(false)->find('URLSegment', 'first-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($firstCategory->canDelete($admin), 'Admin should be able to delete category.');
|
||||
$this->assertTrue($firstCategory->canDelete($editor), 'Editor should be able to category category.');
|
||||
|
||||
$category = $this->objFromFixture(BlogCategory::class, 'SecondCategory');
|
||||
$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.');
|
||||
/** @var Blog $secondBlog */
|
||||
$secondBlog = $this->objFromFixture(Blog::class, 'SecondBlog');
|
||||
$secondCategory = $secondBlog->Categories(false)->find('URLSegment', 'second-category');
|
||||
|
||||
$category = $this->objFromFixture(BlogCategory::class, 'ThirdCategory');
|
||||
$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($secondCategory->canDelete($admin), 'Admin should be able to delete category.');
|
||||
$this->assertFalse($secondCategory->canDelete($editor), 'Editor should not be able to delete category.');
|
||||
|
||||
/** @var Blog $secondBlog */
|
||||
$thirdBlog = $this->objFromFixture(Blog::class, 'ThirdBlog');
|
||||
$thirdCategory = $thirdBlog->Categories(false)->find('URLSegment', 'third-category');
|
||||
|
||||
$this->assertTrue($thirdCategory->canDelete($admin), 'Admin should always be able to delete category.');
|
||||
$this->assertTrue($thirdCategory->canDelete($editor), 'Editor should be able to delete category.');
|
||||
}
|
||||
|
||||
public function testDuplicateCategories()
|
||||
{
|
||||
$this->expectException(ValidationException::class);
|
||||
$this->expectExceptionMessage('A blog category already exists with that name.');
|
||||
|
||||
$blog = new Blog();
|
||||
$blog->Title = 'Testing for duplicate categories';
|
||||
$blog->write();
|
||||
|
||||
$category = new BlogCategory();
|
||||
$category->Title = 'Test';
|
||||
$category->BlogID = $blog->ID;
|
||||
$category->URLSegment = 'test';
|
||||
$category->write();
|
||||
|
||||
$category = new BlogCategory();
|
||||
$category->Title = 'Test';
|
||||
$category->URLSegment = 'test';
|
||||
$category->BlogID = $blog->ID;
|
||||
try {
|
||||
$category->write();
|
||||
$this->fail('Duplicate BlogCategory written');
|
||||
} catch (ValidationException $e) {
|
||||
$messages = $e->getResult()->getMessages();
|
||||
$this->assertCount(1, $messages);
|
||||
$this->assertEquals(BlogTag::DUPLICATE_EXCEPTION, $messages[0]['messageType']);
|
||||
}
|
||||
$category->write();
|
||||
}
|
||||
}
|
||||
|
@ -61,14 +61,15 @@ class BlogTagTest extends FunctionalTest
|
||||
*/
|
||||
public function testAllowMultibyteUrlSegment()
|
||||
{
|
||||
/** @var Blog $blog */
|
||||
$blog = $this->objFromFixture(Blog::class, 'FirstBlog');
|
||||
$tag = new BlogTag();
|
||||
$tag->BlogID = $blog->ID;
|
||||
$tag->setBlogID($blog->ID);
|
||||
$tag->Title = 'تست';
|
||||
$tag->write();
|
||||
// urlencoded
|
||||
$this->assertEquals('%D8%AA%D8%B3%D8%AA', $tag->URLSegment);
|
||||
$link = Controller::join_links($tag->Blog()->Link(), 'tag', '%D8%AA%D8%B3%D8%AA');
|
||||
$link = Controller::join_links($blog->Link(), 'tag', '%D8%AA%D8%B3%D8%AA');
|
||||
$this->assertEquals($link, $tag->getLink());
|
||||
}
|
||||
|
||||
@ -82,15 +83,19 @@ class BlogTagTest extends FunctionalTest
|
||||
$admin = $this->objFromFixture(Member::class, 'Admin');
|
||||
$editor = $this->objFromFixture(Member::class, 'Editor');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'FirstTag');
|
||||
/** @var Blog $firstBlog */
|
||||
$firstBlog = $this->objFromFixture(Blog::class, 'FirstBlog');
|
||||
$firstTag = $firstBlog->Tags(false)->find('URLSegment', 'first-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($firstTag->canView($admin), 'Admin should be able to view tag.');
|
||||
$this->assertTrue($firstTag->canView($editor), 'Editor should be able to view tag.');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'SecondTag');
|
||||
/** @var Blog $secondBlog */
|
||||
$secondBlog = $this->objFromFixture(Blog::class, 'SecondBlog');
|
||||
$secondTag = $secondBlog->Tags(false)->find('URLSegment', 'second-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->assertTrue($secondTag->canView($admin), 'Admin should be able to view tag.');
|
||||
$this->assertFalse($secondTag->canView($editor), 'Editor should not be able to view tag.');
|
||||
}
|
||||
|
||||
public function testCanEdit()
|
||||
@ -100,20 +105,26 @@ class BlogTagTest extends FunctionalTest
|
||||
$admin = $this->objFromFixture(Member::class, 'Admin');
|
||||
$editor = $this->objFromFixture(Member::class, 'Editor');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'FirstTag');
|
||||
/** @var Blog $firstBlog */
|
||||
$firstBlog = $this->objFromFixture(Blog::class, 'FirstBlog');
|
||||
$firstTag = $firstBlog->Tags(false)->find('URLSegment', 'first-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($firstTag->canEdit($admin), 'Admin should be able to edit tag.');
|
||||
$this->assertTrue($firstTag->canEdit($editor), 'Editor should be able to edit tag.');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'SecondTag');
|
||||
/** @var Blog $secondBlog */
|
||||
$secondBlog = $this->objFromFixture(Blog::class, 'SecondBlog');
|
||||
$secondTag = $secondBlog->Tags(false)->find('URLSegment', 'second-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->assertTrue($secondTag->canEdit($admin), 'Admin should be able to edit tag.');
|
||||
$this->assertFalse($secondTag->canEdit($editor), 'Editor should not be able to edit tag.');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'ThirdTag');
|
||||
/** @var Blog $thirdBlog */
|
||||
$thirdBlog = $this->objFromFixture(Blog::class, 'ThirdBlog');
|
||||
$thirdTag = $thirdBlog->Tags(false)->find('URLSegment', 'third-tag');
|
||||
|
||||
$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($thirdTag->canEdit($admin), 'Admin should always be able to edit tags.');
|
||||
$this->assertTrue($thirdTag->canEdit($editor), 'Editor should be able to edit tag.');
|
||||
}
|
||||
|
||||
public function testCanCreate()
|
||||
@ -136,20 +147,26 @@ class BlogTagTest extends FunctionalTest
|
||||
$admin = $this->objFromFixture(Member::class, 'Admin');
|
||||
$editor = $this->objFromFixture(Member::class, 'Editor');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'FirstTag');
|
||||
/** @var Blog $firstBlog */
|
||||
$firstBlog = $this->objFromFixture(Blog::class, 'FirstBlog');
|
||||
$firstTag = $firstBlog->Tags(false)->find('URLSegment', 'first-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($firstTag->canDelete($admin), 'Admin should be able to delete tag.');
|
||||
$this->assertTrue($firstTag->canDelete($editor), 'Editor should be able to delete tag.');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'SecondTag');
|
||||
/** @var Blog $secondBlog */
|
||||
$secondBlog = $this->objFromFixture(Blog::class, 'SecondBlog');
|
||||
$secondTag = $secondBlog->Tags(false)->find('URLSegment', 'second-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->assertTrue($secondTag->canDelete($admin), 'Admin should be able to delete tag.');
|
||||
$this->assertFalse($secondTag->canDelete($editor), 'Editor should not be able to delete tag.');
|
||||
|
||||
$tag = $this->objFromFixture(BlogTag::class, 'ThirdTag');
|
||||
/** @var Blog $thirdBlog */
|
||||
$thirdBlog = $this->objFromFixture(Blog::class, 'ThirdBlog');
|
||||
$thirdTag = $thirdBlog->Tags(false)->find('URLSegment', 'third-tag');
|
||||
|
||||
$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($thirdTag->canDelete($admin), 'Admin should always be able to delete tags.');
|
||||
$this->assertTrue($thirdTag->canDelete($editor), 'Editor should be able to delete tag.');
|
||||
}
|
||||
|
||||
public function testDuplicateTagsForURLSegment()
|
||||
|
@ -12,10 +12,6 @@ SilverStripe\Blog\Model\Blog:
|
||||
blog_a:
|
||||
URLSegment: my-blog
|
||||
Title: My Blog
|
||||
Categories:
|
||||
- =>SilverStripe\Blog\Model\BlogCategory.category_a
|
||||
Tags:
|
||||
- =>SilverStripe\Blog\Model\BlogTag.tag_a
|
||||
|
||||
SilverStripe\Blog\Model\BlogPost:
|
||||
blogpost_a:
|
||||
@ -23,7 +19,3 @@ SilverStripe\Blog\Model\BlogPost:
|
||||
URLSegment: آبیدآبید
|
||||
PublishDate: 2017-08-01 00:00:00
|
||||
Parent: =>SilverStripe\Blog\Model\Blog.blog_a
|
||||
Categories:
|
||||
- =>SilverStripe\Blog\Model\BlogCategory.category_a
|
||||
Tags:
|
||||
- =>SilverStripe\Blog\Model\BlogTag.tag_a
|
||||
|
@ -93,47 +93,37 @@ SilverStripe\Blog\Model\BlogCategory:
|
||||
FirstCategory:
|
||||
Title: 'First Category'
|
||||
URLSegment: 'first-category'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.FirstBlog
|
||||
SecondCategory:
|
||||
Title: 'Second Category'
|
||||
URLSegment: 'second-category'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.SecondBlog
|
||||
ThirdCategory:
|
||||
Title: 'Third Category'
|
||||
URLSegment: 'third-category'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.ThirdBlog
|
||||
|
||||
SilverStripe\Blog\Model\BlogTag:
|
||||
FirstTag:
|
||||
Title: 'First Tag'
|
||||
URLSegment: 'first-tag'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.FirstBlog
|
||||
SecondTag:
|
||||
Title: 'Second Tag'
|
||||
URLSegment: 'second-tag'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.SecondBlog
|
||||
ThirdTag:
|
||||
Title: 'Third Tag'
|
||||
URLSegment: 'third-tag'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.ThirdBlog
|
||||
|
||||
#Tags for Tag Cloud widget
|
||||
PopularTag:
|
||||
Title: 'Popular'
|
||||
URLSegment: 'popular'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.FourthBlog
|
||||
CoolTag:
|
||||
Title: 'Cool'
|
||||
URLSegment: 'cool'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.FourthBlog
|
||||
CatTag:
|
||||
Title: 'Cat'
|
||||
URLSegment: 'cat'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.FourthBlog
|
||||
KiwiTag:
|
||||
Title: 'Kiwi'
|
||||
URLSegment: 'kiwi'
|
||||
BlogID: =>SilverStripe\Blog\Model\Blog.FourthBlog
|
||||
|
||||
SilverStripe\Blog\Model\BlogPost:
|
||||
FirstBlogPost:
|
||||
|
Loading…
Reference in New Issue
Block a user