Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

moved code from sapphire/trunk

  • Loading branch information...
commit f1f90468ee9122b01c0a3b15636e674dba55f011 1 parent c05a43a
@chillu authored
View
0  CHANGELOG
No changes.
View
24 LICENSE
@@ -0,0 +1,24 @@
+* Copyright (c) 2008, Silverstripe Ltd.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of the <organization> nor the
+* names of its contributors may be used to endorse or promote products
+* derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY Silverstripe Ltd. ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL Silverstripe Ltd. BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
13 README
@@ -0,0 +1,13 @@
+####################################################
+Generic Views Module
+####################################################
+
+# Maintainer Contact
+Ingo Schommer (Nickname: ischommer)
+<ingo (at) silverstripe (dot) com>
+
+# Requirements
+SilverStripe 2.3
+
+# Documentation
+http://doc.silverstripe.com/doku.php?id=modules:genericviews
View
2  _config.php
@@ -0,0 +1,2 @@
+<?php
+?>
View
283 code/CollectionController.php
@@ -0,0 +1,283 @@
+<?php
+/**
+ * @package sapphire
+ * @subpackage control
+ */
+abstract class CollectionController extends Controller {
+
+ public $parentController;
+
+ /**
+ * @var string $modelClass Subclass of {@link DataObject} that should be processed.
+ * You can influence the selection of records through {@link getRecords()}.
+ */
+ protected $modelClass;
+
+ /**
+ * @var string|boolean $recordControllerClass Use a {@link RecordController} subclass
+ * to customize the detail viewing/editing behaviour.
+ */
+ protected $recordControllerClass = 'RecordController';
+
+ static $url_handlers = array(
+ '' => 'index',
+ '$Action' => 'handleActionOrID',
+ );
+
+ public static $page_size = 20;
+
+ static $allowed_actions = array('index','search','add','AddForm','SearchForm','ResultsForm');
+
+ /**
+ * @param string $parentController
+ * @param string $modelClass
+ */
+ function __construct($parentController = null, $modelClass = null) {
+ if($parentController) $this->parentController = $parentController;
+ if($modelClass) $this->modelClass = $modelClass;
+
+ parent::__construct();
+ }
+
+ function init() {
+ parent::init();
+
+ Requirements::themedCSS('layout');
+ Requirements::themedCSS('typography');
+ Requirements::themedCSS('form');
+ }
+
+ /**
+ * Appends the model class to the URL.
+ *
+ * @return unknown
+ */
+ function Link() {
+ if($this->parentController) {
+ return Controller::join_links($this->parentController->Link(), "$this->modelClass");
+ } else {
+ return Controller::join_links("$this->modelClass");
+ }
+ }
+
+ /**
+ * Delegate to different control flow, depending on whether the
+ * URL parameter is a number (record id) or string (action).
+ *
+ * @param unknown_type $request
+ * @return unknown
+ */
+ function handleActionOrID($request) {
+ if (is_numeric($request->param('Action'))) {
+ return $this->handleID($request);
+ } else {
+ return $this->handleAction($request);
+ }
+ }
+
+ /**
+ * Delegate to the RecordController if a valid numeric ID appears in the URL
+ * segment.
+ *
+ * @param HTTPRequest $request
+ * @return RecordController
+ */
+ function handleID($request) {
+ $class = $this->recordControllerClass;
+ return new $class($this, $request);
+ }
+
+ /**
+ * Return the class name of the model being managed.
+ *
+ * @return unknown
+ */
+ function getModelClass() {
+ return $this->modelClass;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ function index($request) {
+ return $this->render(array(
+ 'Results' => $this->getRecords()
+ ));
+ }
+
+ function getRecords($searchCriteria = array()) {
+ $start = ($this->request->getVar('start')) ? (int)$this->request->getVar('start') : 0;
+ $limit = $this->stat('page_size');
+
+ $context = singleton($this->modelClass)->getDefaultSearchContext();
+ $query = $context->getQuery($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
+ $records = $context->getResults($searchCriteria, null, array('start'=>$start,'limit'=>$limit));
+ if($records) {
+ $records->setPageLimits($start, $limit, $query->unlimitedRowCount());
+ }
+
+ return $records;
+ }
+
+ /**
+ * Get a search form for a single {@link DataObject} subclass.
+ *
+ * @return Form
+ */
+ public function SearchForm() {
+ $context = singleton($this->modelClass)->getDefaultSearchContext();
+ $fields = $context->getSearchFields();
+ $form = new Form($this, "SearchForm",
+ $fields,
+ new FieldSet(
+ new FormAction('search', _t('MemberTableField.SEARCH'))
+ )
+ );
+ $form->setFormMethod('get');
+
+ return $form;
+ }
+
+ /**
+ * Action to render a data object collection, using the model context to provide filters
+ * and paging.
+ *
+ * @return string
+ */
+ function search($data, $form, $request) {
+ return $this->render(array(
+ 'Results' => $this->getRecords($form->getData()),
+ 'SearchForm' => $form
+ ));
+ }
+
+ /**
+ * Gets the search query generated on the SearchContext from
+ * {@link DataObject::getDefaultSearchContext()},
+ * and the current GET parameters on the request.
+ *
+ * @return SQLQuery
+ */
+ function getSearchQuery($searchCriteria) {
+ $context = singleton($this->modelClass)->getDefaultSearchContext();
+ return $context->getQuery($searchCriteria);
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Create a new model record.
+ *
+ * @param unknown_type $request
+ * @return unknown
+ */
+ function add($request) {
+ if(!singleton($this->modelClass)->canCreate(Member::currentUser())) {
+ return $this->httpError(403);
+ }
+
+ return $this->render(array(
+ 'Form' => $this->AddForm(),
+ 'SearchForm' => false
+ ));
+ }
+
+ /**
+ * Returns a form for editing the attached model
+ */
+ public function AddForm() {
+ $newRecord = new $this->modelClass();
+ if($newRecord->hasMethod('getAddFormFields')) {
+ $fields = $newRecord->getAddFormFields();
+ } else {
+ $fields = $newRecord->getFormFields();
+ }
+
+ $validator = ($newRecord->hasMethod('getValidator')) ? $newRecord->getValidator() : null;
+
+ $actions = new FieldSet(new FormAction("doAdd", "Add"));
+
+ $form = new Form($this, "AddForm", $fields, $actions, $validator);
+
+ return $form;
+ }
+
+ function doAdd($data, $form, $request) {
+ if(!singleton($this->modelClass)->canCreate(Member::currentUser())) {
+ return $this->httpError(403);
+ }
+
+ $className = $this->modelClass;
+ $model = new $className();
+ // We write before saveInto, since this will let us save has-many and many-many relationships :-)
+ $model->write();
+ $form->saveInto($model);
+ $model->write();
+
+ /*
+ $form->sessionMessage(
+ _t('RecordController.SAVESUCCESS','Saved record'),
+ 'good'
+ );
+ */
+
+ if($this->canDetailView()) {
+ Director::redirect(Controller::join_links($this->Link(), $model->ID , 'edit'));
+ } else {
+ Director::redirectBack();
+ }
+
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @return string
+ */
+ public function ModelNameSingular() {
+ return singleton($this->modelClass)->i18n_singular_name();
+ }
+
+ /**
+ * @return string
+ */
+ public function ModelNamePlural() {
+ return singleton($this->modelClass)->i18n_plural_name();
+ }
+
+ /**
+ * Use this to control permissions or completely disable
+ * links to detail records.
+ * @return boolean (Default: true)
+ */
+ public function canDetailView() {
+ return true;
+ }
+
+ /**
+ * If a parentcontroller exists, use its main template,
+ * and mix in specific collectioncontroller subtemplates.
+ */
+ function getViewer($action) {
+ if($this->parentController) {
+ $viewer = $this->parentController->getViewer($action);
+ $parentClass = $this->class;
+ $layoutTemplate = null;
+ while($parentClass != "Controller" && !$layoutTemplate) {
+ $layoutGenericTemplate = SSViewer::getTemplateFileByType($parentClass, 'Layout');
+ if($layoutGenericTemplate) $layoutTemplate = $layoutGenericTemplate;
+ $layoutActionTemplate = SSViewer::getTemplateFileByType(strtok($parentClass,'_') . '_' . $action, 'Layout');
+ if($layoutActionTemplate) $layoutTemplate = $layoutActionTemplate;
+ $parentClass = get_parent_class($parentClass);
+ }
+ if($layoutTemplate) $viewer->setTemplateFile('Layout', $layoutTemplate);
+
+ return $viewer;
+ } else {
+ return parent::getViewer($action);
+ }
+ }
+}
+?>
View
211 code/RecordController.php
@@ -0,0 +1,211 @@
+<?php
+/**
+ * @package sapphire
+ * @subpackage control
+ */
+class RecordController extends Controller {
+ protected $parentController;
+ protected $currentRecord;
+
+ static $allowed_actions = array('edit','view','delete','EditForm','ViewForm','DeleteForm');
+
+ function __construct($parentController, $request) {
+ $this->parentController = $parentController;
+ $modelName = $parentController->getModelClass();
+
+ if(is_numeric($request->latestParam('Action'))) {
+ $this->currentRecord = DataObject::get_by_id($this->modelClass, $request->latestParam('Action'));
+ }
+
+ parent::__construct();
+ }
+
+ function init() {
+ parent::init();
+
+ Requirements::themedCSS('layout');
+ Requirements::themedCSS('typography');
+ Requirements::themedCSS('form');
+ }
+
+ /**
+ * Link fragment - appends the current record ID to the URL.
+ *
+ */
+ function Link() {
+ return Controller::join_links($this->parentController->Link(), "/{$this->currentRecord->ID}");
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ function index($request) {
+ return $this->view($request);
+ }
+
+ /**
+ * Edit action - shows a form for editing this record
+ */
+ function edit($request) {
+ if(!$this->currentRecord) {
+ return $this->httpError(404);
+ }
+ if(!$this->currentRecord->canEdit(Member::currentUser())) {
+ return $this->httpError(403);
+ }
+
+ return $this->render(array(
+ 'Form' => $this->EditForm(),
+ 'ExtraForm' => $this->DeleteForm()
+ ));
+ }
+
+ /**
+ * Returns a form for editing the attached model
+ */
+ public function EditForm() {
+ $fields = $this->currentRecord->getFormFields();
+ $fields->push(new HiddenField("ID"));
+
+ $validator = ($this->currentRecord->hasMethod('getValidator')) ? $this->currentRecord->getValidator() : new RequiredFields();
+
+ $actions = new FieldSet(
+ new FormAction("doEdit", "Save")
+ );
+
+ $form = new Form($this, "EditForm", $fields, $actions, $validator);
+ $form->loadDataFrom($this->currentRecord);
+
+ return $form;
+ }
+
+ public function DeleteForm() {
+ if(!$this->currentRecord->canDelete(Member::currentUser())) {
+ return false;
+ }
+
+ $form = new Form($this,
+ "DeleteForm",
+ new FieldSet(),
+ new FieldSet(new ConfirmedFormAction('doDelete', 'Delete'))
+ );
+
+ return $form;
+ }
+
+ /**
+ * Postback action to save a record
+ *
+ * @param array $data
+ * @param Form $form
+ * @param HTTPRequest $request
+ * @return mixed
+ */
+ function doEdit($data, $form, $request) {
+ if(!$this->currentRecord->canEdit(Member::currentUser())) {
+ return $this->httpError(403);
+ }
+
+ $form->saveInto($this->currentRecord);
+ $this->currentRecord->write();
+
+ $form->sessionMessage(
+ _t('RecordController.SAVESUCCESS','Saved record'),
+ 'good'
+ );
+
+ Director::redirectBack();
+ }
+
+ /**
+ * Delete the current record
+ */
+ public function doDelete($data, $form, $request) {
+ if(!$this->currentRecord->canDelete(Member::currentUser())) {
+ return $this->httpError(403);
+ }
+
+ $this->currentRecord->delete();
+ $form->sessionMessage(
+ _t('RecordController.DELETESUCCESS','Successfully deleted record'),
+ 'good'
+ );
+
+ Director::redirectBack();
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Renders the record view template.
+ *
+ * @param HTTPRequest $request
+ * @return mixed
+ */
+ function view($request) {
+ if(!$this->currentRecord) {
+ return $this->httpError(404);
+ }
+ if(!$this->currentRecord->canView(Member::currentUser())) {
+ return $this->httpError(403);
+ }
+
+ return $this->render(array(
+ 'Form' => $this->ViewForm()
+ ));
+ }
+
+ /**
+ * Returns a form for viewing the attached model
+ *
+ * @return Form
+ */
+ public function ViewForm() {
+ $fields = $this->currentRecord->getFormFields();
+ $form = new Form($this, "EditForm", $fields, new FieldSet());
+ $form->loadDataFrom($this->currentRecord);
+ $form->makeReadonly();
+ return $form;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @return string
+ */
+ public function ModelNameSingular() {
+ return singleton($this->modelClass)->i18n_singular_name();
+ }
+
+ /**
+ * @return string
+ */
+ public function ModelNamePlural() {
+ return singleton($this->modelClass)->i18n_plural_name();
+ }
+
+ /**
+ * If a parentcontroller exists, use its main template,
+ * and mix in specific collectioncontroller subtemplates.
+ */
+ function getViewer($action) {
+ if($this->parentController) {
+ $viewer = $this->parentController->getViewer($action);
+ $parentClass = $this->class;
+ $layoutTemplate = null;
+ while($parentClass != "Controller" && !$layoutTemplate) {
+ $layoutGenericTemplate = SSViewer::getTemplateFileByType($parentClass, 'Layout');
+ if($layoutGenericTemplate) $layoutTemplate = $layoutGenericTemplate;
+ $layoutActionTemplate = SSViewer::getTemplateFileByType(strtok($parentClass,'_') . '_' . $action, 'Layout');
+ if($layoutActionTemplate) $layoutTemplate = $layoutActionTemplate;
+ $parentClass = get_parent_class($parentClass);
+ }
+ if($layoutTemplate) $viewer->setTemplateFile('Layout', $layoutTemplate);
+
+ return $viewer;
+ } else {
+ return parent::getViewer($action);
+ }
+ }
+}
+?>
View
22 templates/CollectionController.ss
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
+<head>
+ <% base_tag %>
+ $MetaTags
+</head>
+<body>
+ <div id="BgContainer">
+ <div id="Container">
+ <div id="Header">
+ <h1>$ModelNameSingular</h1>
+ </div>
+
+ <div id="Layout">
+ $Layout
+ </div>
+
+ </div>
+ </div>
+</body>
+</html>
View
21 templates/Layout/CollectionController.ss
@@ -0,0 +1,21 @@
+<div class="typography">
+ <div id="Content">
+
+ <h2>$Title</h2>
+
+ $Form
+
+ <% if SearchForm %>
+ <h3><% _t('SEARCH','Search') %></h3>
+ $SearchForm
+ <% end_if %>
+
+ <% include CollectionController_Results %>
+
+ <% if canCurrentUserCreate %>
+ <h3>Add</h3>
+ <a href="$Link/add"><% _t('ADDNEWRECORD','Add new record') %></a>
+ <% end_if %>
+
+ </div>
+</div>
View
11 templates/Layout/RecordController.ss
@@ -0,0 +1,11 @@
+<div class="typography">
+ <div id="Content">
+
+ <h2>$Title</h2>
+
+ $Form
+
+ $ExtraForm
+
+ </div>
+</div>
View
22 templates/RecordController.ss
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
+<head>
+ <% base_tag %>
+ $MetaTags
+</head>
+<body>
+ <div id="BgContainer">
+ <div id="Container">
+ <div id="Header">
+ <h1>$ModelNameSingular</h1>
+ </div>
+
+ <div id="Layout">
+ $Layout
+ </div>
+
+ </div>
+ </div>
+</body>
+</html>
Please sign in to comment.
Something went wrong with that request. Please try again.