Source of file BlogPost.php
Size: 21,394 Bytes - Last Modified: 2021-12-23T10:28:05+00:00
/var/www/docs.ssmods.com/process/src/src/Model/BlogPost.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826 | <?php namespace SilverStripe\Blog\Model; use Page; use SilverStripe\AssetAdmin\Forms\UploadField; use SilverStripe\Assets\Image; use SilverStripe\Control\Controller; use SilverStripe\Core\Config\Config; use SilverStripe\Forms\DatetimeField; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\HTMLEditor\HTMLEditorField; use SilverStripe\Forms\ListboxField; use SilverStripe\Forms\TextField; use SilverStripe\Forms\ToggleCompositeField; use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBHTMLText; use SilverStripe\ORM\ManyManyList; use SilverStripe\ORM\SS_List; use SilverStripe\ORM\UnsavedRelationList; use SilverStripe\Security\Group; use SilverStripe\Security\Member; use SilverStripe\Security\Permission; use SilverStripe\Security\Security; use SilverStripe\TagField\TagField; use SilverStripe\Versioned\Versioned; use SilverStripe\View\ArrayData; use SilverStripe\View\Requirements; /** * An individual blog post. * * @method ManyManyList Categories() * @method ManyManyList Tags() * @method ManyManyList Authors() * @method Blog Parent() * @method Blog FeaturedImage() * * @property string $PublishDate * @property string $AuthorNames * @property string $Summary * @property int $ParentID * @property int $FeaturedImageID */ class BlogPost extends Page { /** * Same as above, but for list of users that can be * given credit in the author field for blog posts * @var string|bool false or group code */ private static $restrict_authors_to_group = false; /** * {@inheritDoc} * @var string */ private static $table_name = 'BlogPost'; /** * @var string */ private static $icon_class = 'font-icon-p-post'; /** * @var array */ private static $db = [ 'PublishDate' => 'Datetime', 'AuthorNames' => 'Varchar(1024)', 'Summary' => 'HTMLText' ]; /** * @var array */ private static $indexes = [ 'PublishDate' => true, ]; /** * @var array */ private static $has_one = [ 'FeaturedImage' => Image::class ]; /** * @var array */ private static $owns = [ 'FeaturedImage', ]; /** * @var array */ private static $many_many = [ 'Categories' => BlogCategory::class, 'Tags' => BlogTag::class, 'Authors' => Member::class ]; /** * The ProvideComments db column is defined in the silverstripe/comments module * The InheritSideBar db column is defined in the silverstripe/widgets module * * @var array */ private static $defaults = [ 'ShowInMenus' => false, 'InheritSideBar' => true, 'ProvideComments' => true ]; /** * @var array */ private static $extensions = [ BlogPostFilter::class ]; /** * @var array */ private static $searchable_fields = [ 'Title' ]; /** * @var array */ private static $summary_fields = [ 'Title' ]; /** * @var array */ private static $casting = [ 'Excerpt' => 'HTMLText', 'Date' => 'DBDatetime' ]; /** * @var array */ private static $allowed_children = []; /** * The default sorting lists BlogPosts with an empty PublishDate at the top. * * @var string */ private static $default_sort = '"PublishDate" IS NULL DESC, "PublishDate" DESC'; /** * @var bool */ private static $can_be_root = false; /** * This will display or hide the current class from the SiteTree. This variable can be * configured using YAML. * * @var bool */ private static $show_in_sitetree = false; /** * This helps estimate how long an article will take to read, if your target audience * is elderly then you should lower this value. See {@link getMinutesToRead()} * * @var int */ private static $minutes_to_read_wpm = 200; /** * Sets the upload directory for featured images to help keep your files organised * * @config * @var string */ private static $featured_images_directory = null; /** * Determine the role of the given member. * * Call be called via template to determine the current user. * * @example "Hello $RoleOf($CurrentMember.ID)" * * @param null|int|Member $member * * @return null|string */ public function RoleOf($member = null) { $member = $this->getMember($member); if (!$member) { return null; } if ($this->isAuthor($member)) { return _t(__CLASS__ . '.AUTHOR', 'Author'); } $parent = $this->Parent(); if ($parent instanceof Blog) { return $parent->RoleOf($member); } return null; } /** * Determine if the given member is an author of this post. * * @param null|Member $member * * @return bool */ public function isAuthor($member = null) { if (!$member || !$member->exists()) { return false; } $list = $this->Authors(); if ($list instanceof UnsavedRelationList) { return in_array($member->ID, $list->getIDList()); } return $list->byID($member->ID) !== null; } /** * {@inheritdoc} */ public function getCMSFields() { Requirements::css('silverstripe/blog:client/dist/styles/main.css'); Requirements::javascript('silverstripe/blog:client/dist/js/main.bundle.js'); $this->beforeUpdateCMSFields(function ($fields) { $uploadField = UploadField::create('FeaturedImage', _t(__CLASS__ . '.FeaturedImage', 'Featured Image')); $uploadField->getValidator()->setAllowedExtensions(['jpg', 'jpeg', 'png', 'gif']); $uploadDirectory = $this->config()->get('featured_images_directory'); if ($uploadDirectory != '') { $uploadField->setFolderName($uploadDirectory); } /** * @var FieldList $fields */ $fields->insertAfter('Content', $uploadField); $summary = HtmlEditorField::create('Summary', false); $summary->setRows(5); $summary->setDescription(_t( __CLASS__ . '.SUMMARY_DESCRIPTION', 'If no summary is specified the first 30 words will be used.' )); $summaryHolder = ToggleCompositeField::create( 'CustomSummary', _t(__CLASS__ . '.CUSTOMSUMMARY', 'Add A Custom Summary'), [ $summary, ] ); $summaryHolder->setHeadingLevel(4); $summaryHolder->addExtraClass('custom-summary'); if ($this->Summary) { $summaryHolder->setStartClosed(false); } $fields->insertAfter('FeaturedImage', $summaryHolder); $authorField = ListboxField::create( 'Authors', _t(__CLASS__ . '.Authors', 'Authors'), $this->getCandidateAuthors()->map()->toArray() ); $authorNames = TextField::create( 'AuthorNames', _t(__CLASS__ . '.AdditionalCredits', 'Additional Credits'), null, 1024 )->setDescription( _t( __CLASS__ . '.AdditionalCredits_Description', 'If some authors of this post don\'t have CMS access, enter their name(s) here. '. 'You can separate multiple names with a comma.' ) ); if (!$this->canEditAuthors()) { $authorField = $authorField->performDisabledTransformation(); $authorNames = $authorNames->performDisabledTransformation(); } $publishDate = DatetimeField::create('PublishDate', _t(__CLASS__ . '.PublishDate', 'Publish Date')); if (!$this->PublishDate) { $publishDate->setDescription( _t( __CLASS__ . '.PublishDate_Description', 'Will be set to "now" if published without a value.' ) ); } // 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( 'Root.PostOptions', [ $publishDate, TagField::create( 'Categories', _t(__CLASS__ . '.Categories', 'Categories'), $categories, $this->Categories() ) ->setCanCreate($this->canCreateCategories()) ->setShouldLazyLoad(true), TagField::create( 'Tags', _t(__CLASS__ . '.Tags', 'Tags'), $tags, $this->Tags() ) ->setCanCreate($this->canCreateTags()) ->setShouldLazyLoad(true), $authorField, $authorNames ] ); // )->setTitle('Post Options'); // $options->setName('blog-admin-sidebar'); // $fields->insertBefore($options, 'Root'); $fields->fieldByName('Root.PostOptions') ->setTitle(_t(__CLASS__ . '.PostOptions', 'Post Options')); }); $fields = parent::getCMSFields(); $fields->fieldByName('Root')->setTemplate('TabSet_holder'); return $fields; } /** * Gets the list of author candidates to be assigned as authors of this blog post. * * @return SS_List */ public function getCandidateAuthors() { if ($this->config()->get('restrict_authors_to_group')) { return Group::get()->filter('Code', $this->config()->get('restrict_authors_to_group'))->first()->Members(); } $list = Member::get(); $this->extend('updateCandidateAuthors', $list); return $list; } /** * Determine if this user can edit the authors list. * * @param null|int|Member $member * * @return bool */ public function canEditAuthors($member = null) { $member = $this->getMember($member); $extended = $this->extendedCan('canEditAuthors', $member); if ($extended !== null) { return $extended; } $parent = $this->Parent(); if ($parent instanceof Blog && $parent->exists()) { if ($parent->isEditor($member)) { return true; } if ($parent->isWriter($member) && $this->isAuthor($member)) { return true; } } return Permission::checkMember($member, Blog::MANAGE_USERS); } /** * @param null|int|Member $member * * @return null|Member */ protected function getMember($member = null) { if (!$member) { $member = Security::getCurrentUser(); } if (is_numeric($member)) { $member = Member::get()->byID($member); } return $member; } /** * Determine whether user can create new categories. * * @param null|int|Member $member * * @return bool */ public function canCreateCategories($member = null) { $member = $this->getMember($member); $parent = $this->Parent(); if (!$parent || !$parent->exists() || !($parent instanceof Blog)) { return false; } if ($parent->isEditor($member)) { return true; } return Permission::checkMember($member, 'ADMIN'); } /** * Determine whether user can create new tags. * * @param null|int|Member $member * * @return bool */ public function canCreateTags($member = null) { $member = $this->getMember($member); $parent = $this->Parent(); if (!$parent || !$parent->exists() || !($parent instanceof Blog)) { return false; } if ($parent->isEditor($member)) { return true; } if ($parent->isWriter($member)) { return true; } return Permission::checkMember($member, 'ADMIN'); } /** * {@inheritdoc} * * Update the PublishDate to now if the BlogPost would otherwise be published without a date. */ public function onBeforePublish() { /** * @var DBDatetime $publishDate */ $publishDate = $this->dbObject('PublishDate'); if (!$publishDate->getValue()) { $this->PublishDate = DBDatetime::now()->getValue(); $this->write(); } } /** * {@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} */ public function canView($member = null) { $member = $this->getMember($member); if (!parent::canView($member)) { return false; } if ($this->canEdit($member)) { return true; } // If on draft stage, user has permission to view draft, so show it if (Versioned::get_stage() === Versioned::DRAFT) { return true; } /** * @var DBDatetime $publishDate */ $publishDate = $this->dbObject('PublishDate'); if (!$publishDate->exists()) { return false; } return !$publishDate->InFuture(); } /** * {@inheritdoc} */ public function canPublish($member = null) { $member = $this->getMember($member); if (Permission::checkMember($member, 'ADMIN')) { return true; } $extended = $this->extendedCan('canPublish', $member); if ($extended !== null) { return $extended; } $parent = $this->Parent(); if ($parent instanceof Blog && $parent->exists()) { if ($parent->isEditor($member)) { return true; } if ($parent->isWriter($member) && $this->isAuthor($member)) { return true; } if ($parent->isContributor($member)) { return parent::canEdit($member); } } return $this->canEdit($member); } /** * {@inheritdoc} */ public function canEdit($member = null) { $member = $this->getMember($member); if (parent::canEdit($member)) { return true; } $parent = $this->Parent(); if (!$parent || !$parent->exists() || !($parent instanceof Blog)) { return false; } if ($parent->isEditor($member)) { return true; } if (!$parent->isWriter($member) && !$parent->isContributor($member)) { return false; } return $this->isAuthor($member); } /** * Returns the post excerpt. * * @param int $wordsToDisplay * * @return string */ public function Excerpt($wordsToDisplay = 30) { /** @var DBHTMLText $content */ $content = $this->dbObject('Content'); return $content->Summary($wordsToDisplay); } /** * Returns a monthly archive link for the current blog post. * * @param string $type * @return string */ public function getMonthlyArchiveLink($type = 'day') { /** @var DBDatetime $date */ $date = $this->dbObject('PublishDate'); if ($type !== 'year') { if ($type === 'day') { return Controller::join_links( $this->Parent()->Link('archive'), $date->format('Y'), $date->format('M'), $date->format('d') ); } return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y'), $date->format('M')); } return Controller::join_links($this->Parent()->Link('archive'), $date->format('Y')); } /** * Returns a yearly archive link for the current blog post. * * @return string */ public function getYearlyArchiveLink() { return $this->getMonthlyArchiveLink('year'); } /** * Resolves static and dynamic authors linked to this post. * * @return ArrayList */ public function getCredits() { $list = ArrayList::create(); $list->merge($this->getDynamicCredits()); $list->merge($this->getStaticCredits()); return $list->sort('Name'); } /** * Resolves dynamic authors linked to this post. * * @return ArrayList */ protected function getDynamicCredits() { // Find best page to host user profiles $parent = $this->Parent(); if (! ($parent instanceof Blog)) { $parent = Blog::get()->first(); } // If there is no parent blog, return list undecorated if (!$parent) { $items = $this->Authors()->toArray(); return ArrayList::create($items); } // Update all authors $items = ArrayList::create(); foreach ($this->Authors() as $author) { // Add link for each author $author = $author->customise([ 'URL' => $parent->ProfileLink($author->URLSegment), ]); $items->push($author); } return $items; } /** * Resolves static authors linked to this post. * * @return ArrayList */ protected function getStaticCredits() { $items = ArrayList::create(); $authors = array_filter(preg_split('/\s*,\s*/', $this->AuthorNames)); foreach ($authors as $author) { $item = ArrayData::create([ 'Name' => $author, ]); $items->push($item); } return $items; } /** * Checks to see if User Profiles has been disabled via config * * @return bool */ public function getProfilesDisabled() { return Config::inst()->get(BlogController::class, 'disable_profiles'); } /** * Sets the label for BlogPost.Title to 'Post Title' (Rather than 'Page name'). * * @param bool $includeRelations * * @return array */ public function fieldLabels($includeRelations = true) { $labels = parent::fieldLabels($includeRelations); $labels['Title'] = _t(__CLASS__ . '.PageTitleLabel', 'Post Title'); return $labels; } /** * Proxy method for displaying the publish date in rss feeds. * @see https://github.com/silverstripe/silverstripe-blog/issues/394 * * @return string|null */ public function getDate() { if ($this->hasDatabaseField('Date')) { return $this->getField('Date'); } return !empty($this->PublishDate) ? $this->PublishDate : null; } /** * Provides a rough estimate of how long this post will take to read based on wikipedias answer to "How fast can a * human read" of 200wpm. Source https://en.wikipedia.org/wiki/Speed_reading * * @param null|integer $wpm * * @return string */ public function MinutesToRead($wpm = null) { $wpm = $wpm ?: $this->config()->get('minutes_to_read_wpm'); if (!is_numeric($wpm)) { throw new \InvalidArgumentException(sprintf("Expecting integer but got %s instead", gettype($wpm))); } $wordCount = str_word_count(strip_tags($this->Content)); if ($wordCount < $wpm) { return 0; } return round($wordCount / $wpm, 0); } /** * {@inheritdoc} */ protected function onBeforeWrite() { parent::onBeforeWrite(); if (!$this->exists() && ($member = Security::getCurrentUser())) { $this->Authors()->add($member); } } } |