From 2201af5c74edd001e917d98ed2827d493ff1b03c Mon Sep 17 00:00:00 2001 From: micmania1 Date: Sun, 21 Jul 2013 11:23:35 +0100 Subject: [PATCH] initial commit --- _config.php | 1 + _config/config.yml | 6 + extensions/BlogPostFilter.php | 65 ++++++ forms/AjaxTextField.php | 5 + forms/gridfield/GridFieldAddByDBField.php | 140 +++++++++++++ .../GridFieldConfig_AddByDBField.php | 15 ++ forms/gridfield/GridFieldConfig_SiteTree.php | 27 +++ .../GridFieldSiteTreeAddNewButton.php | 38 ++++ .../gridfield/GridFieldSiteTreeEditButton.php | 31 +++ model/BlogCategory.php | 25 +++ model/BlogTag.php | 25 +++ page/Blog.php | 189 ++++++++++++++++++ page/BlogPost.php | 100 +++++++++ templates/Includes/GridFieldAddByDBField.ss | 5 + templates/Layout/Blog.ss | 18 ++ 15 files changed, 690 insertions(+) create mode 100755 _config.php create mode 100755 _config/config.yml create mode 100755 extensions/BlogPostFilter.php create mode 100755 forms/AjaxTextField.php create mode 100755 forms/gridfield/GridFieldAddByDBField.php create mode 100755 forms/gridfield/GridFieldConfig_AddByDBField.php create mode 100755 forms/gridfield/GridFieldConfig_SiteTree.php create mode 100755 forms/gridfield/GridFieldSiteTreeAddNewButton.php create mode 100755 forms/gridfield/GridFieldSiteTreeEditButton.php create mode 100755 model/BlogCategory.php create mode 100755 model/BlogTag.php create mode 100755 page/Blog.php create mode 100755 page/BlogPost.php create mode 100755 templates/Includes/GridFieldAddByDBField.ss create mode 100755 templates/Layout/Blog.ss diff --git a/_config.php b/_config.php new file mode 100755 index 0000000..6fd199e --- /dev/null +++ b/_config.php @@ -0,0 +1 @@ + + * + **/ +class BlogPostFilter extends Hierarchy { + + /** + * Augments (@link Hierarchy::stageChildren()} + * + * @param $staged DataList + * @param $showAll boolean + **/ + public function stageChildren($showAll = false) { + $staged = parent::stageChildren($showAll); + + $controller = Controller::curr(); + if($controller->class == "CMSPagesController" && in_array($controller->getAction(), array("treeview", "listview", "getsubtree"))) { + return $staged->exclude("ClassName", $this->owner->getExcludedSiteTreeClassNames()); + } else if(in_array($this->owner->ClassName, ClassInfo::subClassesFor("Blog")) && !Permission::check("VIEW_DRAFT_CONTENT")) { + + // Get the current stage. + $stage = Versioned::current_stage(); + if($stage == "Stage") $stage = ""; + else $stage = "_" . Convert::raw2sql($stage); + + $dataQuery = $staged->dataQuery() + ->innerJoin("BlogPost", "BlogPost" . $stage . ".ID = SiteTree" . $stage . ".ID") + ->where("PublishDate < NOW()"); + $staged = $staged->setDataQuery($dataQuery); + + } + return $staged; + } + + + + /** + * Augments (@link Hierarchy::liveChildren()} + * + * @param $staged DataList + * @param $showAll boolean + **/ + public function liveChildren($showAll = false, $onlyDeletedFromStage = false) { + $staged = parent::liveChildren($showAll, $onlyDeletedFromStage); + + $controller = Controller::curr(); + if($controller->class == "CMSPagesController" && in_array($controller->getAction(), array("treeview", "listview", "getsubtree"))) { + return $staged->exclude("ClassName", $this->owner->getExcludedSiteTreeClassNames()); + } else if(in_array($this->owner->ClassName, ClassInfo::subClassesFor("Blog")) && !Permission::check("VIEW_DRAFT_CONTENT")) { + $dataQuery = $staged->dataQuery() + ->innerJoin("BlogPost", "BlogPost_Live.ID = SiteTree_Live.ID") + ->where("PublishDate < NOW()"); + $staged = $staged->setDataQuery($dataQuery); + } + return $staged; + } + +} \ No newline at end of file diff --git a/forms/AjaxTextField.php b/forms/AjaxTextField.php new file mode 100755 index 0000000..21a41cd --- /dev/null +++ b/forms/AjaxTextField.php @@ -0,0 +1,5 @@ + +**/ +class GridFieldAddByDBField implements GridField_ActionProvider, GridField_HTMLProvider { + + /** + * HTML Fragment to render the field. + * + * @var string + **/ + protected $targetFragment; + + + + /** + * Default field to create the dataobject by should be Title. + * + * @var string + **/ + protected $dataObjectField = "Title"; + + + + /** + * Creates a text field and add button which allows the user to directly create a new + * DataObject by just entering the title. + * + * @param $targetFragment string + **/ + public function __construct($targetFragment = 'before', $dataObjectField = "Title") { + $this->targetFragment = $targetFragment; + $this->dataObjectField = (string) $dataObjectField; + } + + + + /** + * Provide actions to this component. + * + * @param $gridField GridField + * + * @return array + **/ + public function getActions($gridField) { + return array("add"); + } + + + + /** + * Handles the add action for the given DataObject + * + * @param $gridFIeld GridFIeld + * @param $actionName string + * @param $arguments mixed + * @param $data array + **/ + public function handleAction(GridField $gridField, $actionName, $arguments, $data) { + if($actionName == "add") { + $dbField = $this->getDataObjectField(); + + $objClass = $gridField->getModelClass(); + $obj = new $objClass(); + if($obj->hasField($dbField)) { + $obj->setCastedField($dbField, $data['gridfieldaddbydbfield'][$obj->ClassName][$dbField]); + + $id = $gridField->getList()->add($obj); + if(!$id) { + $gridField->setError(_t("GridFieldAddByDBField.ADDFAIL", "Unable to save " . $obj->Title . " to the database.")); + } + } else { + throw new UnexpectedValueException("Invalid field (" . $dbField . ") on " . $obj->ClassName . "."); + } + } + } + + + + /** + * Renders the TextField and add button to the GridField. + * + * @param $girdField GridField + * + * @return string HTML + **/ + public function getHTMLFragments($gridField) { + $dataClass = $gridField->getList()->dataClass(); + $obj = singleton($dataClass); + $dbField = $this->getDataObjectField(); + + $textField = TextField::create("gridfieldaddbydbfield[" . $obj->ClassName . "][" . Convert::raw2htmlatt($dbField) . "]") + ->setAttribute("placeholder", $obj->fieldLabel($dbField)) + ->addExtraClass("no-change-track"); + + $addAction = new GridField_FormAction($gridField, 'add', + sprintf(_t('GridField.ADD', "Add %s"), $obj->i18n_singular_name()), 'add', 'add'); + $addAction->setAttribute('data-icon', 'add'); + + // Start thinking about rending this back to the GF + $forTemplate = new ArrayData(array()); + $forTemplate->Fields = new ArrayList(); + + $forTemplate->Fields->push($textField); + $forTemplate->Fields->push($addAction); + + return array( + $this->targetFragment => $forTemplate->renderWith("GridFieldAddByDBField") + ); + } + + + + /** + * Returns the database field for which we'll add the new data object. + * + * @return string + **/ + public function getDataObjectField() { + return $this->dataObjectField; + } + + + + /** + * Set the database field. + * + * @param $field string + **/ + public function setDataObjectField($field) { + $this->dataObjectField = (string) $field; + } + +} \ No newline at end of file diff --git a/forms/gridfield/GridFieldConfig_AddByDBField.php b/forms/gridfield/GridFieldConfig_AddByDBField.php new file mode 100755 index 0000000..c5d5b9a --- /dev/null +++ b/forms/gridfield/GridFieldConfig_AddByDBField.php @@ -0,0 +1,15 @@ +removeComponentsByType("GridFieldAddNewButton"); + + // Add new components + $this->addComponent(new GridFieldAddByDBField("buttons-before-left", $dataObjectField)); + } + +} \ No newline at end of file diff --git a/forms/gridfield/GridFieldConfig_SiteTree.php b/forms/gridfield/GridFieldConfig_SiteTree.php new file mode 100755 index 0000000..7ed18a6 --- /dev/null +++ b/forms/gridfield/GridFieldConfig_SiteTree.php @@ -0,0 +1,27 @@ + +**/ +class GridFieldConfig_SiteTree extends GridFieldConfig { + + public function __construct($itemsPerPage = null) { + parent::__construct($itemsPerPage); + $this->addComponent(new GridFieldButtonRow('before')); + $this->addComponent(new GridFieldSiteTreeAddNewButton('buttons-before-left')); + $this->addComponent(new GridFieldToolbarHeader()); + $this->addComponent($sort = new GridFieldSortableHeader()); + $this->addComponent($filter = new GridFieldFilterHeader()); + $this->addComponent(new GridFieldDataColumns()); + $this->addComponent(new GridFieldSiteTreeEditButton()); + $this->addComponent(new GridFieldPageCount('toolbar-header-right')); + $this->addComponent($pagination = new GridFieldPaginator($itemsPerPage)); + + $pagination->setThrowExceptionOnBadDataType(false); + } +} \ No newline at end of file diff --git a/forms/gridfield/GridFieldSiteTreeAddNewButton.php b/forms/gridfield/GridFieldSiteTreeAddNewButton.php new file mode 100755 index 0000000..48f6149 --- /dev/null +++ b/forms/gridfield/GridFieldSiteTreeAddNewButton.php @@ -0,0 +1,38 @@ +canCreate()} for this record + * returns true. + * + * @package framework + * @subpackage fields-gridfield + */ +class GridFieldSiteTreeAddNewButton extends GridFieldAddNewButton { + + public function getHTMLFragments($gridField) { + $singleton = singleton($gridField->getModelClass()); + + if(!$singleton->canCreate()) { + return array(); + } + + if(!$this->buttonName) { + // provide a default button name, can be changed by calling {@link setButtonName()} on this component + $objectName = $singleton->i18n_singular_name(); + $this->buttonName = _t('GridField.Add', 'Add {name}', array('name' => $objectName)); + } + + $controller = $gridField->getForm()->getController(); + $data = new ArrayData(array( + 'NewLink' => $controller->LinkPageAdd("?ParentID=" . $controller->currentPageID()), + 'ButtonName' => $this->buttonName, + )); + + return array( + $this->targetFragment => $data->renderWith('GridFieldAddNewbutton'), + ); + } + +} \ No newline at end of file diff --git a/forms/gridfield/GridFieldSiteTreeEditButton.php b/forms/gridfield/GridFieldSiteTreeEditButton.php new file mode 100755 index 0000000..1b05f0d --- /dev/null +++ b/forms/gridfield/GridFieldSiteTreeEditButton.php @@ -0,0 +1,31 @@ + +**/ +class GridFieldSiteTreeEditButton extends GridFieldEditButton { + + /** + * @param GridField $gridField + * @param DataObject $record + * @param string $columnName + * + * @return string - the HTML for the column + */ + public function getColumnContent($gridField, $record, $columnName) { + // No permission checks, handled through GridFieldDetailForm, + // which can make the form readonly if no edit permissions are available. + + $data = new ArrayData(array( + 'Link' => $record->CMSEditLink() + )); + + return $data->renderWith('GridFieldEditButton'); + } + +} \ No newline at end of file diff --git a/model/BlogCategory.php b/model/BlogCategory.php new file mode 100755 index 0000000..24be276 --- /dev/null +++ b/model/BlogCategory.php @@ -0,0 +1,25 @@ + +**/ +class BlogCategory extends DataObject { + + private static $db = array( + "Title" => "Varchar(255)", + ); + + private static $has_one = array( + "Blog" => "Blog", + ); + + private static $many_many = array( + "BlogPosts" => "BlogPost", + ); + +} \ No newline at end of file diff --git a/model/BlogTag.php b/model/BlogTag.php new file mode 100755 index 0000000..251363e --- /dev/null +++ b/model/BlogTag.php @@ -0,0 +1,25 @@ + +**/ +class BlogTag extends DataObject { + + private static $db = array( + "Title" => "Varchar(255)", + ); + + private static $has_one = array( + "Blog" => "Blog", + ); + + private static $many_many = array( + "BlogPosts" => "BlogPost", + ); + +} \ No newline at end of file diff --git a/page/Blog.php b/page/Blog.php new file mode 100755 index 0000000..f72a098 --- /dev/null +++ b/page/Blog.php @@ -0,0 +1,189 @@ + +**/ +class Blog extends Page { + + private static $has_many = array( + "Tags" => "BlogTag", + "Categories" => "BlogCategory" + ); + + private static $allowed_children = array( + "BlogPost" + ); + + + /** + * Enable archive. + * + * @var boolean + **/ + private static $archive_enabled = true; + + + /** + * Enable tags + * + * @var boolean + **/ + private static $tags_enabled = true; + + + /** + * Enable categories + * + * @var boolean + **/ + private static $categories_enabled = true; + + + + /** + * Whether or not to show BlogPost's in a GridField. Usually this will be + * the case when they're hidden from the SiteTree. + * + * @var boolean + **/ + private static $show_posts_in_gridfield = true; + + + + public function getCMSFields() { + $fields = parent::getCMSFields(); + if($this->config()->get("show_posts_in_gridfield")) { + $gridField = new GridField( + "BlogPost", + _t("Blog.FieldLabels.BlogPosts", "Blog Posts"), + $this->AllChildrenIncludingDeleted(), + GridFieldConfig_SiteTree::create() + ); + $fields->addFieldToTab("Root.BlogPosts", $gridField); + } + + if($this->config()->get("categories_enabled")) { + $fields->addFieldToTab("Root." . _t("Blog.CATEGORIES", "Categories"), + GridField::create( + "Categories", + _t("Blog.FieldLabels.Categories", "Categories"), + $this->Categories(), + GridFieldConfig_AddByDBField::create() + ) + ); + } + + if($this->config()->get("tags_enabled")) { + $fields->addFieldToTab("Root." . _t("Blog.TAGS", "Tags"), + GridField::create( + "Tags", + _t("Blog.FieldLabels.Tags", "Tags"), + $this->Tags(), + GridFieldConfig_AddByDBField::create() + ) + ); + } + return $fields; + } + + + + /** + * Loops through subclasses of BlogPost and checks whether they have been configured + * to be hidden. If so, then they will be excluded from the SiteTree. + * + * @return array + **/ + public function getExcludedSiteTreeClassNames() { + $classes = array(); + $tmpClasses = ClassInfo::subClassesFor("BlogPost"); + foreach($tmpClasses as $class) { + if(!Config::inst()->get($class, "show_in_site_tree")) { + $classes[$class] = $class; + } + } + return $classes; + } + + + + /** + * Return blogs posts + * + * @return DataList of BlogPost objects + **/ + public function getBlogPosts() { + return $this->AllChildren()->filter("ClassName", ClassInfo::subClassesFor("BlogPost")); + } + +} + + + +/** + * Blog Controller + * + * @package silverstripe + * @subpackage blog + * + * @author Michael String +**/ +class Blog_Controller extends Page_Controller { + + private static $allowed_actions = array( + 'archive', + 'tag', + 'category', + ); + + private static $url_handlers = array( + 'tag/$Tag' => "tag", + 'category/$Category' => "category", + ); + + protected $blogPosts; + + public function index() { + $this->blogPosts = $this->AllChildren(); + return $this->render(); + } + + + public function archive() { + return $this->render(); + } + + + public function tag() { + $tag = $this->request->param("Tag"); + if($tag) { + $tag = $this->Tags()->filter("Title", $tag)->first(); + if($tag) { + $this->blogPosts = $this->AllChildren()->filter("ID", $tag->BlogPosts()->getIDList()); + return $this->render(); + } + } + return $this->httpError(404, "Not Found"); + } + + public function category() { + $category = $this->request->param("Category"); + if($category) { + $category = $this->Categories()->filter("Title", $category)->first(); + if($category) { + $this->blogPosts = $this->AllChildren()->filter("ID", $category->BlogPosts()->getIDList()); + return $this->render(); + } + } + return $this->httpError(404, "Not Found"); + } + + public function PaginatedPosts() { + return new PaginatedList($this->blogPosts); + } +} \ No newline at end of file diff --git a/page/BlogPost.php b/page/BlogPost.php new file mode 100755 index 0000000..36f24b2 --- /dev/null +++ b/page/BlogPost.php @@ -0,0 +1,100 @@ + +**/ +class BlogPost extends Page { + + /** + * @var array + **/ + private static $db = array( + "PublishDate" => "SS_Datetime", + ); + + + /** + * @var array + **/ + private static $allowed_children = array(); + + + + /** + * @var boolean + **/ + public static $can_be_root = false; + + + /** + * This will display or hide the current class from the SiteTree. This + * variable can be configured using YAML. + * + * @var boolean + **/ + private static $show_in_site_tree = false; + + + public function getCMSFields() { + $fields = parent::getCMSFields(); + $fields->insertBefore( + $publishDate = DatetimeField::create("PublishDate", _t("BlogPost.FieldLabels.PublishDate", "Publish Date")), + "Content" + ); + + // Publish date field config. + $publishDate->getDateField()->setConfig("showcalendar", true); + + return $fields; + } + + + + /** + * If no publish date is set, set the date to now. + **/ + public function onBeforeWrite() { + parent::onBeforeWrite(); + if(!$this->PublishDate) $this->setCastedField("PublishDate", time()); + } + + + + /** + * Checks the publish date to see if the blog post as actually been published. + * + * @param $member Member|null + * + * @return boolean + **/ + public function canView($member = null) { + if(!parent::canView($member)) return false; + + if($this->PublishDate) { + $publishDate = $this->dbObject("PublishDate"); + if($publishDate->InFuture() && !Permission::checkMember($member, "VIEW_DRAFT_CONTENT")) { + return false; + } + } + return true; + } + +} + + +/** + * An indivisual blog post. + * + * @package silverstripe + * @subpackage blog + * + * @author Michael Strong +**/ +class BlogPost_Controller extends Page_Controller { + +} \ No newline at end of file diff --git a/templates/Includes/GridFieldAddByDBField.ss b/templates/Includes/GridFieldAddByDBField.ss new file mode 100755 index 0000000..1de1eeb --- /dev/null +++ b/templates/Includes/GridFieldAddByDBField.ss @@ -0,0 +1,5 @@ +
+ <% loop $Fields %> + $Field + <% end_loop %> +
diff --git a/templates/Layout/Blog.ss b/templates/Layout/Blog.ss new file mode 100755 index 0000000..44af685 --- /dev/null +++ b/templates/Layout/Blog.ss @@ -0,0 +1,18 @@ +<% include SideBar %> +
+
+

$Title

+
$Content
+ <% if BlogPosts %> +
    + <% loop BlogPosts %> +
  • $Title
  • + <% end_loop %> +
+ <% else %> +

Unable to find any blog posts.

+ <% end_if %> +
+ $Form + $PageComments +
\ No newline at end of file