Code cleanup and fix compatibility for ss 3.2

This commit is contained in:
Damian Mooyman 2014-08-22 16:36:42 +12:00
parent 095a97018e
commit 66e51bb5a4
16 changed files with 841 additions and 1024 deletions

View File

@ -1,17 +1,17 @@
# See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details # See https://github.com/silverstripe-labs/silverstripe-travis-support for setup details
language: php language: php
php: php:
- 5.3 - 5.3
- 5.4
env: env:
- DB=MYSQL CORE_RELEASE=3.1 - DB=MYSQL CORE_RELEASE=master
- DB=PGSQL CORE_RELEASE=master
matrix: matrix:
include: include:
- php: 5.4 - php: 5.4
env: DB=MYSQL CORE_RELEASE=master env: DB=PGSQL CORE_RELEASE=master
before_script: before_script:
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support - git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
@ -19,4 +19,4 @@ before_script:
- cd ~/builds/ss - cd ~/builds/ss
script: script:
- phpunit blog/tests/ - vendor/bin/phpunit blog/tests

View File

@ -0,0 +1,4 @@
<?php
// 0.8 version for framework 3.2
Deprecation::notification_version('0.8.0', 'blog');

View File

@ -1,4 +1,5 @@
<?php <?php
/** /**
* An individual blog entry page type. * An individual blog entry page type.
* *
@ -23,14 +24,6 @@ class BlogEntry extends Page {
private static $singular_name = 'Blog Entry Page'; private static $singular_name = 'Blog Entry Page';
private static $plural_name = 'Blog Entry Pages'; private static $plural_name = 'Blog Entry Pages';
private static $has_one = array();
private static $has_many = array();
private static $many_many = array();
private static $belongs_many_many = array();
private static $defaults = array( private static $defaults = array(
"ProvideComments" => true, "ProvideComments" => true,
@ -41,7 +34,7 @@ class BlogEntry extends Page {
* Is WYSIWYG editing allowed? * Is WYSIWYG editing allowed?
* @var boolean * @var boolean
*/ */
static $allow_wysiwyg_editing = true; public static $allow_wysiwyg_editing = true;
/** /**
* Overload so that the default date is today. * Overload so that the default date is today.
@ -49,41 +42,55 @@ class BlogEntry extends Page {
public function populateDefaults(){ public function populateDefaults(){
parent::populateDefaults(); parent::populateDefaults();
$this->setField('Date', date('Y-m-d H:i:s', strtotime('now'))); $this->setField('Date', SS_DateTime::now()->getValue());
} }
function getCMSFields() { public function getCMSFields() {
Requirements::javascript('blog/javascript/bbcodehelp.js'); Requirements::javascript('blog/javascript/bbcodehelp.js');
Requirements::themedCSS('bbcodehelp'); Requirements::themedCSS('bbcodehelp', 'blog');
// Add fields prior to extension
$this->beforeUpdateCMSFields(function($fields) {
// Disable HTML editing if wysiwyg is disabled
if(!BlogEntry::$allow_wysiwyg_editing) {
$fields->FieldList('Content', TextareaField::create("Content", _t("BlogEntry.CN", "Content"), 20));
}
// Date field
$dateField = DatetimeField::create("Date", _t("BlogEntry.DT", "Date"));;
$dateField->getDateField()->setConfig('showcalendar', true);
$dateField->getTimeField()->setConfig('timeformat', 'H:m:s');
$fields->addFieldToTab("Root.Main", $dateField, "Content");
// Author field
$firstName = Member::currentUser() ? Member::currentUser()->FirstName : '';
$fields->addFieldToTab(
"Root.Main",
TextField::create("Author", _t("BlogEntry.AU", "Author"), $firstName),
"Content"
);
// BB code hints
if(!BlogEntry::$allow_wysiwyg_editing) {
$codeparser = BBCodeParser::create();
$hintField = new LiteralField(
"BBCodeHelper",
"<div id='BBCode' class='field'>" .
"<a id=\"BBCodeHint\" target='new'>" . _t("BlogEntry.BBH", "BBCode help") . "</a>" .
"<div id='BBTagsHolder' style='display:none;'>".$codeparser->useable_tagsHTML()."</div></div>"
);
$fields->addFieldToTab("Root.Main", $hintField);
}
// Tags
$fields->addFieldToTab(
"Root.Main",
TextField::create("Tags", _t("BlogEntry.TS", "Tags (comma sep.)")),
"Content"
);
});
$firstName = Member::currentUser() ? Member::currentUser()->FirstName : ''; return parent::getCMSFields();
$codeparser = new BBCodeParser();
SiteTree::disableCMSFieldsExtensions();
$fields = parent::getCMSFields();
SiteTree::enableCMSFieldsExtensions();
if(!self::$allow_wysiwyg_editing) {
$fields->removeFieldFromTab("Root.Main","Content");
$fields->addFieldToTab("Root.Main", new TextareaField("Content", _t("BlogEntry.CN", "Content"), 20));
}
$fields->addFieldToTab("Root.Main", $dateField = new DatetimeField("Date", _t("BlogEntry.DT", "Date")),"Content");
$dateField->getDateField()->setConfig('showcalendar', true);
$dateField->getTimeField()->setConfig('timeformat', 'H:m:s');
$fields->addFieldToTab("Root.Main", new TextField("Author", _t("BlogEntry.AU", "Author"), $firstName),"Content");
if(!self::$allow_wysiwyg_editing) {
$fields->addFieldToTab("Root.Main", new LiteralField("BBCodeHelper", "<div id='BBCode' class='field'>" .
"<a id=\"BBCodeHint\" target='new'>" . _t("BlogEntry.BBH", "BBCode help") . "</a>" .
"<div id='BBTagsHolder' style='display:none;'>".$codeparser->useable_tagsHTML()."</div></div>"));
}
$fields->addFieldToTab("Root.Main", new TextField("Tags", _t("BlogEntry.TS", "Tags (comma sep.)")),"Content");
$this->extend('updateCMSFields', $fields);
return $fields;
} }
/** /**
@ -106,7 +113,6 @@ class BlogEntry extends Page {
* @return ArrayList List of ArrayData with Tag, Link, and URLTag keys * @return ArrayList List of ArrayData with Tag, Link, and URLTag keys
*/ */
public function TagsCollection() { public function TagsCollection() {
$tags = $this->TagNames(); $tags = $this->TagNames();
$output = new ArrayList(); $output = new ArrayList();
@ -123,11 +129,11 @@ class BlogEntry extends Page {
return $output; return $output;
} }
function Content() { public function Content() {
if(self::$allow_wysiwyg_editing) { if(self::$allow_wysiwyg_editing) {
return $this->getField('Content'); return $this->getField('Content');
} else { } else {
$parser = new BBCodeParser($this->Content); $parser = BBCodeParser::create($this->Content);
$content = new HTMLText('Content'); $content = new HTMLText('Content');
$content->value = $parser->parse(); $content->value = $parser->parse();
return $content; return $content;
@ -135,87 +141,72 @@ class BlogEntry extends Page {
} }
/** /**
* To be used by RSSFeed. If RSSFeed uses Content field, it doesn't pull in correctly parsed content. * To be used by RSSFeed. If RSSFeed uses Content field, it doesn't pull in correctly parsed content.
*
* @return string
*/ */
function RSSContent() { public function RSSContent() {
return $this->Content();
}
/**
* Get a bbcode parsed summary of the blog entry
* @deprecated
*/
function ParagraphSummary(){
user_error("BlogEntry::ParagraphSummary() is deprecated; use BlogEntry::Content()", E_USER_NOTICE);
$val = $this->Content();
$content = $val;
if(!($content instanceof HTMLText)) {
$content = new HTMLText('Content');
$content->value = $val;
}
return $content->FirstParagraph('html');
}
/**
* Get the bbcode parsed content
* @deprecated
*/
function ParsedContent() {
user_error("BlogEntry::ParsedContent() is deprecated; use BlogEntry::Content()", E_USER_NOTICE);
return $this->Content(); return $this->Content();
} }
/** /**
* Link for editing this blog entry * Link for editing this blog entry
*
* @return string Edit URL
*/ */
function EditURL() { public function EditURL() {
return ($this->getParent()) ? $this->getParent()->Link('post') . '/' . $this->ID . '/' : false; $parent = $this->getParent();
} if($parent) {
return Controller::join_links($parent->Link('post'), $this->ID);
function IsOwner() {
if(method_exists($this->Parent(), 'IsOwner')) {
return $this->Parent()->IsOwner();
} }
} }
/**
* Returns true if the current user is an admin, or is the owner of this blog
* {@see BlogHolder::IsOwner}
*
* @return bool
*/
public function IsOwner() {
$parent = $this->Parent();
return $parent && $parent->hasMethod('IsOwner') && $parent->IsOwner();
}
/** /**
* Call this to enable WYSIWYG editing on your blog entries. * Call this to enable WYSIWYG editing on your blog entries.
* By default the blog uses BBCode * By default the blog uses BBCode
*/ */
static function allow_wysiwyg_editing() { public static function allow_wysiwyg_editing() {
self::$allow_wysiwyg_editing = true; self::$allow_wysiwyg_editing = true;
} }
/** /**
* Get the previous blog entry from this section of blog pages. * Get the next oldest blog entry from this section of blog pages.
* *
* @return BlogEntry * @return BlogEntry
*/ */
function PreviousBlogEntry() { public function PreviousBlogEntry() {
return DataObject::get_one( return BlogEntry::get()
'BlogEntry', ->filter('ParentID', $this->ParentID)
"\"SiteTree\".\"ParentID\" = '$this->ParentID' AND \"BlogEntry\".\"Date\" < '$this->Date'", ->exclude('ID', $this->ID)
true, ->filter('Date:LessThanOrEqual', $this->Date)
'Date DESC' ->sort('"BlogEntry"."Date" DESC')
); ->first();
} }
/** /**
* Get the next blog entry from this section of blog pages. * Get the next most recent blog entry from this section of blog pages.
* *
* @return BlogEntry * @return BlogEntry
*/ */
function NextBlogEntry() { public function NextBlogEntry() {
return DataObject::get_one( return BlogEntry::get()
'BlogEntry', ->filter('ParentID', $this->ParentID)
"\"SiteTree\".\"ParentID\" = '$this->ParentID' AND \"BlogEntry\".\"Date\" > '$this->Date'", ->exclude('ID', $this->ID)
true, ->filter('Date:GreaterThanOrEqual', $this->Date)
'Date ASC' ->sort('"BlogEntry"."Date" ASC')
); ->first();
} }
/** /**
@ -223,7 +214,7 @@ class BlogEntry extends Page {
* *
* @return BlogHolder * @return BlogHolder
*/ */
function getBlogHolder() { public function getBlogHolder() {
$holder = null; $holder = null;
if($this->ParentID && $this->Parent()->ClassName == 'BlogHolder') { if($this->ParentID && $this->Parent()->ClassName == 'BlogHolder') {
$holder = $this->Parent(); $holder = $this->Parent();
@ -236,47 +227,31 @@ class BlogEntry extends Page {
class BlogEntry_Controller extends Page_Controller { class BlogEntry_Controller extends Page_Controller {
private static $allowed_actions = array( private static $allowed_actions = array(
'index', 'unpublishPost'
'unpublishPost',
'PageComments',
'SearchForm'
); );
function init() { public function init() {
parent::init(); parent::init();
Requirements::themedCSS("blog","blog"); Requirements::themedCSS("blog", "blog");
} }
/** /**
* Gets a link to unpublish the blog entry * Gets a link to unpublish the blog entry
*/ */
function unpublishPost() { public function unpublishPost() {
if(!$this->IsOwner()) { if(!$this->IsOwner()) {
Security::permissionFailure( Security::permissionFailure(
$this, $this,
'Unpublishing blogs is an administrator task. Please log in.' 'Unpublishing blogs is an administrator task. Please log in.'
); );
} else { } else {
$SQL_id = (int) $this->ID; $page = BlogEntry::get()->byID($this->data()->ID);
$page = DataObject::get_by_id('SiteTree', $SQL_id);
$page->deleteFromStage('Live'); $page->deleteFromStage('Live');
$page->flushCache(); $page->flushCache();
$this->redirect($this->getParent()->Link()); return $this->redirect($this->getParent()->Link());
} }
} }
/**
* Temporary workaround for compatibility with 'comments' module
* (has been extracted from sapphire/trunk in 12/2010).
*
* @return Form
*/
function PageComments() {
if($this->hasMethod('CommentsForm')) return $this->CommentsForm();
else if(method_exists('Page_Controller', 'PageComments')) return parent::PageComments();
}
} }

View File

@ -34,40 +34,37 @@ class BlogHolder extends BlogTree implements PermissionProvider {
'BlogEntry' 'BlogEntry'
); );
function getCMSFields() { public function getCMSFields() {
$blogOwners = $this->blogOwners(); $blogOwners = $this->blogOwners();
SiteTree::disableCMSFieldsExtensions(); // Add holder fields prior to extensions being called
$fields = parent::getCMSFields(); $this->beforeUpdateCMSFields(function($fields) use ($blogOwners) {
SiteTree::enableCMSFieldsExtensions(); $fields->addFieldsToTab(
'Root.Main',
array(
DropdownField::create('OwnerID', 'Blog owner', $blogOwners->map('ID', 'Name')->toArray())
->setEmptyString('(None)')
->setHasEmptyDefault(true),
CheckboxField::create('AllowCustomAuthors', 'Allow non-admins to have a custom author field'),
CheckboxField::create("ShowFullEntry", "Show Full Entry")
->setDescription('Show full content in overviews rather than summary')
),
"Content"
);
});
$fields->addFieldToTab( return parent::getCMSFields();
'Root.Main',
DropdownField::create('OwnerID', 'Blog owner', $blogOwners->map('ID', 'Name')->toArray())
->setEmptyString('(None)')
->setHasEmptyDefault(true),
"Content"
);
$fields->addFieldToTab('Root.Main', new CheckboxField('AllowCustomAuthors', 'Allow non-admins to have a custom author field'), "Content");
$fields->addFieldToTab(
"Root.Main",
CheckboxField::create("ShowFullEntry", "Show Full Entry")
->setDescription('Show full content in overviews rather than summary'),
"Content"
);
$this->extend('updateCMSFields', $fields);
return $fields;
} }
/** /**
* Get members who have BLOGMANAGEMENT and ADMIN permission * Get members who have BLOGMANAGEMENT and ADMIN permission
*/ *
* @param array $sort
function blogOwners($sort = array('FirstName'=>'ASC','Surname'=>'ASC'), $direction = null) { * @param string $direction
* @return SS_List
$members = Permission::get_members_by_permission(array('ADMIN','BLOGMANAGEMENT')); */
public function blogOwners($sort = array('FirstName'=>'ASC','Surname'=>'ASC'), $direction = null) {
$members = Permission::get_members_by_permission(array('ADMIN', 'BLOGMANAGEMENT'));
$members->sort($sort); $members->sort($sort);
$this->extend('extendBlogOwners', $members); $this->extend('extendBlogOwners', $members);
@ -86,7 +83,7 @@ class BlogHolder extends BlogTree implements PermissionProvider {
/** /**
* Only display the blog entries that have the specified tag * Only display the blog entries that have the specified tag
*/ */
function ShowTag() { public function ShowTag() {
if($this->request->latestParam('Action') == 'tag') { if($this->request->latestParam('Action') == 'tag') {
return Convert::raw2xml(Director::urlParam('ID')); return Convert::raw2xml(Director::urlParam('ID'));
} }
@ -95,30 +92,30 @@ class BlogHolder extends BlogTree implements PermissionProvider {
/** /**
* Check if url has "/post" * Check if url has "/post"
*/ */
function isPost() { public function isPost() {
return $this->request->latestParam('Action') == 'post'; return $this->request->latestParam('Action') == 'post';
} }
/** /**
* Link for creating a new blog entry * Link for creating a new blog entry
*/ */
function postURL(){ public function postURL() {
return $this->Link('post'); return $this->Link('post');
} }
/** /**
* Returns true if the current user is an admin, or is the owner of this blog * Returns true if the current user is an admin, or is the owner of this blog
* *
* @return Boolean * @return bool
*/ */
function IsOwner() { public function IsOwner() {
return (Permission::check('BLOGMANAGEMENT') || Permission::check('ADMIN')); return (Permission::check('BLOGMANAGEMENT') || Permission::check('ADMIN'));
} }
/** /**
* Create default blog setup * Create default blog setup
*/ */
function requireDefaultRecords() { public function requireDefaultRecords() {
parent::requireDefaultRecords(); parent::requireDefaultRecords();
// Skip creation of default records // Skip creation of default records
@ -179,7 +176,7 @@ class BlogHolder extends BlogTree implements PermissionProvider {
} }
} }
function providePermissions() { public function providePermissions() {
return array("BLOGMANAGEMENT" => "Blog management"); return array("BLOGMANAGEMENT" => "Blog management");
} }
} }
@ -196,7 +193,7 @@ class BlogHolder_Controller extends BlogTree_Controller {
'BlogEntryForm' => 'BLOGMANAGEMENT', 'BlogEntryForm' => 'BLOGMANAGEMENT',
); );
function init() { public function init() {
parent::init(); parent::init();
Requirements::themedCSS("bbcodehelp"); Requirements::themedCSS("bbcodehelp");
} }
@ -204,14 +201,14 @@ class BlogHolder_Controller extends BlogTree_Controller {
/** /**
* Return list of usable tags for help * Return list of usable tags for help
*/ */
function BBTags() { public function BBTags() {
return BBCodeParser::usable_tags(); return BBCodeParser::usable_tags();
} }
/** /**
* Post a new blog entry * Post a new blog entry
*/ */
function post(){ public function post(){
if(!Permission::check('BLOGMANAGEMENT')) return Security::permissionFailure(); if(!Permission::check('BLOGMANAGEMENT')) return Security::permissionFailure();
$page = $this->customise(array( $page = $this->customise(array(
'Content' => false, 'Content' => false,
@ -223,62 +220,74 @@ class BlogHolder_Controller extends BlogTree_Controller {
/** /**
* A simple form for creating blog entries * A simple form for creating blog entries
*
* @return Form
*/ */
function BlogEntryForm() { public function BlogEntryForm() {
if(!Permission::check('BLOGMANAGEMENT')) return Security::permissionFailure(); if(!Permission::check('BLOGMANAGEMENT')) return Security::permissionFailure();
$id = 0; $codeparser = BBCodeParser::create();
if($this->request->latestParam('ID')) {
$id = (int) $this->request->latestParam('ID');
}
$codeparser = new BBCodeParser();
$membername = Member::currentUser() ? Member::currentUser()->getName() : ""; $membername = Member::currentUser() ? Member::currentUser()->getName() : "";
if(BlogEntry::$allow_wysiwyg_editing) { if(BlogEntry::$allow_wysiwyg_editing) {
$contentfield = new HtmlEditorField("BlogPost", _t("BlogEntry.CN")); $contentfield = HtmlEditorField::create("BlogPost", _t("BlogEntry.CN"));
} else { } else {
$contentfield = new CompositeField( $contentfield = CompositeField::create(
new LiteralField("BBCodeHelper","<a id=\"BBCodeHint\" target='new'>"._t("BlogEntry.BBH")."</a><div class='clear'><!-- --></div>" ), LiteralField::create(
new TextareaField("BlogPost", _t("BlogEntry.CN"),20), // This is called BlogPost as the id #Content is generally used already "BBCodeHelper",
new LiteralField("BBCodeTags","<div id=\"BBTagsHolder\">".$codeparser->useable_tagsHTML()."</div>") "<a id=\"BBCodeHint\" target='new'>"._t("BlogEntry.BBH")."</a><div class='clear'><!-- --></div>"
),
TextareaField::create(
"BlogPost",
_t("BlogEntry.CN"),
20
), // This is called BlogPost as the id #Content is generally used already
LiteralField::create(
"BBCodeTags",
"<div id=\"BBTagsHolder\">".$codeparser->useable_tagsHTML()."</div>"
)
); );
} }
// Support for https://github.com/chillu/silverstripe-tagfield
if(class_exists('TagField')) { if(class_exists('TagField')) {
$tagfield = new TagField('Tags', null, null, 'BlogEntry'); $tagfield = TagField::create('Tags', null, null, 'BlogEntry');
$tagfield->setSeparator(', '); $tagfield->setSeparator(', ');
} else { } else {
$tagfield = new TextField('Tags'); $tagfield = TextField::create('Tags');
} }
$field = 'TextField'; $field = 'TextField';
if(!$this->AllowCustomAuthors && !Permission::check('ADMIN')) { if(!$this->AllowCustomAuthors && !Permission::check('ADMIN')) {
$field = 'ReadonlyField'; $field = 'ReadonlyField';
} }
$fields = new FieldList( $fields = FieldList::create(
new HiddenField("ID", "ID"), HiddenField::create("ID", "ID"),
new TextField("Title", _t('BlogHolder.SJ', "Subject")), TextField::create("Title", _t('BlogHolder.SJ', "Subject")),
new $field("Author", _t('BlogEntry.AU'), $membername), $field::create("Author", _t('BlogEntry.AU'), $membername),
$contentfield, $contentfield,
$tagfield, $tagfield,
new LiteralField("Tagsnote"," <label id='tagsnote'>"._t('BlogHolder.TE', "For example: sport, personal, science fiction")."<br/>" . LiteralField::create(
_t('BlogHolder.SPUC', "Please separate tags using commas.")."</label>") "Tagsnote",
" <label id='tagsnote'>"._t('BlogHolder.TE', "For example: sport, personal, science fiction")."<br/>" .
_t('BlogHolder.SPUC', "Please separate tags using commas.")."</label>"
)
); );
$submitAction = new FormAction('postblog', _t('BlogHolder.POST', 'Post blog entry')); $submitAction = FormAction::create('postblog', _t('BlogHolder.POST', 'Post blog entry'));
$actions = new FieldList($submitAction); $actions = FieldList::create($submitAction);
$validator = new RequiredFields('Title','BlogPost'); $validator = RequiredFields::create('Title','BlogPost');
$form = new Form($this, 'BlogEntryForm',$fields, $actions,$validator); $form = Form::create($this, 'BlogEntryForm', $fields, $actions, $validator);
if($id != 0) { $id = (int) $this->request->latestParam('ID');
$entry = DataObject::get_by_id('BlogEntry', $id); if($id) {
$entry = BlogEntry::get()->byID($id);
if($entry->IsOwner()) { if($entry->IsOwner()) {
$form->loadDataFrom($entry); $form->loadDataFrom($entry);
$form->Fields()->fieldByName('BlogPost')->setValue($entry->Content); $form->Fields()->fieldByName('BlogPost')->setValue($entry->Content);
} }
} else { } else {
$form->loadDataFrom(array("Author" => Cookie::get("BlogHolder_Name"))); $form->loadDataFrom(array("Author" => Cookie::get("BlogHolder_Name")));
@ -287,22 +296,18 @@ class BlogHolder_Controller extends BlogTree_Controller {
return $form; return $form;
} }
function postblog($data, $form) { public function postblog($data, $form) {
if(!Permission::check('BLOGMANAGEMENT')) return Security::permissionFailure(); if(!Permission::check('BLOGMANAGEMENT')) return Security::permissionFailure();
Cookie::set("BlogHolder_Name", $data['Author']); Cookie::set("BlogHolder_Name", $data['Author']);
$blogentry = false; $blogentry = false;
if(isset($data['ID']) && $data['ID']) { if(!empty($data['ID'])) {
$blogentry = DataObject::get_by_id("BlogEntry", $data['ID']); $candidate = BlogEntry::get()->byID($data['ID']);
if(!$blogentry->IsOwner()) { if($candidate->IsOwner()) $blogentry = $candidate;
unset($blogentry);
}
} }
if(!$blogentry) { if(!$blogentry) $blogentry = BlogEntry::create();
$blogentry = new BlogEntry();
}
$form->saveInto($blogentry); $form->saveInto($blogentry);
$blogentry->ParentID = $this->ID; $blogentry->ParentID = $this->ID;
@ -313,8 +318,11 @@ class BlogHolder_Controller extends BlogTree_Controller {
$blogentry->Locale = $this->Locale; $blogentry->Locale = $this->Locale;
} }
$blogentry->writeToStage("Stage"); $oldMode = Versioned::get_reading_mode();
Versioned::reading_stage('Stage');
$blogentry->write();
$blogentry->publish("Stage", "Live"); $blogentry->publish("Stage", "Live");
Versioned::set_reading_mode($oldMode);
$this->redirect($this->Link()); $this->redirect($this->Link());
} }

View File

@ -4,36 +4,44 @@
* Adds author and "post date" fields. * Adds author and "post date" fields.
*/ */
class BlogLeftMainExtension extends Extension { class BlogLeftMainExtension extends Extension {
function updateListView($listView) {
/**
* {@see CMSMain::ListViewForm}
*
* @param type $listView
* @return type
*/
public function updateListView($listView) {
$parentId = $listView->getController()->getRequest()->requestVar('ParentID'); $parentId = $listView->getController()->getRequest()->requestVar('ParentID');
$parent = ($parentId) ? Page::get()->byId($parentId) : new Page(); if(!$parentId) return;
// Only apply logic for this page type // Only apply logic for this page type
if($parent && $parent instanceof BlogHolder) { $parent = BlogHolder::get()->byId($parentId);
$gridField = $listView->Fields()->dataFieldByName('Page'); if(!$parent) return;
if($gridField) {
// Sort by post date
$list = $gridField->getList();
$list = $list->leftJoin('BlogEntry', '"BlogEntry"."ID" = "SiteTree"."ID"');
$gridField->setList($list->sort('Date', 'DESC'));
// Change columns $gridField = $listView->Fields()->dataFieldByName('Page');
$cols = $gridField->getConfig()->getComponentByType('GridFieldDataColumns'); if(!$gridField) return;
if($cols) {
$fields = $cols->getDisplayFields($gridField); // Sort by post date
$castings = $cols->getFieldCasting($gridField); $list = $gridField->getList();
$list = $list->leftJoin('BlogEntry', '"BlogEntry"."ID" = "SiteTree"."ID"');
// Add author to columns $gridField->setList($list->sort('Date', 'DESC'));
$fields['Author'] = _t("BlogEntry.AU", "Author");
// Add post date and remove duplicate "created" date // Change columns
$fields['Date'] = _t("BlogEntry.DT", "Date"); $cols = $gridField->getConfig()->getComponentByType('GridFieldDataColumns');
$castings['Date'] = 'SS_Datetime->Ago'; if(!$cols) return;
if(isset($fields['Created'])) unset($fields['Created']);
$fields = $cols->getDisplayFields($gridField);
$cols->setDisplayFields($fields); $castings = $cols->getFieldCasting($gridField);
$cols->setFieldCasting($castings);
} // Add author to columns
} $fields['Author'] = _t("BlogEntry.AU", "Author");
} // Add post date and remove duplicate "created" date
$fields['Date'] = _t("BlogEntry.DT", "Date");
$castings['Date'] = 'SS_Datetime->Ago';
if(isset($fields['Created'])) unset($fields['Created']);
$cols->setDisplayFields($fields);
$cols->setFieldCasting($castings);
} }
} }

View File

@ -1,11 +1,11 @@
<?php <?php
/** /**
* @package blog * @package blog
*/ */
/** /**
* Blog tree is a way to group Blogs. It allows a tree of "Blog Holders". * Blog tree is a way to group Blogs. It allows a tree of "Blog Holders".
* Viewing branch nodes shows all blog entries from all blog holder children * Viewing branch nodes shows all blog entries from all blog holder children
*/ */
@ -14,28 +14,27 @@ class BlogTree extends Page {
private static $icon = "blog/images/blogtree-file.png"; private static $icon = "blog/images/blogtree-file.png";
private static $description = "A grouping of blogs"; private static $description = "A grouping of blogs";
private static $singular_name = 'Blog Tree Page'; private static $singular_name = 'Blog Tree Page';
private static $plural_name = 'Blog Tree Pages'; private static $plural_name = 'Blog Tree Pages';
// Default number of blog entries to show /**
static $default_entries_limit = 10; * Default number of blog entries to show
*
* @var int
* @config
*/
private static $default_entries_limit = 10;
private static $db = array( private static $db = array(
'Name' => 'Varchar(255)', 'Name' => 'Varchar(255)',
'LandingPageFreshness' => 'Varchar', 'LandingPageFreshness' => 'Varchar',
); );
private static $defaults = array(
);
private static $has_one = array();
private static $has_many = array();
private static $allowed_children = array( private static $allowed_children = array(
'BlogTree', 'BlogHolder' 'BlogTree',
'BlogHolder'
); );
/* /*
@ -48,179 +47,181 @@ class BlogTree extends Page {
* uses current * uses current
* @return BlogTree * @return BlogTree
*/ */
static function current($page = null) { public static function current($page = null) {
// extract page from current request if not specified
if (!$page && Controller::has_curr()) { if (!$page && Controller::has_curr()) {
$controller = Controller::curr(); $controller = Controller::curr();
if ($controller->hasMethod('data')) { if ($controller->hasMethod('data')) {
$page = $controller->data(); $page = $controller->data();
} }
} }
if ($page) { if ($page) {
// If we _are_ a BlogTree, use us // If we _are_ a BlogTree, use us
if ($page instanceof BlogTree) return $page; if ($page instanceof BlogTree) return $page;
// If page is a virtual page use that // If page is a virtual page use that
if($page instanceof VirtualPage && $page->CopyContentFrom() instanceof BlogTree) return $page; if($page instanceof VirtualPage && $page->CopyContentFrom() instanceof BlogTree) {
return $page;
}
// Or, if we a a BlogEntry underneath a BlogTree, use our parent // Or, if we a a BlogEntry underneath a BlogTree, use our parent
if($page->is_a("BlogEntry")) { if($page instanceof BlogEntry && $page->getParent() instanceof BlogTree) {
$parent = $page->getParent(); return $page->getParent();
if($parent instanceof BlogTree) return $parent;
} }
} }
// Try to find a top-level BlogTree // Try to find a top-level BlogTree
$top = DataObject::get_one('BlogTree', "\"ParentID\" = '0'"); $top = BlogTree::get()->filter("ParentID", 0)->first();
if($top) return $top; if($top) return $top;
// Try to find any BlogTree that is not inside another BlogTree // Try to find any BlogTree that is not inside another BlogTree
if($blogTrees=DataObject::get('BlogTree')) foreach($blogTrees as $tree) { $blogTrees = BlogTree::get();
foreach($blogTrees as $tree) {
if(!($tree->getParent() instanceof BlogTree)) return $tree; if(!($tree->getParent() instanceof BlogTree)) return $tree;
} }
// This shouldn't be possible, but assuming the above fails, just return anything you can get // This shouldn't be possible, but assuming the above fails, just return anything you can get
return $blogTrees->first(); return $blogTrees->first();
} }
/* ----------- ACCESSOR OVERRIDES -------------- */ /**
* Calculates number of months of landing page freshness to show
public function getLandingPageFreshness() { *
$freshness = $this->getField('LandingPageFreshness'); * @return int Number of months, if filtered
// If we want to inherit freshness, try that first */
if ($freshness == "INHERIT" && $this->getParent()) $freshness = $this->getParent()->LandingPageFreshness; public function getLandingPageFreshnessMonths() {
// If we don't have a parent, or the inherited result was still inherit, use default $freshness = $this->LandingPageFreshness;
if ($freshness == "INHERIT") $freshness = '';
// Substitute 'INHERIT' for parent freshness, if available
if ($freshness === "INHERIT") {
$freshness = (($parent = $this->getParent()) && $parent instanceof BlogTree)
? $parent->getLandingPageFreshnessMonths()
: null;
}
return $freshness; return $freshness;
} }
/* ----------- CMS CONTROL -------------- */ /* ----------- CMS CONTROL -------------- */
function getSettingsFields() { public function getSettingsFields() {
$fields = parent::getSettingsFields(); $fields = parent::getSettingsFields();
$fields->addFieldToTab( $fields->addFieldToTab(
'Root.Settings', 'Root.Settings',
new DropdownField( new DropdownField(
'LandingPageFreshness', 'LandingPageFreshness',
'When you first open the blog, how many entries should I show', 'When you first open the blog, how many entries should I show',
array( array(
"" => "All entries", "" => "All entries",
"1" => "Last month's entries", "1" => "Last month's entries",
"2" => "Last 2 months' entries", "2" => "Last 2 months' entries",
"3" => "Last 3 months' entries", "3" => "Last 3 months' entries",
"4" => "Last 4 months' entries", "4" => "Last 4 months' entries",
"5" => "Last 5 months' entries", "5" => "Last 5 months' entries",
"6" => "Last 6 months' entries", "6" => "Last 6 months' entries",
"7" => "Last 7 months' entries", "7" => "Last 7 months' entries",
"8" => "Last 8 months' entries", "8" => "Last 8 months' entries",
"9" => "Last 9 months' entries", "9" => "Last 9 months' entries",
"10" => "Last 10 months' entries", "10" => "Last 10 months' entries",
"11" => "Last 11 months' entries", "11" => "Last 11 months' entries",
"12" => "Last year's entries", "12" => "Last year's entries",
"INHERIT" => "Take value from parent Blog Tree" "INHERIT" => "Take value from parent Blog Tree"
) )
) )
); );
return $fields; return $fields;
} }
/* ----------- New accessors -------------- */ /* ----------- New accessors -------------- */
public function loadDescendantBlogHolderIDListInto(&$idList) { public function loadDescendantBlogHolderIDListInto(&$idList) {
if ($children = $this->AllChildren()) { if ($children = $this->AllChildren()) {
foreach($children as $child) { foreach($children as $child) {
if(in_array($child->ID, $idList)) continue; if(in_array($child->ID, $idList)) continue;
if($child instanceof BlogHolder) { if($child instanceof BlogHolder) {
$idList[] = $child->ID; $idList[] = $child->ID;
} elseif($child instanceof BlogTree) { } elseif($child instanceof BlogTree) {
$child->loadDescendantBlogHolderIDListInto($idList); $child->loadDescendantBlogHolderIDListInto($idList);
} }
} }
} }
} }
// Build a list of all IDs for BlogHolders that are children of us /**
* Build a list of all IDs for BlogHolders that are children of us
*
* @return array
*/
public function BlogHolderIDs() { public function BlogHolderIDs() {
$holderIDs = array(); $holderIDs = array();
$this->loadDescendantBlogHolderIDListInto($holderIDs); $this->loadDescendantBlogHolderIDListInto($holderIDs);
return $holderIDs; return $holderIDs;
} }
/** /**
* Get entries in this blog. * Get entries in this blog.
* *
* @param string $limit A clause to insert into the limit clause. * @param string $limit Page size of paginated list
* @param string $tag Only get blog entries with this tag * @param string $tag Only get blog entries with this tag
* @param string $date Only get blog entries on this date - either a year, or a year-month eg '2008' or '2008-02' * @param string $date Only get blog entries on this date - either a year, or a year-month eg '2008' or '2008-02'
* @param callable $retrieveCallback A function to call with pagetype, filter and limit for custom blog * @param array $filters A list of DataList compatible filters
* sorting or filtering * @param mixed $where Raw SQL WHERE condition(s)
* @param string $filter Filter condition
* @return PaginatedList The list of entries in a paginated list * @return PaginatedList The list of entries in a paginated list
*/ */
public function Entries($limit = '', $tag = '', $date = '', $retrieveCallback = null, $filter = '') { public function Entries($limit = '', $tag = '', $date = '', $filters = array(), $where = '') {
// Filter by all current blog holder parents, if any are available
$tagCheck = ''; $holderIDs = $this->BlogHolderIDs();
$dateCheck = ''; if(empty($holderIDs)) return false;
if($tag) {
$SQL_tag = Convert::raw2sql($tag);
$tagCheck = "AND \"BlogEntry\".\"Tags\" LIKE '%$SQL_tag%'";
}
if($date) { // Build filtered list
// Some systems still use the / seperator for date presentation $entries = BlogEntry::get()
if( strpos($date, '-') ) $seperator = '-'; ->filter('ParentID', $holderIDs)
elseif( strpos($date, '/') ) $seperator = '/'; ->sort($order = '"BlogEntry"."Date" DESC');
if(isset($seperator) && !empty($seperator)) {
// The 2 in the explode argument will tell it to only create 2 elements
// i.e. in this instance the $year and $month fields respectively
list($year,$month) = explode( $seperator, $date, 2);
$year = (int)$year;
$month = (int)$month;
if($year && $month) { // Apply where condition
if(method_exists(DB::getConn(), 'formattedDatetimeClause')) { if($where) $entries = $entries->where($where);
$db_date=DB::getConn()->formattedDatetimeClause('"BlogEntry"."Date"', '%m');
$dateCheck = "AND CAST($db_date AS " . DB::getConn()->dbDataType('unsigned integer') . ") = $month AND " . DB::getConn()->formattedDatetimeClause('"BlogEntry"."Date"', '%Y') . " = '$year'"; // Add tag condition
} else { if($tag) $entries = $entries->filter('Tags:PartialMatch', $tag);
$dateCheck = "AND MONTH(\"BlogEntry\".\"Date\") = '$month' AND YEAR(\"BlogEntry\".\"Date\") = '$year'";
} // Add date condition
} if($date && preg_match('/^(?<year>\d+)([-\\/](?<month>\d+))?/', $date, $matches)) {
} else { // Add year filter
$year = (int) $date; $yearExpression = DB::get_conn()->formattedDatetimeClause('"BlogEntry"."Date"', '%Y');
if($year) { $uintExpression = DB::get_schema()->dbDataType('unsigned integer');
if(method_exists(DB::getConn(), 'formattedDatetimeClause')) { $entries = $entries->where(array(
$dateCheck = "AND " . DB::getConn()->formattedDatetimeClause('"BlogEntry"."Date"', '%Y') . " = '$year'"; "CAST($yearExpression AS $uintExpression) = ?" => $matches['year']
} else { ));
$dateCheck = "AND YEAR(\"BlogEntry\".\"Date\") = '$year'";
} // Add month filter
} if(!empty($matches['month'])) {
$monthExpression = DB::get_conn()->formattedDatetimeClause('"BlogEntry"."Date"', '%m');
$entries = $entries->where(array(
"CAST($monthExpression AS $uintExpression) = ?" => $matches['month']
));
} }
} }
// Build a list of all IDs for BlogHolders that are children of us
$holderIDs = $this->BlogHolderIDs();
// If no BlogHolders, no BlogEntries. So return false // Deprecate old $retrieveCallback parameter
if(empty($holderIDs)) return false; if($filters && (is_string($filters) || is_callable($filters))) {
Deprecation::notice(
// Otherwise, do the actual query '0.8',
if($filter) $filter .= ' AND '; '$retrieveCallback parameter is deprecated. Use updateEntries in an extension instead.'
$filter .= '"SiteTree"."ParentID" IN (' . implode(',', $holderIDs) . ") $tagCheck $dateCheck"; );
$callbackWhere = $entries->dataQuery()->query()->getWhere();
return call_user_func($filters, 'BlogEntry', $callbackWhere, $limit, $order);
}
$order = '"BlogEntry"."Date" DESC'; // Apply filters
if($filters) $entries = $entries->filter($filters);
// By specifying a callback, you can alter the SQL, or sort on something other than date. // Extension point
if($retrieveCallback) return call_user_func($retrieveCallback, 'BlogEntry', $filter, $limit, $order); $this->extend('updateEntries', $entries, $limit, $tag, $date, $filters, $where);
$entries = BlogEntry::get()->where($filter)->sort($order);
// Paginate results
$list = new PaginatedList($entries, Controller::curr()->request); $list = new PaginatedList($entries, Controller::curr()->request);
$list->setPageLength($limit); $list->setPageLength($limit);
return $list; return $list;
@ -228,66 +229,57 @@ class BlogTree extends Page {
} }
class BlogTree_Controller extends Page_Controller { class BlogTree_Controller extends Page_Controller {
private static $allowed_actions = array( private static $allowed_actions = array(
'index', 'index',
'rss', 'rss',
'tag', 'tag',
'date' 'date'
); );
private static $casting = array( private static $casting = array(
'SelectedTag' => 'Text', 'SelectedTag' => 'Text',
'SelectedAuthor' => 'Text' 'SelectedAuthor' => 'Text'
); );
function init() { public function init() {
parent::init(); parent::init();
$this->IncludeBlogRSS(); $this->IncludeBlogRSS();
Requirements::themedCSS("blog","blog"); Requirements::themedCSS("blog","blog");
} }
/** /**
* Determine selected BlogEntry items to show on this page * Determine selected BlogEntry items to show on this page
* *
* @param int $limit * @param int $limit
* @return PaginatedList * @return PaginatedList
*/ */
public function BlogEntries($limit = null) { public function BlogEntries($limit = null) {
require_once('Zend/Date.php'); require_once('Zend/Date.php');
$filter = array();
if($limit === null) $limit = BlogTree::$default_entries_limit;
// Defaults for limit
if($limit === null) $limit = BlogTree::config()->default_entries_limit;
// only use freshness if no action is present (might be displaying tags or rss) // only use freshness if no action is present (might be displaying tags or rss)
if ($this->LandingPageFreshness && !$this->request->param('Action')) { $landingPageFreshness = $this->getLandingPageFreshnessMonths();
$d = new Zend_Date(SS_Datetime::now()->getValue()); if ($landingPageFreshness && !$this->request->param('Action')) {
$d->sub($this->LandingPageFreshness, Zend_Date::MONTH); $date = new Zend_Date(SS_Datetime::now()->getValue());
$date = $d->toString('YYYY-MM-dd'); $date->sub($landingPageFreshness, Zend_Date::MONTH);
$date = $date->toString('YYYY-MM-dd');
$filter = "\"BlogEntry\".\"Date\" > '$date'";
} else { $filter["Date:GreaterThan"] = $date;
$filter = '';
} }
// allow filtering by author field and some blogs have an authorID field which
// may allow filtering by id // Allow filtering by author field
if(isset($_GET['author']) && isset($_GET['authorID'])) { if($author = $this->SelectedAuthor()) {
$author = Convert::raw2sql($_GET['author']); $filter['Author:PartialMatch'] = $author;
$id = Convert::raw2sql($_GET['authorID']);
$filter .= " \"BlogEntry\".\"Author\" LIKE '". $author . "' OR \"BlogEntry\".\"AuthorID\" = '". $id ."'";
}
else if(isset($_GET['author'])) {
$filter .= " \"BlogEntry\".\"Author\" LIKE '". Convert::raw2sql($_GET['author']) . "'";
}
else if(isset($_GET['authorID'])) {
$filter .= " \"BlogEntry\".\"AuthorID\" = '". Convert::raw2sql($_GET['authorID']). "'";
} }
$date = $this->SelectedDate(); // Return filtered items
return $this->Entries($limit, $this->SelectedTag(), $this->SelectedDate(), $filter);
return $this->Entries($limit, $this->SelectedTag(), ($date) ? $date : '', null, $filter);
} }
/** /**
@ -296,7 +288,7 @@ class BlogTree_Controller extends Page_Controller {
public function IncludeBlogRSS() { public function IncludeBlogRSS() {
RSSFeed::linkToFeed($this->Link('rss'), _t('BlogHolder.RSSFEED',"RSS feed of these blogs")); RSSFeed::linkToFeed($this->Link('rss'), _t('BlogHolder.RSSFEED',"RSS feed of these blogs"));
} }
/** /**
* Get the rss feed for this blog holder's entries * Get the rss feed for this blog holder's entries
*/ */
@ -305,7 +297,7 @@ class BlogTree_Controller extends Page_Controller {
$blogName = $this->Title; $blogName = $this->Title;
$altBlogName = $project_name . ' blog'; $altBlogName = $project_name . ' blog';
$entries = $this->Entries(20); $entries = $this->Entries(20);
if($entries) { if($entries) {
@ -313,18 +305,18 @@ class BlogTree_Controller extends Page_Controller {
return $rss->outputToBrowser(); return $rss->outputToBrowser();
} }
} }
/** /**
* Protection against infinite loops when an RSS widget pointing to this page is added to this page * Protection against infinite loops when an RSS widget pointing to this page is added to this page
*/ */
public function defaultAction($action) { public function defaultAction($action) {
if(stristr($_SERVER['HTTP_USER_AGENT'], 'SimplePie')) return $this->rss(); if(stristr($_SERVER['HTTP_USER_AGENT'], 'SimplePie')) return $this->rss();
return parent::defaultAction($action); return parent::defaultAction($action);
} }
/** /**
* Return the currently viewing tag used in the template as $Tag * Return the currently viewing tag used in the template as $Tag
* *
* @return string * @return string
*/ */
@ -335,68 +327,51 @@ class BlogTree_Controller extends Page_Controller {
} }
return ''; return '';
} }
/** /**
* Return the selected date from the blog tree * Return the selected date from the blog tree
* *
* @return string * @return string Date in format 'year-month', 'year', or false if not a date
*/ */
public function SelectedDate() { public function SelectedDate() {
if($this->request->latestParam('Action') == 'date') { if($this->request->latestParam('Action') !== 'date') return false;
$year = $this->request->latestParam('ID');
$month = $this->request->latestParam('OtherID'); // Check year
$year = $this->request->latestParam('ID');
if(is_numeric($year) && is_numeric($month) && $month < 13) { if(!is_numeric($year)) return false;
$date = $year .'-'. $month; // Check month
return $date; $month = $this->request->latestParam('OtherID');
if(is_numeric($month) && $month < 13) {
} else { return $year . '-' . $month;
} else {
if(is_numeric($year)) return $year; return $year;
}
} }
return false;
} }
/** /**
* @return string * @return string
*/ */
public function SelectedAuthor() { public function SelectedAuthor() {
if($this->request->getVar('author')) { if($author = $this->request->getVar('author')) {
$hasAuthor = BlogEntry::get()->filter('Author', $this->request->getVar('author'))->Count(); $hasAuthor = BlogEntry::get()
return $hasAuthor ->filter('Author:PartialMatch', $author)
? $this->request->getVar('author') ->Count();
: null; if($hasAuthor) return $author;
} elseif($this->request->getVar('authorID')) {
$hasAuthor = BlogEntry::get()->filter('AuthorID', $this->request->getVar('authorID'))->Count();
if($hasAuthor) {
$member = Member::get()->byId($this->request->getVar('authorID'));
if($member) {
if($member->hasMethod('BlogAuthorTitle')) {
return $member->BlogAuthorTitle;
} else {
return $member->Title;
}
} else {
return null;
}
}
} }
} }
/** /**
* *
* @return string * @return string
*/ */
public function SelectedNiceDate(){ public function SelectedNiceDate(){
$date = $this->SelectedDate(); $date = $this->SelectedDate();
if(strpos($date, '-')) { if(strpos($date, '-')) {
$date = explode("-",$date); $date = explode("-",$date);
return date("F", mktime(0, 0, 0, $date[1], 1, date('Y'))). " " .date("Y", mktime(0, 0, 0, date('m'), 1, $date[0])); return date("F", mktime(0, 0, 0, $date[1], 1, date('Y'))). " " .date("Y", mktime(0, 0, 0, date('m'), 1, $date[0]));
} else { } else {
return date("Y", mktime(0, 0, 0, date('m'), 1, $date)); return date("Y", mktime(0, 0, 0, date('m'), 1, $date));
} }

View File

@ -7,8 +7,9 @@ require_once(BASE_PATH . '/blog/thirdparty/xmlrpc/xmlrpc_wrappers.php');
/** /**
* MetaWeblogController provides the MetaWeblog API for SilverStripe blogs. * MetaWeblogController provides the MetaWeblog API for SilverStripe blogs.
*/ */
class MetaWeblogController extends Controller { class MetaWeblogController extends Controller {
function index($request) {
public function index($request) {
// Create an xmlrpc server, and set up the method calls // Create an xmlrpc server, and set up the method calls
$service = new xmlrpc_server(array( $service = new xmlrpc_server(array(
@ -34,16 +35,16 @@ class MetaWeblogController extends Controller {
/** /**
* Get a list of BlogHolders the user has access to. * Get a list of BlogHolders the user has access to.
*/ */
function getUsersBlogs($appkey, $username, $password) { public function getUsersBlogs($appkey, $username, $password) {
$member = MemberAuthenticator::authenticate(array( $member = MemberAuthenticator::authenticate(array(
'Email' => $username, 'Email' => $username,
'Password' => $password, 'Password' => $password,
)); ));
// TODO Throw approriate error. // TODO Throw approriate error.
if(!$member) die(); if(!$member) die();
$blogholders = DataObject::get('BlogHolder'); $blogholders = SearchForm::get();
$response = array(); $response = array();
@ -64,7 +65,7 @@ class MetaWeblogController extends Controller {
/** /**
* Get the most recent posts on a blog. * Get the most recent posts on a blog.
*/ */
function getRecentPosts($blogid, $username, $password, $numberOfPosts) { public function getRecentPosts($blogid, $username, $password, $numberOfPosts) {
$member = MemberAuthenticator::authenticate(array( $member = MemberAuthenticator::authenticate(array(
'Email' => $username, 'Email' => $username,
'Password' => $password, 'Password' => $password,
@ -96,10 +97,8 @@ class MetaWeblogController extends Controller {
return $res; return $res;
} }
function getCategories() { public function getCategories() {
//TODO dummy function //TODO dummy function
return array(); return array();
} }
} }
?>

View File

@ -1,152 +0,0 @@
<?php
require_once("model/DB.php");
class TypoImport extends Controller {
/**
* Imports product status and price change updates.
*
*/
function testinstall() {
echo "Ok";
}
/**
* Imports blog entries and comments from a Potgres-based typo installation into a SilverStripe blog
*/
function import(){
// some of the guys in the contents table are articles, some are contents. Distinguished by type = "Article" or "Comment"
// fields are: id, title, author, body, body_html, extended, excerpt, keywords, created_at, updated_at, extended_html, user_id, permalink, guid, [13]
// text_filter_id, whiteboard, type, article_id, email, url, ip, blog_name, name, published, allow_pings, allow_comments, blog_id
// published_at, state, status_confirmed
$dbconn = pg_connect("host=orwell port=5432 dbname=typo_prod user=postgres password=possty");
// create a new blogholder and call it "imported blog"
$bholder = new BlogHolder();
$bholder->Title = "imported blog";
// write it!
$bholder->write();
$bholder->publish("Stage", "Live");
// get the typo articles
$result = pg_query($dbconn, "SELECT * FROM contents WHERE type='Article'");
while ($row = pg_fetch_row($result)) {
// title [1]
// author [2]
// body [3]
// body_html [4] (type rendered and cached the html here. This is the preferred blog entry content for migration)
// keywords (space separated) [7] (tags table is just a list of the unique variants of these keywords)
// created_at [8]
// permalink [12] (this is like the url in sitetree, prolly not needed)
// email [18] (address of the commenter)
// url [19] (url of the commenter)
$title = $row[1];
$author = $row[2];
$blog_entry = $row[4];
$keywords = $row[7];
$created_at = $row[8];
// sometimes it's empty. If it is, grab the body
if ($blog_entry == ""){
// use "body"
$blog_entry = $row[3];
}
echo "blog_entry: $blog_entry";
echo "<br />\n";
// put the typo blog entry in the SS database
$newEntry = new BlogEntry();
$newEntry->Title = $title;
$newEntry->Author = $author;
$newEntry->Content = $blog_entry;
$newEntry->Tags = $keywords;
$newEntry->Date = $created_at;
// tie each blog entry back to the blogholder we created initially
$newEntry->ParentID = $bholder->ID;
// write it!
$newEntry->write();
$newEntry->publish("Stage", "Live");
// grab the id so we can get the comments
$old_article_id = $row[0];
// get the comments
$result2 = pg_query($dbconn, "SELECT * FROM contents WHERE type = 'Comment' AND article_id = $old_article_id");
while ($row2 = pg_fetch_row($result2)) {
// grab the body_html
$comment = $row2[4];
// sometimes it's empty. If it is, grab the body
if ($comment == ""){
// use "body"
$comment = $row2[3];
}
$Cauthor = $row2[2];
$Ccreated_at = $row2[8];
// put the typo blog comment in the SS database
$newCEntry = new PageComment();
$newCEntry->Name = $Cauthor;
$newCEntry->Comment = $comment;
$newCEntry->Created = $created_at;
// need to grab the newly inserted blog entry's id
$newCEntry->ParentID = $newEntry->ID;
// write it!
$newCEntry->write();
echo "comment: $comment";
echo "<br />\n";
}
$newEntry->flushCache();
// fix up the specialchars
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#215;\", \"x\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8217;\", \"&rsquo;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8216;\", \"&lsquo;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#151;\", \"&mdash;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8220;\", \"&ldquo;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8221;\", \"&rdquo;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8211;\", \"&ndash;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8212;\", \"&mdash;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8230;\", \"&hellip;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#8482;\", \"&trade;\")");
pg_query($dbconn, "UPDATE SiteTree SET Content = REPLACE(Content, \"&#38;\", \"&amp;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#215;\", \"x\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8217;\", \"&rsquo;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8216;\", \"&lsquo;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#151;\", \"&mdash;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8220;\", \"&ldquo;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8221;\", \"&rdquo;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8211;\", \"&ndash;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8212;\", \"&mdash;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8230;\", \"&hellip;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#8482;\", \"&trade;\")");
pg_query($dbconn, "UPDATE PageComment SET Comment = REPLACE(Comment, \"&#38;\", \"&amp;\")");
}
pg_close($dbconn);
} // end function
} // end class
?>

View File

@ -1,117 +1,115 @@
<?php <?php
if(class_exists('Widget')) { if(!class_exists('Widget')) return;
/** /**
* Shows a widget with viewing blog entries * Shows a widget with viewing blog entries
* by months or years. * by months or years.
* *
* @package blog * @package blog
*/ */
class ArchiveWidget extends Widget { class ArchiveWidget extends Widget {
private static $db = array(
'DisplayMode' => 'Varchar'
);
private static $defaults = array(
'DisplayMode' => 'month'
);
private static $title = 'Browse by Date';
private static $cmsTitle = 'Blog Archive';
private static $description =
'Show a list of months or years in which there are blog posts, and provide links to them.';
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->merge(
new FieldList( private static $db = array(
new OptionsetField( 'DisplayMode' => 'Varchar'
'DisplayMode', );
_t('ArchiveWidget.DispBY', 'Display by'),
array( private static $defaults = array(
'month' => _t('ArchiveWidget.MONTH', 'month'), 'DisplayMode' => 'month'
'year' => _t('ArchiveWidget.YEAR', 'year') );
)
private static $title = 'Browse by Date';
private static $cmsTitle = 'Blog Archive';
private static $description =
'Show a list of months or years in which there are blog posts, and provide links to them.';
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->merge(
new FieldList(
new OptionsetField(
'DisplayMode',
_t('ArchiveWidget.DispBY', 'Display by'),
array(
'month' => _t('ArchiveWidget.MONTH', 'month'),
'year' => _t('ArchiveWidget.YEAR', 'year')
) )
) )
); )
);
$this->extend('updateCMSFields', $fields);
return $fields;
}
function getDates() {
Requirements::themedCSS('archivewidget');
$results = new ArrayList();
$container = BlogTree::current();
$ids = $container->BlogHolderIDs();
$stage = Versioned::current_stage();
$suffix = (!$stage || $stage == 'Stage') ? "" : "_$stage";
if(method_exists(DB::getConn(), 'formattedDatetimeClause')) { $this->extend('updateCMSFields', $fields);
$monthclause = DB::getConn()->formattedDatetimeClause('"Date"', '%m');
$yearclause = DB::getConn()->formattedDatetimeClause('"Date"', '%Y'); return $fields;
} else {
$monthclause = 'MONTH("Date")';
$yearclause = 'YEAR("Date")';
}
if($this->DisplayMode == 'month') {
$sqlResults = DB::query("
SELECT DISTINCT CAST($monthclause AS " . DB::getConn()->dbDataType('unsigned integer') . ")
AS \"Month\",
$yearclause AS \"Year\"
FROM \"SiteTree$suffix\" INNER JOIN \"BlogEntry$suffix\"
ON \"SiteTree$suffix\".\"ID\" = \"BlogEntry$suffix\".\"ID\"
WHERE \"ParentID\" IN (" . implode(', ', $ids) . ")
ORDER BY \"Year\" DESC, \"Month\" DESC;"
);
} else {
$sqlResults = DB::query("
SELECT DISTINCT $yearclause AS \"Year\"
FROM \"SiteTree$suffix\" INNER JOIN \"BlogEntry$suffix\"
ON \"SiteTree$suffix\".\"ID\" = \"BlogEntry$suffix\".\"ID\"
WHERE \"ParentID\" IN (" . implode(', ', $ids) . ")
ORDER BY \"Year\" DESC"
);
}
if($sqlResults) foreach($sqlResults as $sqlResult) {
$isMonthDisplay = $this->DisplayMode == 'month';
$monthVal = (isset($sqlResult['Month'])) ? (int) $sqlResult['Month'] : 1;
$month = ($isMonthDisplay) ? $monthVal : 1;
$year = ($sqlResult['Year']) ? (int) $sqlResult['Year'] : date('Y');
$date = DBField::create_field('Date', array(
'Day' => 1,
'Month' => $month,
'Year' => $year
));
if($isMonthDisplay) {
$link = $container->Link('date') . '/' . $sqlResult['Year'] . '/' . sprintf("%'02d", $monthVal);
} else {
$link = $container->Link('date') . '/' . $sqlResult['Year'];
}
$results->push(new ArrayData(array(
'Date' => $date,
'Link' => $link
)));
}
return $results;
}
} }
public function getDates() {
Requirements::themedCSS('archivewidget');
$results = new ArrayList();
$container = BlogTree::current();
$ids = $container->BlogHolderIDs();
$stage = Versioned::current_stage();
$suffix = (!$stage || $stage == 'Stage') ? "" : "_$stage";
if(method_exists(DB::getConn(), 'formattedDatetimeClause')) {
$monthclause = DB::getConn()->formattedDatetimeClause('"Date"', '%m');
$yearclause = DB::getConn()->formattedDatetimeClause('"Date"', '%Y');
} else {
$monthclause = 'MONTH("Date")';
$yearclause = 'YEAR("Date")';
}
if($this->DisplayMode == 'month') {
$sqlResults = DB::query("
SELECT DISTINCT CAST($monthclause AS " . DB::getConn()->dbDataType('unsigned integer') . ")
AS \"Month\",
$yearclause AS \"Year\"
FROM \"SiteTree$suffix\" INNER JOIN \"BlogEntry$suffix\"
ON \"SiteTree$suffix\".\"ID\" = \"BlogEntry$suffix\".\"ID\"
WHERE \"ParentID\" IN (" . implode(', ', $ids) . ")
ORDER BY \"Year\" DESC, \"Month\" DESC;"
);
} else {
$sqlResults = DB::query("
SELECT DISTINCT $yearclause AS \"Year\"
FROM \"SiteTree$suffix\" INNER JOIN \"BlogEntry$suffix\"
ON \"SiteTree$suffix\".\"ID\" = \"BlogEntry$suffix\".\"ID\"
WHERE \"ParentID\" IN (" . implode(', ', $ids) . ")
ORDER BY \"Year\" DESC"
);
}
if($sqlResults) foreach($sqlResults as $sqlResult) {
$isMonthDisplay = $this->DisplayMode == 'month';
$monthVal = (isset($sqlResult['Month'])) ? (int) $sqlResult['Month'] : 1;
$month = ($isMonthDisplay) ? $monthVal : 1;
$year = ($sqlResult['Year']) ? (int) $sqlResult['Year'] : date('Y');
$date = DBField::create_field('Date', array(
'Day' => 1,
'Month' => $month,
'Year' => $year
));
if($isMonthDisplay) {
$link = $container->Link('date') . '/' . $sqlResult['Year'] . '/' . sprintf("%'02d", $monthVal);
} else {
$link = $container->Link('date') . '/' . $sqlResult['Year'];
}
$results->push(new ArrayData(array(
'Date' => $date,
'Link' => $link
)));
}
return $results;
}
} }

View File

@ -1,60 +1,66 @@
<?php <?php
if(class_exists('Widget')) { if(!class_exists('Widget')) return;
/**
* Blog Management Widget
*
* @package blog
*/
class BlogManagementWidget extends Widget {
private static $title = "Blog Management";
private static $cmsTitle = "Blog Management";
private static $description =
"Provide a number of links useful for administering a blog. Only shown if the user is an admin.";
/** /**
* Blog Management Widget * Get text of latest comment
* *
* @package blog * @return string
*/ */
class BlogManagementWidget extends Widget { public function CommentText() {
if(!class_exists('Comment')) return false;
private static $title = "Blog Management"; $unmoderatedcount = DB::query("SELECT COUNT(*) FROM \"Comment\" WHERE \"Moderated\"=1")->value();
if($unmoderatedcount == 1) {
private static $cmsTitle = "Blog Management"; return _t("BlogManagementWidget.UNM1", "You have 1 unmoderated comment");
} else if($unmoderatedcount > 1) {
private static $description = return sprintf(_t("BlogManagementWidget.UNMM", "You have %i unmoderated comments"), $unmoderatedcount);
"Provide a number of links useful for administering a blog. Only shown if the user is an admin."; } else {
return _t("BlogManagementWidget.COMADM", "Comment administration");
function CommentText() {
if(!class_exists('Comment')) return false;
$unmoderatedcount = DB::query("SELECT COUNT(*) FROM \"Comment\" WHERE \"Moderated\"=1")->value();
if($unmoderatedcount == 1) {
return _t("BlogManagementWidget.UNM1", "You have 1 unmoderated comment");
} else if($unmoderatedcount > 1) {
return sprintf(_t("BlogManagementWidget.UNMM", "You have %i unmoderated comments"), $unmoderatedcount);
} else {
return _t("BlogManagementWidget.COMADM", "Comment administration");
}
} }
function CommentLink() {
if(!Permission::check('BLOGMANAGEMENT') || !class_exists('Comment')) return false;
$unmoderatedcount = DB::query("SELECT COUNT(*) FROM \"Comment\" WHERE \"Moderated\"=1")->value();
if($unmoderatedcount > 0) {
return "admin/comments/unmoderated";
} else {
return "admin/comments";
}
}
} }
class BlogManagementWidget_Controller extends Widget_Controller { /**
* Link to edit comment
function WidgetHolder() { *
if(Permission::check("BLOGMANAGEMENT")) { * @return string
return $this->renderWith("WidgetHolder"); */
} public function CommentLink() {
} if(!Permission::check('BLOGMANAGEMENT') || !class_exists('Comment')) return false;
$unmoderatedcount = DB::query("SELECT COUNT(*) FROM \"Comment\" WHERE \"Moderated\"=1")->value();
function PostLink() {
$container = BlogTree::current(); if($unmoderatedcount > 0) {
return ($container && $container->ClassName != "BlogTree") ? $container->Link('post') : false; return "admin/comments/unmoderated";
} else {
return "admin/comments";
} }
} }
} }
class BlogManagementWidget_Controller extends Widget_Controller {
public function WidgetHolder() {
if(Permission::check("BLOGMANAGEMENT")) {
return $this->renderWith("WidgetHolder");
}
}
public function PostLink() {
$container = BlogTree::current();
return ($container && $container->ClassName != "BlogTree") ? $container->Link('post') : false;
}
}

View File

@ -1,109 +1,107 @@
<?php <?php
if (class_exists('Widget')) { if(!class_exists('Widget')) return;
/**
* Presents a list of items from an RSS feed url
*
* @package blog
*/
class RSSWidget extends Widget {
private static $db = array(
"RSSTitle" => "Text",
"RssUrl" => "Text",
"NumberToShow" => "Int"
);
private static $defaults = array(
"NumberToShow" => 10,
"RSSTitle" => 'RSS Feed'
);
private static $cmsTitle = "RSS Feed";
private static $description = "Downloads another page's RSS feed and displays items in a list.";
/** /**
* Presents a list of items from an RSS feed url * If the RssUrl is relative, convert it to absolute with the
* * current baseURL to avoid confusing simplepie.
* @package blog * Passing relative URLs to simplepie will result
* in strange DNS lookups and request timeouts.
*
* @return string
*/ */
class RSSWidget extends Widget { public function getAbsoluteRssUrl() {
$urlParts = parse_url($this->RssUrl);
private static $db = array( if(!isset($urlParts['host']) || !$urlParts['host']) {
"RSSTitle" => "Text", return Director::absoluteBaseURL() . $this->RssUrl;
"RssUrl" => "Text", } else {
"NumberToShow" => "Int" return $this->RssUrl;
);
private static $defaults = array(
"NumberToShow" => 10,
"RSSTitle" => 'RSS Feed'
);
private static $cmsTitle = "RSS Feed";
private static $description = "Downloads another page's RSS feed and displays items in a list.";
/**
* If the RssUrl is relative, convert it to absolute with the
* current baseURL to avoid confusing simplepie.
* Passing relative URLs to simplepie will result
* in strange DNS lookups and request timeouts.
*
* @return string
*/
function getAbsoluteRssUrl() {
$urlParts = parse_url($this->RssUrl);
if(!isset($urlParts['host']) || !$urlParts['host']) {
return Director::absoluteBaseURL() . $this->RssUrl;
} else {
return $this->RssUrl;
}
}
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->merge(
new FieldList(
new TextField("RSSTitle", _t('RSSWidget.CT', "Custom title for the feed")),
new TextField("RssUrl", _t(
'RSSWidget.URL',
"URL of the other page's RSS feed. Please make sure this URL points to an RSS feed."
)),
new NumericField("NumberToShow", _t('RSSWidget.NTS', "Number of Items to show"))
)
);
$this->extend('updateCMSFields', $fields);
return $fields;
}
function Title() {
return ($this->RSSTitle) ? $this->RSSTitle : _t('RSSWidget.DEFAULTTITLE', 'RSS Feed');
}
function getFeedItems() {
$output = new ArrayList();
// Protection against infinite loops when an RSS widget pointing to this page is added to this page
if(stristr($_SERVER['HTTP_USER_AGENT'], 'SimplePie')) {
return $output;
}
if(!class_exists('SimplePie')) {
throw new LogicException(
'Please install the "simplepie/simplepie" library by adding it to the "require" '
+ 'section of your composer.json'
);
}
$t1 = microtime(true);
$feed = new SimplePie();
$feed->set_feed_url($this->AbsoluteRssUrl);
$feed->set_cache_location(TEMP_FOLDER);
$feed->init();
if($items = $feed->get_items(0, $this->NumberToShow)) {
foreach($items as $item) {
// Cast the Date
$date = new Date('Date');
$date->setValue($item->get_date());
// Cast the Title
$title = new Text('Title');
$title->setValue(html_entity_decode($item->get_title()));
$output->push(new ArrayData(array(
'Title' => $title,
'Date' => $date,
'Link' => $item->get_link()
)));
}
return $output;
}
} }
} }
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->merge(
new FieldList(
new TextField("RSSTitle", _t('RSSWidget.CT', "Custom title for the feed")),
new TextField("RssUrl", _t(
'RSSWidget.URL',
"URL of the other page's RSS feed. Please make sure this URL points to an RSS feed."
)),
new NumericField("NumberToShow", _t('RSSWidget.NTS', "Number of Items to show"))
)
);
$this->extend('updateCMSFields', $fields);
return $fields;
}
public function Title() {
return $this->RSSTitle ?: _t('RSSWidget.DEFAULTTITLE', 'RSS Feed');
}
public function getFeedItems() {
$output = new ArrayList();
// Protection against infinite loops when an RSS widget pointing to this page is added to this page
if(stristr($_SERVER['HTTP_USER_AGENT'], 'SimplePie')) {
return $output;
}
if(!class_exists('SimplePie')) {
throw new LogicException(
'Please install the "simplepie/simplepie" library by adding it to the "require" '
+ 'section of your composer.json'
);
}
$t1 = microtime(true);
$feed = new SimplePie();
$feed->set_feed_url($this->AbsoluteRssUrl);
$feed->set_cache_location(TEMP_FOLDER);
$feed->init();
if($items = $feed->get_items(0, $this->NumberToShow)) {
foreach($items as $item) {
// Cast the Date
$date = new Date('Date');
$date->setValue($item->get_date());
// Cast the Title
$title = new Text('Title');
$title->setValue(html_entity_decode($item->get_title()));
$output->push(new ArrayData(array(
'Title' => $title,
'Date' => $date,
'Link' => $item->get_link()
)));
}
return $output;
}
}
} }

View File

@ -1,33 +1,31 @@
<?php <?php
if(class_exists('Widget')) { if(!class_exists('Widget')) return;
/**
* A simple widget that just shows a link
* to this website's blog RSS, with an RSS
* icon.
*
* @package blog
*/
class SubscribeRSSWidget extends Widget {
private static $title = 'Subscribe via RSS';
private static $cmsTitle = 'Subscribe via RSS widget';
private static $description = 'Shows a link allowing a user to subscribe to this blog via RSS.';
/** /**
* A simple widget that just shows a link * Return an absolute URL based on the BlogHolder
* to this website's blog RSS, with an RSS * that this widget is located on.
* icon. *
* * @return string
* @package blog
*/ */
class SubscribeRSSWidget extends Widget { public function getRSSLink() {
Requirements::themedCSS('subscribersswidget');
private static $title = 'Subscribe via RSS'; $container = BlogTree::current();
if ($container) return $container->Link('rss');
private static $cmsTitle = 'Subscribe via RSS widget';
private static $description = 'Shows a link allowing a user to subscribe to this blog via RSS.';
/**
* Return an absolute URL based on the BlogHolder
* that this widget is located on.
*
* @return string
*/
function getRSSLink() {
Requirements::themedCSS('subscribersswidget');
$container = BlogTree::current();
if ($container) return $container->Link('rss');
}
} }
} }

View File

@ -1,155 +1,154 @@
<?php <?php
if(class_exists('Widget')) { if(!class_exists('Widget')) return;
/**
* A list of tags associated with blog posts
*
* @package blog
*/
class TagCloudWidget extends Widget {
private static $db = array(
"Title" => "Varchar",
"Limit" => "Int",
"Sortby" => "Varchar"
);
private static $defaults = array(
"Title" => "Tag Cloud",
"Limit" => "0",
"Sortby" => "alphabet"
);
private static $cmsTitle = "Tag Cloud";
private static $description = "Shows a tag cloud of tags on your blog.";
/** /**
* A list of tags associated with blog posts * List of popularity classes in order of least to most popular
* *
* @package blog * @config
* @var array
*/ */
class TagCloudWidget extends Widget { private static $popularities = array(
'not-popular',
private static $db = array( 'not-very-popular',
"Title" => "Varchar", 'somewhat-popular',
"Limit" => "Int", 'popular',
"Sortby" => "Varchar" 'very-popular',
); 'ultra-popular'
);
private static $defaults = array( public function getCMSFields() {
"Title" => "Tag Cloud",
"Limit" => "0",
"Sortby" => "alphabet"
);
private static $cmsTitle = "Tag Cloud"; $this->beforeUpdateCMSFields(function($fields) {
$fields->merge(
private static $description = "Shows a tag cloud of tags on your blog."; new FieldList(
new TextField("Title", _t("TagCloudWidget.TILE", "Title")),
/** new TextField("Limit", _t("TagCloudWidget.LIMIT", "Limit number of tags")),
* List of popularity classes in order of least to most popular new OptionsetField(
* "Sortby",
* @config _t("TagCloudWidget.SORTBY", "Sort by"),
* @var array array(
*/ "alphabet" => _t("TagCloudWidget.SBAL", "alphabet"),
private static $popularities = array( "frequency" => _t("TagCloudWidget.SBFREQ", "frequency")
'not-popular',
'not-very-popular',
'somewhat-popular',
'popular',
'very-popular',
'ultra-popular'
);
public function getCMSFields() {
$this->beforeUpdateCMSFields(function($fields) {
$fields->merge(
new FieldList(
new TextField("Title", _t("TagCloudWidget.TILE", "Title")),
new TextField("Limit", _t("TagCloudWidget.LIMIT", "Limit number of tags")),
new OptionsetField(
"Sortby",
_t("TagCloudWidget.SORTBY", "Sort by"),
array(
"alphabet" => _t("TagCloudWidget.SBAL", "alphabet"),
"frequency" => _t("TagCloudWidget.SBFREQ", "frequency")
)
) )
) )
); )
);
});
return parent::getCMSFields();
}
public function Title() {
return $this->Title ?: _t('TagCloudWidget.DEFAULTTITLE', 'Tag Cloud');
}
/**
* Current BlogTree used as the container for this tagcloud.
* Used by {@link TagCloudWidgetTest} for testing
*
* @var BlogTree
*/
public static $container = null;
/**
* Return all sorted tags in the system
*
* @return ArrayList
*/
public function getTagsCollection() {
Requirements::themedCSS("tagcloud");
// Ensure there is a valid BlogTree with entries
$container = BlogTree::current(self::$container);
if( !$container
|| !($entries = $container->Entries())
|| $entries->count() == 0
) return null;
// Extract all tags from each entry
$tagCounts = array(); // Mapping of tag => frequency
$tagLabels = array(); // Mapping of tag => label
foreach($entries as $entry) {
$theseTags = $entry->TagNames();
foreach($theseTags as $tag => $tagLabel) {
$tagLabels[$tag] = $tagLabel;
//getting the count into key => value map
$tagCounts[$tag] = isset($tagCounts[$tag]) ? $tagCounts[$tag] + 1 : 1;
}
}
if(empty($tagCounts)) return null;
$minCount = min($tagCounts);
$maxCount = max($tagCounts);
// Apply sorting mechanism
if($this->Sortby == "alphabet") {
// Sort by name
ksort($tagCounts);
} else {
// Sort by frequency
uasort($tagCounts, function($a, $b) {
return $b - $a;
}); });
return parent::getCMSFields();
} }
function Title() { // Apply limiting
return $this->Title ? $this->Title : _t('TagCloudWidget.DEFAULTTITLE', 'Tag Cloud'); if($this->Limit > 0) $tagCounts = array_slice($tagCounts, 0, $this->Limit, true);
}
/**
* Current BlogTree used as the container for this tagcloud.
* Used by {@link TagCloudWidgetTest} for testing
*
* @var BlogTree
*/
public static $container = null;
/** // Calculate buckets of popularities
* Return all sorted tags in the system $numsizes = count(array_unique($tagCounts)); //Work out the number of different sizes
* $popularities = self::config()->popularities;
* @return ArrayList $buckets = count($popularities);
*/
function getTagsCollection() {
Requirements::themedCSS("tagcloud");
// Ensure there is a valid BlogTree with entries // If there are more frequencies than buckets, divide frequencies into buckets
$container = BlogTree::current(self::$container); if ($numsizes > $buckets) $numsizes = $buckets;
if( !$container
|| !($entries = $container->Entries())
|| $entries->count() == 0
) return null;
// Extract all tags from each entry // Adjust offset to use central buckets (if using a subset of available buckets)
$tagCounts = array(); // Mapping of tag => frequency $offset = round(($buckets - $numsizes)/2);
$tagLabels = array(); // Mapping of tag => label
foreach($entries as $entry) {
$theseTags = $entry->TagNames();
foreach($theseTags as $tag => $tagLabel) {
$tagLabels[$tag] = $tagLabel;
//getting the count into key => value map
$tagCounts[$tag] = isset($tagCounts[$tag]) ? $tagCounts[$tag] + 1 : 1;
}
}
if(empty($tagCounts)) return null;
$minCount = min($tagCounts);
$maxCount = max($tagCounts);
// Apply sorting mechanism $output = new ArrayList();
if($this->Sortby == "alphabet") { foreach($tagCounts as $tag => $count) {
// Sort by name
ksort($tagCounts); // Find position of $count in the selected range, adjusted for bucket range used
if($maxCount == $minCount) {
$popularity = $offset;
} else { } else {
// Sort by frequency $popularity = round(
uasort($tagCounts, function($a, $b) { ($count-$minCount) / ($maxCount-$minCount) * ($numsizes-1)
return $b - $a; ) + $offset;
});
} }
$class = $popularities[$popularity];
// Apply limiting
if($this->Limit > 0) $tagCounts = array_slice($tagCounts, 0, $this->Limit, true);
// Calculate buckets of popularities $output->push(new ArrayData(array(
$numsizes = count(array_unique($tagCounts)); //Work out the number of different sizes "Tag" => $tagLabels[$tag],
$popularities = self::config()->popularities; "Count" => $count,
$buckets = count($popularities); "Class" => $class,
"Link" => Controller::join_links($container->Link('tag'), urlencode($tag))
// If there are more frequencies than buckets, divide frequencies into buckets )));
if ($numsizes > $buckets) $numsizes = $buckets;
// Adjust offset to use central buckets (if using a subset of available buckets)
$offset = round(($buckets - $numsizes)/2);
$output = new ArrayList();
foreach($tagCounts as $tag => $count) {
// Find position of $count in the selected range, adjusted for bucket range used
if($maxCount == $minCount) {
$popularity = $offset;
} else {
$popularity = round(
($count-$minCount) / ($maxCount-$minCount) * ($numsizes-1)
) + $offset;
}
$class = $popularities[$popularity];
$output->push(new ArrayData(array(
"Tag" => $tagLabels[$tag],
"Count" => $count,
"Class" => $class,
"Link" => Controller::join_links($container->Link('tag'), urlencode($tag))
)));
}
return $output;
} }
return $output;
} }
} }

View File

@ -4,22 +4,22 @@
"type": "silverstripe-module", "type": "silverstripe-module",
"keywords": ["silverstripe", "blog"], "keywords": ["silverstripe", "blog"],
"authors": [ "authors": [
{ {
"name": "Saophalkun Ponlu", "name": "Saophalkun Ponlu",
"email": "phalkunz@silverstripe.com" "email": "phalkunz@silverstripe.com"
}, },
{ {
"name": "Carlos Barberis", "name": "Carlos Barberis",
"email": "carlos@silverstripe.com" "email": "carlos@silverstripe.com"
} }
], ],
"require": {
"require": "silverstripe/cms": "~3.2"
{
"silverstripe/cms": "~3.1"
}, },
"suggest": "require-dev": {
{ "phpunit/PHPUnit": "~3.7@stable"
},
"suggest": {
"silverstripe/widgets": "Additional 'sidebar features', e.g. a list of recent posts and a tagcloud", "silverstripe/widgets": "Additional 'sidebar features', e.g. a list of recent posts and a tagcloud",
"silverstripe/comments": "Enable user comments on any page type, including blog posts", "silverstripe/comments": "Enable user comments on any page type, including blog posts",
"simplepie/simplepie": "Parse RSS feeds, required for the RSS widget" "simplepie/simplepie": "Parse RSS feeds, required for the RSS widget"

View File

@ -72,11 +72,12 @@ class BlogTreeTest extends SapphireTest {
function testLandingPageFreshness() { function testLandingPageFreshness() {
$node = $this->objFromFixture('BlogTree', 'root'); $node = $this->objFromFixture('BlogTree', 'root');
$this->assertEquals($node->LandingPageFreshness, '7 DAYS'); $this->assertEquals('7', $node->LandingPageFreshness);
$node = $this->objFromFixture('BlogTree', 'levela'); $node = $this->objFromFixture('BlogTree', 'levela');
$this->assertEquals($node->LandingPageFreshness, '2 DAYS'); $this->assertEquals('2', $node->LandingPageFreshness);
$node = $this->objFromFixture('BlogTree', 'levelb'); $node = $this->objFromFixture('BlogTree', 'levelb');
$this->assertEquals($node->LandingPageFreshness, '7 DAYS'); $this->assertEquals('INHERIT', $node->LandingPageFreshness);
$this->assertEquals('7', $node->getLandingPageFreshnessMonths());
} }
function testGettingAssociatedBlogTree() { function testGettingAssociatedBlogTree() {

View File

@ -1,13 +1,13 @@
BlogTree: BlogTree:
root: root:
Title: Root BlogTree Title: Root BlogTree
LandingPageFreshness: 7 DAYS LandingPageFreshness: 7
otherroot: otherroot:
Title: Other root BlogTree Title: Other root BlogTree
levela: levela:
Title: Level A Title: Level A
Parent: =>BlogTree.root Parent: =>BlogTree.root
LandingPageFreshness: 2 DAYS LandingPageFreshness: 2
levelb: levelb:
Title: Level B Title: Level B
Parent: =>BlogTree.root Parent: =>BlogTree.root
@ -27,7 +27,7 @@ BlogHolder:
levelaa_blog1: levelaa_blog1:
Title: Level AA Blog 1 Title: Level AA Blog 1
Parent: =>BlogTree.levelaa Parent: =>BlogTree.levelaa
LandingPageFreshness: 1 DAY LandingPageFreshness: 1
levelaa_blog2: levelaa_blog2:
Title: Level AA Blog 2 Title: Level AA Blog 2
Parent: =>BlogTree.levelaa Parent: =>BlogTree.levelaa