Initial work on categorisation rewrite.

Remove relation between blog and categories / tags
Soft-resolve duplicates on query via URLSegment
Remove and simplify tag / category management
Code quality cleanup
This commit is contained in:
Damian Mooyman 2019-10-15 15:35:47 +13:00
parent 2f646eafeb
commit c45499b876
No known key found for this signature in database
GPG Key ID: 19B1752E86A700BB
9 changed files with 390 additions and 273 deletions

View File

@ -4,6 +4,7 @@ namespace SilverStripe\Blog\Admin;
use SilverStripe\Blog\Forms\GridField\GridFieldAddByDBField;
use SilverStripe\Blog\Model\CategorisationObject;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Forms\GridField\GridFieldAddNewButton;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
use SilverStripe\Forms\GridField\GridFieldDataColumns;
@ -12,13 +13,14 @@ 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
* @param SiteTree $parent
*/
public function __construct($itemsPerPage, $mergeRecords, $parentType, $parentMethod, $childMethod)
public function __construct($itemsPerPage, $mergeRecords, $parentType, $parentMethod, $childMethod, $parent)
{
parent::__construct($itemsPerPage);
@ -39,31 +41,24 @@ class GridFieldCategorisationConfig extends GridFieldConfig_RecordEditor
$columns->setFieldFormatting(
[
'BlogPostsCount' => function ($value, CategorisationObject $item) {
'BlogPostsCount' => function ($value, CategorisationObject $item) use ($parent) {
return $item
->BlogPosts()
->filter(['ParentID' => $parent->ID])
->Count();
},
'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'
]
);
}

View File

@ -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,52 @@ 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();
if ($this->ID) {
$tags->setDataQueryParam('BlogID', $this->ID);
// Conditionally hide empty tags
if ($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();
if ($this->ID) {
$tags->setDataQueryParam('BlogID', $this->ID);
// Conditionally hide empty categories
if ($hideEmpty) {
$tags = $tags->filter([
'BlogPosts.ParentID' => $this->ID,
]);
}
}
$this->extend('updateBlogCategories', $tags);
return $tags;
}
/**
* {@inheritdoc}
*/
@ -141,7 +180,7 @@ class Blog extends Page implements PermissionProvider
{
$this->addCMSRequirements();
$this->beforeUpdateCMSFields(function ($fields) {
$this->beforeUpdateCMSFields(function (FieldList $fields) {
if (!$this->canEdit()) {
return;
}
@ -149,43 +188,47 @@ class Blog extends Page implements PermissionProvider
$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'
'BlogPosts',
$this
)
);
$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'
'BlogPosts',
$this
)
);
/**
* @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 +242,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 +293,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 +571,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 +636,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 +666,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 +691,9 @@ class Blog extends Page implements PermissionProvider
/**
* Assign users as necessary to the blog group.
*
* @throws ValidationException
* @throws Exception
*/
protected function assignGroup()
{
@ -665,6 +706,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 +720,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;
}

View File

@ -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,
];
/**

View File

@ -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,190 @@ 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 ($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 (preg_match('/^[0-9]{1,2}$/', $month)
&& $month > 0
&& $month < 13
) {
return (int)$month;
}
return null;
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;
}
// Cannot calculate day without month and year
$month = $this->getArchiveMonth();
$year = $this->getArchiveYear();
if (!$month || !$year) {
return false;
}
return null;
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 +336,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 +442,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 +472,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 +501,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 +540,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 +565,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 +612,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 +637,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;
}
}

View File

@ -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
{

View File

@ -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->getSourceQueryParam('BlogID');
if ($blogID) {
/** @var Blog $blog */
$blog = Blog::get()->byID($blogID);
return $blog;
}
return null;
}
/**
* {@inheritdoc}
*/
@ -75,14 +92,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
);
@ -158,14 +179,12 @@ trait BlogObject
return $this->Blog()->canEdit($member);
}
/**
* {@inheritdoc}
*/
protected function onBeforeWrite()
{
parent::onBeforeWrite();
if ($this->exists() || empty($this->URLSegment)) {
return $this->generateURLSegment();
$this->generateURLSegment();
}
}
@ -178,7 +197,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 +228,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);

View File

@ -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())
@ -816,4 +808,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;
}
}

View File

@ -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,
];
/**

View File

@ -2,8 +2,10 @@
namespace SilverStripe\Blog\Model;
use SilverStripe\ORM\ManyManyList;
/**
* @method ManyManyList BlogPosts
* @method ManyManyList|BlogPost[] BlogPosts()
*/
interface CategorisationObject
{