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