mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #5943 from open-sausages/pulls/4.0/template-lookup-redux
API Update template lookup to late resolution for performance reasons
This commit is contained in:
commit
3b71b7731a
@ -15,6 +15,7 @@ use SilverStripe\ORM\ArrayList;
|
|||||||
use SilverStripe\ORM\Queries\SQLSelect;
|
use SilverStripe\ORM\Queries\SQLSelect;
|
||||||
use SilverStripe\ORM\ManyManyList;
|
use SilverStripe\ORM\ManyManyList;
|
||||||
use SilverStripe\MSSQL\MSSQLDatabase;
|
use SilverStripe\MSSQL\MSSQLDatabase;
|
||||||
|
use SSViewer;
|
||||||
use TemplateGlobalProvider;
|
use TemplateGlobalProvider;
|
||||||
use Deprecation;
|
use Deprecation;
|
||||||
use i18n;
|
use i18n;
|
||||||
@ -1541,8 +1542,10 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
|||||||
$dateFormatMap
|
$dateFormatMap
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$formatClass = get_class($dateFormatField);
|
||||||
$dateFormatField->setValue($self->DateFormat);
|
$dateFormatField->setValue($self->DateFormat);
|
||||||
$dateFormatField->setDescriptionTemplate('forms/MemberDatetimeOptionsetField_description_date');
|
$dateTemplate = SSViewer::get_templates_by_class($formatClass, '_description_date', $formatClass);
|
||||||
|
$dateFormatField->setDescriptionTemplate($dateTemplate);
|
||||||
|
|
||||||
$defaultTimeFormat = Zend_Locale_Format::getTimeFormat(new Zend_Locale($self->Locale));
|
$defaultTimeFormat = Zend_Locale_Format::getTimeFormat(new Zend_Locale($self->Locale));
|
||||||
$timeFormatMap = array(
|
$timeFormatMap = array(
|
||||||
@ -1559,7 +1562,8 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
$timeFormatField->setValue($self->TimeFormat);
|
$timeFormatField->setValue($self->TimeFormat);
|
||||||
$timeFormatField->setDescriptionTemplate('forms/MemberDatetimeOptionsetField_description_time');
|
$timeTemplate = SSViewer::get_templates_by_class($formatClass,'_description_time', $formatClass);
|
||||||
|
$timeFormatField->setDescriptionTemplate($timeTemplate);
|
||||||
});
|
});
|
||||||
|
|
||||||
return parent::getCMSFields();
|
return parent::getCMSFields();
|
||||||
|
@ -972,7 +972,8 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getTemplatesWithSuffix($suffix) {
|
public function getTemplatesWithSuffix($suffix) {
|
||||||
return SSViewer::get_templates_by_class(get_class($this), $suffix, 'SilverStripe\\Admin\\LeftAndMain');
|
$templates = SSViewer::get_templates_by_class(get_class($this), $suffix, __CLASS__);
|
||||||
|
return SSViewer::chooseTemplate($templates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Content() {
|
public function Content() {
|
||||||
|
@ -165,7 +165,7 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
// Add import capabilities. Limit to admin since the import logic can affect assigned permissions
|
// Add import capabilities. Limit to admin since the import logic can affect assigned permissions
|
||||||
if(Permission::check('ADMIN')) {
|
if(Permission::check('ADMIN')) {
|
||||||
$fields->addFieldsToTab('Root.Users', array(
|
$fields->addFieldsToTab('Root.Users', array(
|
||||||
new HeaderField(_t('SecurityAdmin.IMPORTUSERS', 'Import users'), 3),
|
new HeaderField('ImportUsersHeader', _t('SecurityAdmin.IMPORTUSERS', 'Import users'), 3),
|
||||||
new LiteralField(
|
new LiteralField(
|
||||||
'MemberImportFormIframe',
|
'MemberImportFormIframe',
|
||||||
sprintf(
|
sprintf(
|
||||||
@ -176,7 +176,7 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
|||||||
)
|
)
|
||||||
));
|
));
|
||||||
$fields->addFieldsToTab('Root.Groups', array(
|
$fields->addFieldsToTab('Root.Groups', array(
|
||||||
new HeaderField(_t('SecurityAdmin.IMPORTGROUPS', 'Import groups'), 3),
|
new HeaderField('ImportGroupsHeader', _t('SecurityAdmin.IMPORTGROUPS', 'Import groups'), 3),
|
||||||
new LiteralField(
|
new LiteralField(
|
||||||
'GroupImportFormIframe',
|
'GroupImportFormIframe',
|
||||||
sprintf(
|
sprintf(
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
use SilverStripe\ORM\SS_List;
|
use SilverStripe\ORM\SS_List;
|
||||||
use SilverStripe\ORM\ArrayList;
|
use SilverStripe\ORM\ArrayList;
|
||||||
use SilverStripe\ORM\FieldType\DBField;
|
use SilverStripe\ORM\FieldType\DBField;
|
||||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RSSFeed class
|
* RSSFeed class
|
||||||
*
|
*
|
||||||
@ -91,9 +89,11 @@ class RSSFeed extends ViewableData {
|
|||||||
protected $etag;
|
protected $etag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Custom template
|
||||||
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $template = 'RSSFeed';
|
protected $template = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -219,7 +219,7 @@ class RSSFeed extends ViewableData {
|
|||||||
|
|
||||||
Config::inst()->update('SSViewer', 'source_file_comments', $prevState);
|
Config::inst()->update('SSViewer', 'source_file_comments', $prevState);
|
||||||
|
|
||||||
return $this->renderWith($this->getTemplate());
|
return $this->renderWith($this->getTemplates());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -240,6 +240,21 @@ class RSSFeed extends ViewableData {
|
|||||||
public function getTemplate() {
|
public function getTemplate() {
|
||||||
return $this->template;
|
return $this->template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ordered list of preferred templates for rendering this object.
|
||||||
|
* Will prioritise any custom template first, and then templates based on class hiearchy next.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTemplates() {
|
||||||
|
$templates = SSViewer::get_templates_by_class(get_class($this), '', __CLASS__);
|
||||||
|
// Prefer any custom template
|
||||||
|
if($this->getTemplate()) {
|
||||||
|
array_unshift($templates, $this->getTemplate());
|
||||||
|
}
|
||||||
|
return $templates;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,15 +87,17 @@ class ClassInfo {
|
|||||||
*
|
*
|
||||||
* @todo Move this into {@see DataObjectSchema}
|
* @todo Move this into {@see DataObjectSchema}
|
||||||
*
|
*
|
||||||
* @param string|object $class
|
* @param string|object $nameOrObject Class or object instance
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function dataClassesFor($class) {
|
public static function dataClassesFor($nameOrObject) {
|
||||||
if(is_string($class) && !class_exists($class)) return array();
|
if(is_string($nameOrObject) && !class_exists($nameOrObject)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
$result = array();
|
$result = array();
|
||||||
|
|
||||||
$class = self::class_name($class);
|
$class = self::class_name($nameOrObject);
|
||||||
|
|
||||||
$classes = array_merge(
|
$classes = array_merge(
|
||||||
self::ancestry($class),
|
self::ancestry($class),
|
||||||
@ -134,17 +136,17 @@ class ClassInfo {
|
|||||||
* )
|
* )
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
* @param mixed $class string of the classname or instance of the class
|
* @param string|object $nameOrObject The classname or object
|
||||||
* @return array Names of all subclasses as an associative array.
|
* @return array Names of all subclasses as an associative array.
|
||||||
*/
|
*/
|
||||||
public static function subclassesFor($class) {
|
public static function subclassesFor($nameOrObject) {
|
||||||
if(is_string($class) && !class_exists($class)) {
|
if(is_string($nameOrObject) && !class_exists($nameOrObject)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
//normalise class case
|
//normalise class case
|
||||||
$className = self::class_name($class);
|
$className = self::class_name($nameOrObject);
|
||||||
$descendants = SS_ClassLoader::instance()->getManifest()->getDescendantsOf($class);
|
$descendants = SS_ClassLoader::instance()->getManifest()->getDescendantsOf($className);
|
||||||
$result = array($className => $className);
|
$result = array($className => $className);
|
||||||
|
|
||||||
if ($descendants) {
|
if ($descendants) {
|
||||||
@ -174,14 +176,16 @@ class ClassInfo {
|
|||||||
* Returns the passed class name along with all its parent class names in an
|
* Returns the passed class name along with all its parent class names in an
|
||||||
* array, sorted with the root class first.
|
* array, sorted with the root class first.
|
||||||
*
|
*
|
||||||
* @param string $class
|
* @param string|object $nameOrObject Class or object instance
|
||||||
* @param bool $tablesOnly Only return classes that have a table in the db.
|
* @param bool $tablesOnly Only return classes that have a table in the db.
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function ancestry($class, $tablesOnly = false) {
|
public static function ancestry($nameOrObject, $tablesOnly = false) {
|
||||||
if(is_string($class) && !class_exists($class)) return array();
|
if(is_string($nameOrObject) && !class_exists($nameOrObject)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
$class = self::class_name($class);
|
$class = self::class_name($nameOrObject);
|
||||||
|
|
||||||
$lClass = strtolower($class);
|
$lClass = strtolower($class);
|
||||||
|
|
||||||
|
@ -201,11 +201,13 @@ You can use inequalities like `<`, `<=`, `>`, `>=` to compare numbers.
|
|||||||
## Includes
|
## Includes
|
||||||
|
|
||||||
Within SilverStripe templates we have the ability to include other templates using the `<% include %>` tag. The includes
|
Within SilverStripe templates we have the ability to include other templates using the `<% include %>` tag. The includes
|
||||||
will be searched for using the same filename look-up rules as a regular template, so this will include
|
will be searched for using the same filename look-up rules as a regular template. However in the case of the include tag
|
||||||
`templates/Includes/Sidebar.ss`
|
an additional `Includes` directory will be inserted into the resolved path just prior to the filename.
|
||||||
|
|
||||||
:::ss
|
E.g.
|
||||||
<% include Includes\SideBar %>
|
|
||||||
|
* `<% include SideBar %>` will include `templates/Includes/Sidebar.ss`
|
||||||
|
* `<% include MyNamespace/SideBar %>` will include `templates/MyNamespace/Includes/Sidebar.ss`
|
||||||
|
|
||||||
Note that in SilverStripe 3, you didn't have to specify a namespace in your `include` tag, as the template engine didn't
|
Note that in SilverStripe 3, you didn't have to specify a namespace in your `include` tag, as the template engine didn't
|
||||||
use namespaces. As of SilverStripe 4, the template namespaces need to match the folder structure of your template files.
|
use namespaces. As of SilverStripe 4, the template namespaces need to match the folder structure of your template files.
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
* Search filter classes (e.g. `ExactMatchFilter`) are now registered with `Injector`
|
* Search filter classes (e.g. `ExactMatchFilter`) are now registered with `Injector`
|
||||||
via a new `DataListFilter.` prefix convention.
|
via a new `DataListFilter.` prefix convention.
|
||||||
see [search filter documentation](/developer_guides/model/searchfilters) for more information.
|
see [search filter documentation](/developer_guides/model/searchfilters) for more information.
|
||||||
|
* FormField templates no longer look in the 'forms' folder for templates.
|
||||||
|
|
||||||
## New API
|
## New API
|
||||||
|
|
||||||
@ -126,6 +127,9 @@
|
|||||||
* `PopoverField` added to provide popup-menu behaviour in react forms (currently not available for
|
* `PopoverField` added to provide popup-menu behaviour in react forms (currently not available for
|
||||||
non-react forms).
|
non-react forms).
|
||||||
* Admin URL can now be configured via custom Director routing rule
|
* Admin URL can now be configured via custom Director routing rule
|
||||||
|
* Templates now use a standard template lookup system via `SSViewer::get_templates_by_class`
|
||||||
|
which builds a candidate list for a given class. Actual resolution of existing templates
|
||||||
|
for any list of candidates is actually performed by `SSViewer::chooseTemplate`
|
||||||
|
|
||||||
### Front-end build tooling for CMS interface
|
### Front-end build tooling for CMS interface
|
||||||
|
|
||||||
@ -415,8 +419,14 @@ require manual intervention, please see the below upgrading notes.
|
|||||||
Templates are now much more strict about their locations. You can no longer put a template in an arbitrary
|
Templates are now much more strict about their locations. You can no longer put a template in an arbitrary
|
||||||
folder and have it be found. Case is now also checked on case-sensitive filesystems.
|
folder and have it be found. Case is now also checked on case-sensitive filesystems.
|
||||||
|
|
||||||
Either include the folder in the template name (`renderWith('Field.ss')` => `renderWith('forms/Field.ss')`), move the
|
Either include the folder in the template name (`renderWith('MyEmail.ss')` => `renderWith('emails/MyEmail.ss')`),
|
||||||
template into the correct directory, or both.
|
move the template into the correct directory, or both.
|
||||||
|
|
||||||
|
When using `<% include %>` template tag you should continue to leave out the `Includes` folder.
|
||||||
|
`<% include Sidebar %>` will match only match `Includes/Sidebar.ss`, not `Sidebar.ss`.
|
||||||
|
Please refer to our [template syntax](/developer_guides/templates/syntax) for details.
|
||||||
|
|
||||||
|
The `forms` template folder is no longer used to lookup templates for `FormField` instances.
|
||||||
|
|
||||||
### Update code that uses SQLQuery
|
### Update code that uses SQLQuery
|
||||||
|
|
||||||
|
@ -479,9 +479,11 @@ class Email extends ViewableData {
|
|||||||
if($this->ss_template && !$isPlain) {
|
if($this->ss_template && !$isPlain) {
|
||||||
// Requery data so that updated versions of To, From, Subject, etc are included
|
// Requery data so that updated versions of To, From, Subject, etc are included
|
||||||
$data = $this->templateData();
|
$data = $this->templateData();
|
||||||
|
$candidateTemplates = [
|
||||||
$template = new SSViewer('email/'.$this->ss_template);
|
$this->ss_template,
|
||||||
|
[ 'type' => 'email', $this->ss_template ]
|
||||||
|
];
|
||||||
|
$template = new SSViewer($candidateTemplates);
|
||||||
if($template->exists()) {
|
if($template->exists()) {
|
||||||
$fullBody = $template->process($data);
|
$fullBody = $template->process($data);
|
||||||
}
|
}
|
||||||
|
@ -1025,14 +1025,27 @@ class Form extends RequestHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the template to render this form with.
|
* Return the template to render this form with.
|
||||||
* If the template isn't set, then default to the
|
|
||||||
* form class name e.g "Form".
|
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getTemplate() {
|
public function getTemplate() {
|
||||||
if($this->template) return $this->template;
|
return $this->template;
|
||||||
else return $this->class;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returs the ordered list of preferred templates for rendering this form
|
||||||
|
* If the template isn't set, then default to the
|
||||||
|
* form class name e.g "Form".
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTemplates() {
|
||||||
|
$templates = SSViewer::get_templates_by_class(get_class($this), '', __CLASS__);
|
||||||
|
// Prefer any custom template
|
||||||
|
if($this->getTemplate()) {
|
||||||
|
array_unshift($templates, $this->getTemplate());
|
||||||
|
}
|
||||||
|
return $templates;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1639,10 +1652,7 @@ class Form extends RequestHandler {
|
|||||||
* @return DBHTMLText
|
* @return DBHTMLText
|
||||||
*/
|
*/
|
||||||
public function forTemplate() {
|
public function forTemplate() {
|
||||||
$return = $this->renderWith(array_merge(
|
$return = $this->renderWith($this->getTemplates());
|
||||||
(array)$this->getTemplate(),
|
|
||||||
array('Includes/Form')
|
|
||||||
));
|
|
||||||
|
|
||||||
// Now that we're rendered, clear message
|
// Now that we're rendered, clear message
|
||||||
$this->clearMessage();
|
$this->clearMessage();
|
||||||
|
@ -761,7 +761,6 @@ class FormField extends RequestHandler {
|
|||||||
*
|
*
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @param null|array|DataObject $data {@see Form::loadDataFrom}
|
* @param null|array|DataObject $data {@see Form::loadDataFrom}
|
||||||
*
|
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setValue($value) {
|
public function setValue($value) {
|
||||||
@ -1048,22 +1047,14 @@ class FormField extends RequestHandler {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
private function _templates($customTemplate = null, $customTemplateSuffix = null) {
|
protected function _templates($customTemplate = null, $customTemplateSuffix = null) {
|
||||||
$matches = array();
|
$templates = SSViewer::get_templates_by_class(get_class($this), $customTemplateSuffix, __CLASS__);
|
||||||
|
// Prefer any custom template
|
||||||
foreach(array_reverse(ClassInfo::ancestry($this)) as $className) {
|
|
||||||
$matches[] = 'forms/'. $className . $customTemplateSuffix;
|
|
||||||
|
|
||||||
if($className == "FormField") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($customTemplate) {
|
if($customTemplate) {
|
||||||
array_unshift($matches, 'forms/'.$customTemplate);
|
// Prioritise direct template
|
||||||
|
array_unshift($templates, $customTemplate);
|
||||||
}
|
}
|
||||||
|
return $templates;
|
||||||
return $matches;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,13 +25,6 @@ use SilverStripe\ORM\DataList;
|
|||||||
class GridFieldAddExistingAutocompleter
|
class GridFieldAddExistingAutocompleter
|
||||||
implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator, GridField_URLHandler {
|
implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator, GridField_URLHandler {
|
||||||
|
|
||||||
/**
|
|
||||||
* Which template to use for rendering
|
|
||||||
*
|
|
||||||
* @var string $itemClass
|
|
||||||
*/
|
|
||||||
protected $itemClass = 'GridFieldAddExistingAutocompleter';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The HTML fragment to write this component into
|
* The HTML fragment to write this component into
|
||||||
*/
|
*/
|
||||||
@ -84,6 +77,7 @@ class GridFieldAddExistingAutocompleter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
* @param string $targetFragment
|
||||||
* @param array $searchFields Which fields on the object in the list should be searched
|
* @param array $searchFields Which fields on the object in the list should be searched
|
||||||
*/
|
*/
|
||||||
public function __construct($targetFragment = 'before', $searchFields = null) {
|
public function __construct($targetFragment = 'before', $searchFields = null) {
|
||||||
@ -97,7 +91,7 @@ class GridFieldAddExistingAutocompleter
|
|||||||
* @return string[] - HTML
|
* @return string[] - HTML
|
||||||
*/
|
*/
|
||||||
public function getHTMLFragments($gridField) {
|
public function getHTMLFragments($gridField) {
|
||||||
$dataClass = $gridField->getList()->dataClass();
|
$dataClass = $gridField->getModelClass();
|
||||||
|
|
||||||
$forTemplate = new ArrayData(array());
|
$forTemplate = new ArrayData(array());
|
||||||
$forTemplate->Fields = new FieldList();
|
$forTemplate->Fields = new FieldList();
|
||||||
@ -130,8 +124,9 @@ class GridFieldAddExistingAutocompleter
|
|||||||
$forTemplate->Fields->setForm($form);
|
$forTemplate->Fields->setForm($form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
$this->targetFragment => $forTemplate->renderWith('Includes/'.$this->itemClass)
|
$this->targetFragment => $forTemplate->renderWith($template)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +169,7 @@ class GridFieldAddExistingAutocompleter
|
|||||||
if(empty($objectID)) {
|
if(empty($objectID)) {
|
||||||
return $dataList;
|
return $dataList;
|
||||||
}
|
}
|
||||||
$object = DataObject::get_by_id($dataList->dataclass(), $objectID);
|
$object = DataObject::get_by_id($gridField->getModelClass(), $objectID);
|
||||||
if($object) {
|
if($object) {
|
||||||
$dataList->add($object);
|
$dataList->add($object);
|
||||||
}
|
}
|
||||||
@ -198,9 +193,10 @@ class GridFieldAddExistingAutocompleter
|
|||||||
*
|
*
|
||||||
* @param GridField $gridField
|
* @param GridField $gridField
|
||||||
* @param SS_HTTPRequest $request
|
* @param SS_HTTPRequest $request
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function doSearch($gridField, $request) {
|
public function doSearch($gridField, $request) {
|
||||||
$dataClass = $gridField->getList()->dataClass();
|
$dataClass = $gridField->getModelClass();
|
||||||
$allList = $this->searchList ? $this->searchList : DataList::create($dataClass);
|
$allList = $this->searchList ? $this->searchList : DataList::create($dataClass);
|
||||||
|
|
||||||
$searchFields = ($this->getSearchFields())
|
$searchFields = ($this->getSearchFields())
|
||||||
@ -269,6 +265,7 @@ class GridFieldAddExistingAutocompleter
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $fields
|
* @param array $fields
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setSearchFields($fields) {
|
public function setSearchFields($fields) {
|
||||||
$this->searchFields = $fields;
|
$this->searchFields = $fields;
|
||||||
|
@ -43,8 +43,9 @@ class GridFieldAddNewButton implements GridField_HTMLProvider {
|
|||||||
'ButtonName' => $this->buttonName,
|
'ButtonName' => $this->buttonName,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$templates = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
$this->targetFragment => $data->renderWith('Includes/GridFieldAddNewButton'),
|
$this->targetFragment => $data->renderWith($templates),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,9 @@ class GridFieldButtonRow implements GridField_HTMLProvider {
|
|||||||
"RightFragment" => "\$DefineFragment(buttons-{$this->targetFragment}-right)",
|
"RightFragment" => "\$DefineFragment(buttons-{$this->targetFragment}-right)",
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$templates = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
$this->targetFragment => $data->renderWith('Includes/GridFieldButtonRow')
|
$this->targetFragment => $data->renderWith($templates)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ class GridFieldDetailForm implements GridField_URLHandler {
|
|||||||
$class,
|
$class,
|
||||||
array($gridField, $this, $record, $requestHandler, $this->name)
|
array($gridField, $this, $record, $requestHandler, $this->name)
|
||||||
);
|
);
|
||||||
$handler->setTemplate($this->template);
|
$handler->setTemplate($this->getTemplate());
|
||||||
$this->extend('updateItemRequestHandler', $handler);
|
$this->extend('updateItemRequestHandler', $handler);
|
||||||
return $handler;
|
return $handler;
|
||||||
}
|
}
|
||||||
@ -214,7 +214,7 @@ class GridFieldDetailForm implements GridField_URLHandler {
|
|||||||
} else if(ClassInfo::exists(get_class($this) . "_ItemRequest")) {
|
} else if(ClassInfo::exists(get_class($this) . "_ItemRequest")) {
|
||||||
return get_class($this) . "_ItemRequest";
|
return get_class($this) . "_ItemRequest";
|
||||||
} else {
|
} else {
|
||||||
return 'GridFieldDetailForm_ItemRequest';
|
return __CLASS__ . '_ItemRequest';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @var GridField_URLHandler
|
* @var GridFieldDetailForm
|
||||||
*/
|
*/
|
||||||
protected $component;
|
protected $component;
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
|
|||||||
/**
|
/**
|
||||||
* @var String
|
* @var String
|
||||||
*/
|
*/
|
||||||
protected $template = 'GridFieldItemEditView';
|
protected $template = null;
|
||||||
|
|
||||||
private static $url_handlers = array(
|
private static $url_handlers = array(
|
||||||
'$Action!' => '$Action',
|
'$Action!' => '$Action',
|
||||||
@ -293,7 +293,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param GridFIeld $gridField
|
* @param GridFIeld $gridField
|
||||||
* @param GridField_URLHandler $component
|
* @param GridFieldDetailForm $component
|
||||||
* @param DataObject $record
|
* @param DataObject $record
|
||||||
* @param RequestHandler $requestHandler
|
* @param RequestHandler $requestHandler
|
||||||
* @param string $popupFormName
|
* @param string $popupFormName
|
||||||
@ -319,14 +319,14 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
|
|||||||
|
|
||||||
$controller = $this->getToplevelController();
|
$controller = $this->getToplevelController();
|
||||||
|
|
||||||
$form = $this->ItemEditForm($this->gridField, $request);
|
$form = $this->ItemEditForm();
|
||||||
$form->makeReadonly();
|
$form->makeReadonly();
|
||||||
|
|
||||||
$data = new ArrayData(array(
|
$data = new ArrayData(array(
|
||||||
'Backlink' => $controller->Link(),
|
'Backlink' => $controller->Link(),
|
||||||
'ItemEditForm' => $form
|
'ItemEditForm' => $form
|
||||||
));
|
));
|
||||||
$return = $data->renderWith($this->template);
|
$return = $data->renderWith($this->getTemplates());
|
||||||
|
|
||||||
if($request->isAjax()) {
|
if($request->isAjax()) {
|
||||||
return $return;
|
return $return;
|
||||||
@ -337,12 +337,12 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
|
|||||||
|
|
||||||
public function edit($request) {
|
public function edit($request) {
|
||||||
$controller = $this->getToplevelController();
|
$controller = $this->getToplevelController();
|
||||||
$form = $this->ItemEditForm($this->gridField, $request);
|
$form = $this->ItemEditForm();
|
||||||
|
|
||||||
$return = $this->customise(array(
|
$return = $this->customise(array(
|
||||||
'Backlink' => $controller->hasMethod('Backlink') ? $controller->Backlink() : $controller->Link(),
|
'Backlink' => $controller->hasMethod('Backlink') ? $controller->Backlink() : $controller->Link(),
|
||||||
'ItemEditForm' => $form,
|
'ItemEditForm' => $form,
|
||||||
))->renderWith($this->template);
|
))->renderWith($this->getTemplates());
|
||||||
|
|
||||||
if($request->isAjax()) {
|
if($request->isAjax()) {
|
||||||
return $return;
|
return $return;
|
||||||
@ -751,6 +751,21 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler {
|
|||||||
return $this->template;
|
return $this->template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get list of templates to use
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTemplates()
|
||||||
|
{
|
||||||
|
$templates = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
|
// Prefer any custom template
|
||||||
|
if($this->getTemplate()) {
|
||||||
|
array_unshift($templates, $this->getTemplate());
|
||||||
|
}
|
||||||
|
return $templates;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Controller
|
* @return Controller
|
||||||
*/
|
*/
|
||||||
|
@ -49,6 +49,7 @@ class GridFieldEditButton implements GridField_ColumnProvider {
|
|||||||
if($columnName == 'Actions') {
|
if($columnName == 'Actions') {
|
||||||
return array('title' => '');
|
return array('title' => '');
|
||||||
}
|
}
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,8 +76,7 @@ class GridFieldEditButton implements GridField_ColumnProvider {
|
|||||||
* @param GridField $gridField
|
* @param GridField $gridField
|
||||||
* @param DataObject $record
|
* @param DataObject $record
|
||||||
* @param string $columnName
|
* @param string $columnName
|
||||||
*
|
* @return string The HTML for the column
|
||||||
* @return string - the HTML for the column
|
|
||||||
*/
|
*/
|
||||||
public function getColumnContent($gridField, $record, $columnName) {
|
public function getColumnContent($gridField, $record, $columnName) {
|
||||||
// No permission checks, handled through GridFieldDetailForm,
|
// No permission checks, handled through GridFieldDetailForm,
|
||||||
@ -86,7 +86,8 @@ class GridFieldEditButton implements GridField_ColumnProvider {
|
|||||||
'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')
|
'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')
|
||||||
));
|
));
|
||||||
|
|
||||||
return $data->renderWith('Includes/GridFieldEditButton');
|
$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
|
return $data->renderWith($template);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,8 +161,9 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
|
|||||||
$forTemplate->Fields->push($fields);
|
$forTemplate->Fields->push($fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$templates = SSViewer::get_templates_by_class($this, '_Row', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
'header' => $forTemplate->renderWith('Includes/GridFieldFilterHeader_Row'),
|
'header' => $forTemplate->renderWith($templates),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@ class GridFieldFooter implements GridField_HTMLProvider {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $message - a message to display in the footer
|
* @param string $message A message to display in the footer
|
||||||
|
* @param bool $showrecordcount
|
||||||
*/
|
*/
|
||||||
public function __construct($message = null, $showrecordcount = true) {
|
public function __construct($message = null, $showrecordcount = true) {
|
||||||
if($message) {
|
if($message) {
|
||||||
@ -46,9 +47,10 @@ class GridFieldFooter implements GridField_HTMLProvider {
|
|||||||
'NumRecords' => $count
|
'NumRecords' => $count
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
'footer' => $forTemplate->renderWith(
|
'footer' => $forTemplate->renderWith(
|
||||||
'Includes/GridFieldFooter',
|
$template,
|
||||||
array(
|
array(
|
||||||
'Colspan' => count($gridField->getColumns())
|
'Colspan' => count($gridField->getColumns())
|
||||||
)
|
)
|
||||||
|
@ -35,41 +35,49 @@ class GridFieldLevelup extends Object implements GridField_HTMLProvider {
|
|||||||
* @param integer $currentID - The ID of the current item; this button will find that item's parent
|
* @param integer $currentID - The ID of the current item; this button will find that item's parent
|
||||||
*/
|
*/
|
||||||
public function __construct($currentID) {
|
public function __construct($currentID) {
|
||||||
if($currentID && is_numeric($currentID)) $this->currentID = $currentID;
|
parent::__construct();
|
||||||
|
if($currentID && is_numeric($currentID)) {
|
||||||
|
$this->currentID = $currentID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHTMLFragments($gridField) {
|
public function getHTMLFragments($gridField) {
|
||||||
$modelClass = $gridField->getModelClass();
|
$modelClass = $gridField->getModelClass();
|
||||||
$parentID = 0;
|
$parentID = 0;
|
||||||
|
|
||||||
if($this->currentID) {
|
if(!$this->currentID) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$modelObj = DataObject::get_by_id($modelClass, $this->currentID);
|
$modelObj = DataObject::get_by_id($modelClass, $this->currentID);
|
||||||
|
|
||||||
|
$parent = null;
|
||||||
if($modelObj->hasMethod('getParent')) {
|
if($modelObj->hasMethod('getParent')) {
|
||||||
$parent = $modelObj->getParent();
|
$parent = $modelObj->getParent();
|
||||||
} elseif($modelObj->ParentID) {
|
} elseif($modelObj->ParentID) {
|
||||||
$parent = $modelObj->Parent();
|
$parent = $modelObj->Parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if($parent) $parentID = $parent->ID;
|
if ($parent) {
|
||||||
|
$parentID = $parent->ID;
|
||||||
|
}
|
||||||
|
|
||||||
// Attributes
|
// Attributes
|
||||||
$attrs = array_merge($this->attributes, array(
|
$attrs = array_merge($this->attributes, array(
|
||||||
'href' => sprintf($this->linkSpec, $parentID),
|
'href' => sprintf($this->linkSpec, $parentID),
|
||||||
'class' => 'cms-panel-link ss-ui-button font-icon-level-up no-text grid-levelup'
|
'class' => 'cms-panel-link ss-ui-button font-icon-level-up no-text grid-levelup'
|
||||||
));
|
));
|
||||||
$attrsStr = '';
|
$linkTag = FormField::create_tag('a', $attrs);
|
||||||
foreach($attrs as $k => $v) $attrsStr .= " $k=\"" . Convert::raw2att($v) . "\"";
|
|
||||||
|
|
||||||
$forTemplate = new ArrayData(array(
|
$forTemplate = new ArrayData(array(
|
||||||
'UpLink' => DBField::create_field('HTMLFragment', sprintf('<a%s></a>', $attrsStr))
|
'UpLink' => DBField::create_field('HTMLFragment', $linkTag)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
'before' => $forTemplate->renderWith('Includes/GridFieldLevelup'),
|
'before' => $forTemplate->renderWith($template),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public function setAttributes($attrs) {
|
public function setAttributes($attrs) {
|
||||||
$this->attributes = $attrs;
|
$this->attributes = $attrs;
|
||||||
|
@ -16,14 +16,7 @@ class GridFieldPageCount implements GridField_HTMLProvider {
|
|||||||
protected $targetFragment;
|
protected $targetFragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Which template to use for rendering
|
* @param string $targetFragment The fragment indicating the placement of this page count
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $itemClass = 'GridFieldPageCount';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $targetFrament The fragment indicating the placement of this page count
|
|
||||||
*/
|
*/
|
||||||
public function __construct($targetFragment = 'before') {
|
public function __construct($targetFragment = 'before') {
|
||||||
$this->targetFragment = $targetFragment;
|
$this->targetFragment = $targetFragment;
|
||||||
@ -62,14 +55,16 @@ class GridFieldPageCount implements GridField_HTMLProvider {
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getHTMLFragments($gridField) {
|
public function getHTMLFragments($gridField) {
|
||||||
|
|
||||||
// Retrieve paging parameters from the directing paginator component
|
// Retrieve paging parameters from the directing paginator component
|
||||||
$paginator = $this->getPaginator($gridField);
|
$paginator = $this->getPaginator($gridField);
|
||||||
if ($paginator && ($forTemplate = $paginator->getTemplateParameters($gridField))) {
|
if ($paginator && ($forTemplate = $paginator->getTemplateParameters($gridField))) {
|
||||||
|
$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
$this->targetFragment => $forTemplate->renderWith('Includes/'.$this->itemClass)
|
$this->targetFragment => $forTemplate->renderWith($template)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,6 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
|
|||||||
*/
|
*/
|
||||||
protected $itemsPerPage;
|
protected $itemsPerPage;
|
||||||
|
|
||||||
/**
|
|
||||||
* Which template to use for rendering
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $itemClass = 'GridFieldPaginator_Row';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link setThrowExceptionOnBadDataType()}
|
* See {@link setThrowExceptionOnBadDataType()}
|
||||||
*/
|
*/
|
||||||
@ -255,18 +248,22 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getHTMLFragments($gridField) {
|
public function getHTMLFragments($gridField) {
|
||||||
|
|
||||||
$forTemplate = $this->getTemplateParameters($gridField);
|
$forTemplate = $this->getTemplateParameters($gridField);
|
||||||
if($forTemplate) {
|
if(!$forTemplate) {
|
||||||
return array(
|
return null;
|
||||||
'footer' => $forTemplate->renderWith('Includes/'.$this->itemClass,
|
|
||||||
array('Colspan'=>count($gridField->getColumns())))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
$template = SSViewer::get_templates_by_class($this, '_Row', __CLASS__);
|
||||||
|
return array(
|
||||||
|
'footer' => $forTemplate->renderWith(
|
||||||
|
$template,
|
||||||
|
array('Colspan' => count($gridField->getColumns()))
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Int
|
* @param int $num
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setItemsPerPage($num) {
|
public function setItemsPerPage($num) {
|
||||||
$this->itemsPerPage = $num;
|
$this->itemsPerPage = $num;
|
||||||
|
@ -121,8 +121,10 @@ class GridFieldPrintButton implements GridField_HTMLProvider, GridField_ActionPr
|
|||||||
Requirements::css(FRAMEWORK_DIR . '/client/dist/styles/GridField_print.css');
|
Requirements::css(FRAMEWORK_DIR . '/client/dist/styles/GridField_print.css');
|
||||||
|
|
||||||
if($data = $this->generatePrintData($gridField)){
|
if($data = $this->generatePrintData($gridField)){
|
||||||
return $data->renderWith("GridField_print");
|
return $data->renderWith(get_class($gridField)."_print");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,8 +163,9 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
|
|||||||
$forTemplate->Fields->push($field);
|
$forTemplate->Fields->push($field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$template = SSViewer::get_templates_by_class($this, '_Row', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
'header' => $forTemplate->renderWith('Includes/GridFieldSortableHeader_Row'),
|
'header' => $forTemplate->renderWith($template),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,9 +11,14 @@
|
|||||||
*/
|
*/
|
||||||
class GridFieldToolbarHeader implements GridField_HTMLProvider {
|
class GridFieldToolbarHeader implements GridField_HTMLProvider {
|
||||||
|
|
||||||
public function getHTMLFragments( $gridField) {
|
/**
|
||||||
|
* @param GridField $gridField
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getHTMLFragments($gridField) {
|
||||||
|
$templates = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
return array(
|
return array(
|
||||||
'header' => $gridField->renderWith('Includes/GridFieldToolbarHeader')
|
'header' => $gridField->renderWith($templates)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@
|
|||||||
class GridFieldViewButton implements GridField_ColumnProvider {
|
class GridFieldViewButton implements GridField_ColumnProvider {
|
||||||
|
|
||||||
public function augmentColumns($field, &$cols) {
|
public function augmentColumns($field, &$cols) {
|
||||||
if(!in_array('Actions', $cols)) $cols[] = 'Actions';
|
if(!in_array('Actions', $cols)) {
|
||||||
|
$cols[] = 'Actions';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getColumnsHandled($field) {
|
public function getColumnsHandled($field) {
|
||||||
@ -18,12 +20,14 @@ class GridFieldViewButton implements GridField_ColumnProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getColumnContent($field, $record, $col) {
|
public function getColumnContent($field, $record, $col) {
|
||||||
if($record->canView()) {
|
if(!$record->canView()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
$data = new ArrayData(array(
|
$data = new ArrayData(array(
|
||||||
'Link' => Controller::join_links($field->Link('item'), $record->ID, 'view')
|
'Link' => Controller::join_links($field->Link('item'), $record->ID, 'view')
|
||||||
));
|
));
|
||||||
return $data->renderWith('Includes/GridFieldViewButton');
|
$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||||
}
|
return $data->renderWith($template);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getColumnAttributes($field, $record, $col) {
|
public function getColumnAttributes($field, $record, $col) {
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
<% if Backlink %>
|
|
||||||
<a href="$Backlink"><%t GridFieldItemEditView.Go_back 'Go back' %></a>
|
|
||||||
<% end_if %>
|
|
||||||
|
|
||||||
$ItemEditForm
|
|
@ -76,7 +76,7 @@ class RSSFeedTest extends SapphireTest {
|
|||||||
$content = $rssFeed->outputToBrowser();
|
$content = $rssFeed->outputToBrowser();
|
||||||
$this->assertContains('<title>Test Custom Template</title>', $content);
|
$this->assertContains('<title>Test Custom Template</title>', $content);
|
||||||
|
|
||||||
$rssFeed->setTemplate('RSSFeed');
|
$rssFeed->setTemplate(null);
|
||||||
$content = $rssFeed->outputToBrowser();
|
$content = $rssFeed->outputToBrowser();
|
||||||
$this->assertNotContains('<title>Test Custom Template</title>', $content);
|
$this->assertNotContains('<title>Test Custom Template</title>', $content);
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,31 @@ class ThemeResourceLoaderTest extends SapphireTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFindTemplatesByPath() {
|
||||||
|
// Items given as full paths are returned directly
|
||||||
|
$this->assertEquals(
|
||||||
|
"$this->base/themes/theme/templates/Page.ss",
|
||||||
|
$this->loader->findTemplate("$this->base/themes/theme/templates/Page.ss", ['theme'])
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
"$this->base/themes/theme/templates/Page.ss",
|
||||||
|
$this->loader->findTemplate([
|
||||||
|
"$this->base/themes/theme/templates/Page.ss",
|
||||||
|
"Page"
|
||||||
|
], ['theme'])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure checks for file_exists
|
||||||
|
$this->assertEquals(
|
||||||
|
"$this->base/themes/theme/templates/Page.ss",
|
||||||
|
$this->loader->findTemplate([
|
||||||
|
"$this->base/themes/theme/templates/NotAPage.ss",
|
||||||
|
"$this->base/themes/theme/templates/Page.ss",
|
||||||
|
], ['theme'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that 'main' and 'Layout' templates are loaded from set theme
|
* Test that 'main' and 'Layout' templates are loaded from set theme
|
||||||
*/
|
*/
|
||||||
|
@ -110,7 +110,7 @@ class MemberDatetimeOptionsetFieldTest extends SapphireTest {
|
|||||||
$field->setDescription('Test description');
|
$field->setDescription('Test description');
|
||||||
$this->assertEquals('Test description', $field->getDescription());
|
$this->assertEquals('Test description', $field->getDescription());
|
||||||
|
|
||||||
$field->setDescriptionTemplate('forms/MemberDatetimeOptionsetField_description_time');
|
$field->setDescriptionTemplate('MemberDatetimeOptionsetField_description_time');
|
||||||
$this->assertNotEmpty($field->getDescription());
|
$this->assertNotEmpty($field->getDescription());
|
||||||
$this->assertNotEquals('Test description', $field->getDescription());
|
$this->assertNotEquals('Test description', $field->getDescription());
|
||||||
}
|
}
|
||||||
|
@ -1154,22 +1154,57 @@ after')
|
|||||||
$this->useTestTheme(dirname(__FILE__), 'layouttest', function() use ($self) {
|
$this->useTestTheme(dirname(__FILE__), 'layouttest', function() use ($self) {
|
||||||
// Test passing a string
|
// Test passing a string
|
||||||
$templates = SSViewer::get_templates_by_class(
|
$templates = SSViewer::get_templates_by_class(
|
||||||
'TestNamespace\SSViewerTestModel_Controller',
|
'TestNamespace\\SSViewerTestModel_Controller',
|
||||||
'',
|
'',
|
||||||
'Controller'
|
'Controller'
|
||||||
);
|
);
|
||||||
$self->assertEquals([
|
$self->assertEquals([
|
||||||
'TestNamespace\SSViewerTestModel_Controller',
|
'TestNamespace\\SSViewerTestModel_Controller',
|
||||||
|
[
|
||||||
|
'type' => 'Includes',
|
||||||
|
'TestNamespace\\SSViewerTestModel_Controller',
|
||||||
|
],
|
||||||
|
'TestNamespace\\SSViewerTestModel',
|
||||||
'Controller',
|
'Controller',
|
||||||
|
[
|
||||||
|
'type' => 'Includes',
|
||||||
|
'Controller',
|
||||||
|
],
|
||||||
], $templates);
|
], $templates);
|
||||||
|
|
||||||
// Test to ensure we're stopping at the base class.
|
// Test to ensure we're stopping at the base class.
|
||||||
$templates = SSViewer::get_templates_by_class('TestNamespace\SSViewerTestModel_Controller', '', 'TestNamespace\SSViewerTestModel_Controller');
|
$templates = SSViewer::get_templates_by_class(
|
||||||
$self->assertCount(1, $templates);
|
'TestNamespace\SSViewerTestModel_Controller',
|
||||||
|
'',
|
||||||
|
'TestNamespace\SSViewerTestModel_Controller'
|
||||||
|
);
|
||||||
|
$self->assertEquals([
|
||||||
|
'TestNamespace\\SSViewerTestModel_Controller',
|
||||||
|
[
|
||||||
|
'type' => 'Includes',
|
||||||
|
'TestNamespace\\SSViewerTestModel_Controller',
|
||||||
|
],
|
||||||
|
'TestNamespace\\SSViewerTestModel',
|
||||||
|
], $templates);
|
||||||
|
|
||||||
// Make sure we can filter our templates by suffix.
|
// Make sure we can search templates by suffix.
|
||||||
$templates = SSViewer::get_templates_by_class('TestNamespace\SSViewerTestModel', '_Controller');
|
$templates = SSViewer::get_templates_by_class(
|
||||||
$self->assertCount(1, $templates);
|
'TestNamespace\\SSViewerTestModel',
|
||||||
|
'_Controller',
|
||||||
|
'SilverStripe\\ORM\\DataObject'
|
||||||
|
);
|
||||||
|
$self->assertEquals([
|
||||||
|
'TestNamespace\\SSViewerTestModel_Controller',
|
||||||
|
[
|
||||||
|
'type' => 'Includes',
|
||||||
|
'TestNamespace\\SSViewerTestModel_Controller',
|
||||||
|
],
|
||||||
|
'SilverStripe\\ORM\\DataObject_Controller',
|
||||||
|
[
|
||||||
|
'type' => 'Includes',
|
||||||
|
'SilverStripe\\ORM\\DataObject_Controller',
|
||||||
|
],
|
||||||
|
], $templates);
|
||||||
|
|
||||||
// Let's throw something random in there.
|
// Let's throw something random in there.
|
||||||
$self->setExpectedException('InvalidArgumentException');
|
$self->setExpectedException('InvalidArgumentException');
|
||||||
|
@ -859,51 +859,52 @@ class SSViewer implements Flushable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Traverses the given the given class context looking for templates with the relevant name.
|
* Traverses the given the given class context looking for candidate template names
|
||||||
*
|
* which match each item in the class hierarchy. The resulting list of template candidates
|
||||||
* @param $className string - valid class name
|
* may or may not exist, but you can invoke {@see SSViewer::chooseTemplate} on any list
|
||||||
* @param $suffix string
|
* to determine the best candidate based on the current themes.
|
||||||
* @param $baseClass string
|
|
||||||
*
|
*
|
||||||
|
* @param string|object $classOrObject Valid class name, or object
|
||||||
|
* @param string $suffix
|
||||||
|
* @param string $baseClass Class to halt ancestry search at
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function get_templates_by_class($className, $suffix = '', $baseClass = null) {
|
public static function get_templates_by_class($classOrObject, $suffix = '', $baseClass = null) {
|
||||||
// Figure out the class name from the supplied context.
|
// Figure out the class name from the supplied context.
|
||||||
if(!is_string($className) || !class_exists($className)) {
|
if (!is_object($classOrObject) && !(
|
||||||
|
is_string($classOrObject) && class_exists($classOrObject)
|
||||||
|
)) {
|
||||||
throw new InvalidArgumentException(
|
throw new InvalidArgumentException(
|
||||||
'SSViewer::get_templates_by_class() expects a valid class name as its first parameter.'
|
'SSViewer::get_templates_by_class() expects a valid class name as its first parameter.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$templates = array();
|
$templates = array();
|
||||||
$classes = array_reverse(ClassInfo::ancestry($className));
|
$classes = array_reverse(ClassInfo::ancestry($classOrObject));
|
||||||
foreach($classes as $class) {
|
foreach($classes as $class) {
|
||||||
$template = $class . $suffix;
|
$template = $class . $suffix;
|
||||||
if(SSViewer::hasTemplate($template)) {
|
|
||||||
$templates[] = $template;
|
$templates[] = $template;
|
||||||
} elseif(SSViewer::hasTemplate($template = ['type' => 'Includes', $template])) {
|
$templates[] = ['type' => 'Includes', $template];
|
||||||
$templates[] = $template;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the class is "Page_Controller", look for Page.ss
|
// If the class is "Page_Controller", look for Page.ss
|
||||||
if(stripos($class,'_controller') !== false) {
|
if (stripos($class, '_controller') !== false) {
|
||||||
$template = str_ireplace('_controller','',$class) . $suffix;
|
$templates[] = str_ireplace('_controller', '', $class) . $suffix;
|
||||||
if(SSViewer::hasTemplate($template)) {
|
|
||||||
$templates[] = $template;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if($baseClass && $class == $baseClass) break;
|
if($baseClass && $class == $baseClass) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $templates;
|
return $templates;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string|array $templateList If passed as a string with .ss extension, used as the "main" template.
|
* @param string|array $templates If passed as a string with .ss extension, used as the "main" template.
|
||||||
* If passed as an array, it can be used for template inheritance (first found template "wins").
|
* If passed as an array, it can be used for template inheritance (first found template "wins").
|
||||||
* Usually the array values are PHP class names, which directly correlate to template names.
|
* Usually the array values are PHP class names, which directly correlate to template names.
|
||||||
* <code>
|
* <code>
|
||||||
* array('MySpecificPage', 'MyPage', 'Page')
|
* array('MySpecificPage', 'MyPage', 'Page')
|
||||||
* </code>
|
* </code>
|
||||||
|
* @param TemplateParser $parser
|
||||||
*/
|
*/
|
||||||
public function __construct($templates, TemplateParser $parser = null) {
|
public function __construct($templates, TemplateParser $parser = null) {
|
||||||
if ($parser) {
|
if ($parser) {
|
||||||
@ -929,10 +930,20 @@ class SSViewer implements Flushable {
|
|||||||
|
|
||||||
public function setTemplate($templates) {
|
public function setTemplate($templates) {
|
||||||
$this->templates = $templates;
|
$this->templates = $templates;
|
||||||
$this->chosen = ThemeResourceLoader::instance()->findTemplate($templates, self::get_themes());
|
$this->chosen = $this->chooseTemplate($templates);
|
||||||
$this->subTemplates = [];
|
$this->subTemplates = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the template to use for a given list
|
||||||
|
*
|
||||||
|
* @param array|string $templates
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function chooseTemplate($templates) {
|
||||||
|
return ThemeResourceLoader::instance()->findTemplate($templates, self::get_themes());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the template parser that will be used in template generation
|
* Set the template parser that will be used in template generation
|
||||||
* @param \TemplateParser $parser
|
* @param \TemplateParser $parser
|
||||||
|
@ -155,13 +155,6 @@ class ThemeResourceLoader {
|
|||||||
$templateList = array($template);
|
$templateList = array($template);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have an .ss extension, this is a path, not a template name. We should
|
|
||||||
// pass in templates without extensions in order for template manifest to find
|
|
||||||
// files dynamically.
|
|
||||||
if(count($templateList) == 1 && is_string($templateList[0]) && substr($templateList[0], -3) == '.ss') {
|
|
||||||
return $templateList[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($templateList as $i => $template) {
|
foreach($templateList as $i => $template) {
|
||||||
// Check if passed list of templates in array format
|
// Check if passed list of templates in array format
|
||||||
if (is_array($template)) {
|
if (is_array($template)) {
|
||||||
@ -172,6 +165,13 @@ class ThemeResourceLoader {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have an .ss extension, this is a path, not a template name. We should
|
||||||
|
// pass in templates without extensions in order for template manifest to find
|
||||||
|
// files dynamically.
|
||||||
|
if(substr($template, -3) == '.ss' && file_exists($template)) {
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
|
||||||
// Check string template identifier
|
// Check string template identifier
|
||||||
$template = str_replace('\\', '/', $template);
|
$template = str_replace('\\', '/', $template);
|
||||||
$parts = explode('/', $template);
|
$parts = explode('/', $template);
|
||||||
|
Loading…
Reference in New Issue
Block a user