Skip to content

Commit

Permalink
API Refactor template layer into its own module
Browse files Browse the repository at this point in the history
Includes the following large-scale changes:
- Impoved barrier between model and view layers
- Improved casting of scalar to relevant DBField types
- Improved capabilities for rendering arbitrary data in templates
  • Loading branch information
GuySartorelli committed Oct 1, 2024
1 parent 27708c7 commit d4e82cd
Show file tree
Hide file tree
Showing 42 changed files with 1,096 additions and 1,008 deletions.
16 changes: 8 additions & 8 deletions src/Control/RSS/RSSFeed_Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class RSSFeed_Entry extends ModelData
*/
public function __construct($entry, $titleField, $descriptionField, $authorField)
{
$this->failover = $entry;
$this->setFailover($entry);
$this->titleField = $titleField;
$this->descriptionField = $descriptionField;
$this->authorField = $authorField;
Expand All @@ -58,19 +58,19 @@ public function __construct($entry, $titleField, $descriptionField, $authorField
/**
* Get the description of this entry
*
* @return DBField Returns the description of the entry.
* @return DBField|null Returns the description of the entry.
*/
public function Title()
public function getTitle()
{
return $this->rssField($this->titleField);
}

/**
* Get the description of this entry
*
* @return DBField Returns the description of the entry.
* @return DBField|null Returns the description of the entry.
*/
public function Description()
public function getDescription()
{
$description = $this->rssField($this->descriptionField);

Expand All @@ -85,9 +85,9 @@ public function Description()
/**
* Get the author of this entry
*
* @return DBField Returns the author of the entry.
* @return DBField|null Returns the author of the entry.
*/
public function Author()
public function getAuthor()
{
return $this->rssField($this->authorField);
}
Expand All @@ -96,7 +96,7 @@ public function Author()
* Return the safely casted field
*
* @param string $fieldName Name of field
* @return DBField
* @return DBField|null
*/
public function rssField($fieldName)
{
Expand Down
45 changes: 34 additions & 11 deletions src/Core/CustomMethods.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ trait CustomMethods
*/
protected static $built_in_methods = [];

protected array $extraMethodsForInstance = [];

/**
* Attempts to locate and call a method dynamically added to a class at runtime if a default cannot be located
*
Expand Down Expand Up @@ -175,7 +177,7 @@ protected function getExtraMethodConfig($method)
$this->defineMethods();
}

return self::class::$extra_methods[$lowerClass][strtolower($method)] ?? null;
return $this->extraMethodsForInstance[strtolower($method)] ?? self::class::$extra_methods[$lowerClass][strtolower($method)] ?? null;
}

/**
Expand All @@ -190,6 +192,9 @@ public function allMethodNames($custom = false)

// Query extra methods
$lowerClass = strtolower(static::class);
if ($custom && !empty($this->extraMethodsForInstance)) {
$methods = array_merge($this->extraMethodsForInstance, $methods);
}
if ($custom && isset(self::class::$extra_methods[$lowerClass])) {
$methods = array_merge(self::class::$extra_methods[$lowerClass], $methods);
}
Expand Down Expand Up @@ -256,7 +261,7 @@ protected function findMethodsFrom($object)
* @param string|int $index an index to use if the property is an array
* @throws InvalidArgumentException
*/
protected function addMethodsFrom($property, $index = null)
protected function addMethodsFrom($property, $index = null, bool $static = true)
{
$class = static::class;
$object = ($index !== null) ? $this->{$property}[$index] : $this->$property;
Expand All @@ -280,10 +285,18 @@ protected function addMethodsFrom($property, $index = null)

// Merge with extra_methods
$lowerClass = strtolower($class);
if (isset(self::class::$extra_methods[$lowerClass])) {
self::class::$extra_methods[$lowerClass] = array_merge(self::class::$extra_methods[$lowerClass], $newMethods);
if ($static) {
if (isset(self::class::$extra_methods[$lowerClass])) {
self::class::$extra_methods[$lowerClass] = array_merge(self::class::$extra_methods[$lowerClass], $newMethods);
} else {
self::class::$extra_methods[$lowerClass] = $newMethods;
}
} else {
self::class::$extra_methods[$lowerClass] = $newMethods;
if (!empty($this->extraMethodsForInstance)) {
$this->extraMethodsForInstance = array_merge($this->extraMethodsForInstance, $newMethods);
} else {
$this->extraMethodsForInstance = $newMethods;
}
}
}

Expand All @@ -293,7 +306,7 @@ protected function addMethodsFrom($property, $index = null)
* @param string $property the property name
* @param string|int $index an index to use if the property is an array
*/
protected function removeMethodsFrom($property, $index = null)
protected function removeMethodsFrom($property, $index = null, bool $static = true)
{
$extension = ($index !== null) ? $this->{$property}[$index] : $this->$property;
$class = static::class;
Expand All @@ -310,12 +323,22 @@ protected function removeMethodsFrom($property, $index = null)
}
$methods = $this->findMethodsFrom($extension);

// Unset by key
self::class::$extra_methods[$lowerClass] = array_diff_key(self::class::$extra_methods[$lowerClass], $methods);
if ($static) {
// Unset by key
self::class::$extra_methods[$lowerClass] = array_diff_key(self::class::$extra_methods[$lowerClass], $methods);

// Clear empty list
if (empty(self::class::$extra_methods[$lowerClass])) {
unset(self::class::$extra_methods[$lowerClass]);
// Clear empty list
if (empty(self::class::$extra_methods[$lowerClass])) {
unset(self::class::$extra_methods[$lowerClass]);
}
} else {
// Unset by key
$this->extraMethodsForInstance = array_diff_key($this->extraMethodsForInstance, $methods);

// Clear empty list
if (empty($this->extraMethodsForInstance)) {
unset($this->extraMethodsForInstance);
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/Dev/Backtrace.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ public static function full_func_name($item, $showArgs = false, $argCharLimit =
if ($showArgs && isset($item['args'])) {
$args = [];
foreach ($item['args'] as $arg) {
if (!is_object($arg) || method_exists($arg, '__toString')) {
if (is_object($arg)) {
$args[] = get_class($arg);
} else {
$sarg = is_array($arg) ? 'Array' : strval($arg);
$args[] = (strlen($sarg ?? '') > $argCharLimit) ? substr($sarg, 0, $argCharLimit) . '...' : $sarg;
} else {
$args[] = get_class($arg);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Forms/DropdownField.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
* DropdownField::create(
* 'Country',
* 'Country',
* singleton(MyObject::class)->dbObject('Country')->enumValues()
* singleton(MyObject::class)->dbObject('Country')?->enumValues()
* );
* </code>
*
Expand Down
2 changes: 1 addition & 1 deletion src/Forms/FieldGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public function getMessage()
/** @var FormField $subfield */
$messages = [];
foreach ($dataFields as $subfield) {
$message = $subfield->obj('Message')->forTemplate();
$message = $subfield->obj('Message')?->forTemplate();
if ($message) {
$messages[] = rtrim($message ?? '', ".");
}
Expand Down
15 changes: 9 additions & 6 deletions src/Forms/FormField.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use SilverStripe\View\AttributesHTML;
use SilverStripe\View\SSViewer;
use SilverStripe\Model\ModelData;
use SilverStripe\ORM\DataObject;

/**
* Represents a field in a form.
Expand Down Expand Up @@ -458,7 +459,7 @@ public function Value()
*
* By default, makes use of $this->dataValue()
*
* @param ModelData|DataObjectInterface $record Record to save data into
* @param DataObjectInterface $record Record to save data into
*/
public function saveInto(DataObjectInterface $record)
{
Expand All @@ -469,7 +470,9 @@ public function saveInto(DataObjectInterface $record)
if (($pos = strrpos($this->name ?? '', '.')) !== false) {
$relation = substr($this->name ?? '', 0, $pos);
$fieldName = substr($this->name ?? '', $pos + 1);
$component = $record->relObject($relation);
if ($record instanceof DataObject) {
$component = $record->relObject($relation);
}
}

if ($fieldName && $component) {
Expand Down Expand Up @@ -1469,12 +1472,12 @@ public function getSchemaDataDefaults()
'schemaType' => $this->getSchemaDataType(),
'component' => $this->getSchemaComponent(),
'holderId' => $this->HolderID(),
'title' => $this->obj('Title')->getSchemaValue(),
'title' => $this->obj('Title')?->getSchemaValue(),
'source' => null,
'extraClass' => $this->extraClass(),
'description' => $this->obj('Description')->getSchemaValue(),
'rightTitle' => $this->obj('RightTitle')->getSchemaValue(),
'leftTitle' => $this->obj('LeftTitle')->getSchemaValue(),
'description' => $this->obj('Description')?->getSchemaValue(),
'rightTitle' => $this->obj('RightTitle')?->getSchemaValue(),
'leftTitle' => $this->obj('LeftTitle')?->getSchemaValue(),
'readOnly' => $this->isReadonly(),
'disabled' => $this->isDisabled(),
'customValidationMessage' => $this->getCustomValidationMessage(),
Expand Down
4 changes: 2 additions & 2 deletions src/Forms/FormScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public function getFieldList()
$fieldObject = $this
->obj
->dbObject($fieldName)
->scaffoldFormField(null, $this->getParamsArray());
?->scaffoldFormField(null, $this->getParamsArray());
}
// Allow fields to opt-out of scaffolding
if (!$fieldObject) {
Expand Down Expand Up @@ -145,7 +145,7 @@ public function getFieldList()
$fieldClass = $this->fieldClasses[$fieldName];
$hasOneField = new $fieldClass($fieldName);
} else {
$hasOneField = $this->obj->dbObject($fieldName)->scaffoldFormField(null, $this->getParamsArray());
$hasOneField = $this->obj->dbObject($fieldName)?->scaffoldFormField(null, $this->getParamsArray());
}
if (empty($hasOneField)) {
continue; // Allow fields to opt out of scaffolding
Expand Down
21 changes: 15 additions & 6 deletions src/Forms/HTMLEditor/HTMLEditorField.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
use SilverStripe\Assets\Shortcodes\ImageShortcodeProvider;
use SilverStripe\Forms\FormField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use Exception;
use SilverStripe\Model\ModelData;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\View\CastingService;
use SilverStripe\View\Parsers\HTMLValue;

/**
Expand Down Expand Up @@ -123,13 +125,9 @@ public function getAttributes()
);
}

/**
* @param DataObject|DataObjectInterface $record
* @throws Exception
*/
public function saveInto(DataObjectInterface $record)
{
if ($record->hasField($this->name) && $record->escapeTypeForField($this->name) != 'xml') {
if (!$this->usesXmlFriendlyField($record)) {
throw new Exception(
'HTMLEditorField->saveInto(): This field should save into a HTMLText or HTMLVarchar field.'
);
Expand Down Expand Up @@ -225,4 +223,15 @@ private function setEditorHeight(HTMLEditorConfig $config): HTMLEditorConfig

return $config;
}

private function usesXmlFriendlyField(DataObjectInterface $record): bool
{
if ($record instanceof ModelData && !$record->hasField($this->getName())) {
return true;
}

$castingService = CastingService::singleton();
$castValue = $castingService->cast($this->Value(), $record, $this->getName());
return $castValue instanceof DBField && $castValue::config()->get('escape_type') === 'xml';
}
}
8 changes: 4 additions & 4 deletions src/Forms/TreeDropdownField.php
Original file line number Diff line number Diff line change
Expand Up @@ -870,14 +870,14 @@ public function getSchemaStateDefaults()
$ancestors = $record->getAncestors(true)->reverse();

foreach ($ancestors as $parent) {
$title = $parent->obj($this->getTitleField())->getValue();
$title = $parent->obj($this->getTitleField())?->getValue();
$titlePath .= $title . '/';
}
}
$data['data']['valueObject'] = [
'id' => $record->obj($this->getKeyField())->getValue(),
'title' => $record->obj($this->getTitleField())->getValue(),
'treetitle' => $record->obj($this->getLabelField())->getSchemaValue(),
'id' => $record->obj($this->getKeyField())?->getValue(),
'title' => $record->obj($this->getTitleField())?->getValue(),
'treetitle' => $record->obj($this->getLabelField())?->getSchemaValue(),
'titlePath' => $titlePath,
];
}
Expand Down
8 changes: 4 additions & 4 deletions src/Forms/TreeMultiselectField.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ public function getSchemaStateDefaults()
foreach ($items as $item) {
if ($item instanceof DataObject) {
$values[] = [
'id' => $item->obj($this->getKeyField())->getValue(),
'title' => $item->obj($this->getTitleField())->getValue(),
'id' => $item->obj($this->getKeyField())?->getValue(),
'title' => $item->obj($this->getTitleField())?->getValue(),
'parentid' => $item->ParentID,
'treetitle' => $item->obj($this->getLabelField())->getSchemaValue(),
'treetitle' => $item->obj($this->getLabelField())?->getSchemaValue(),
];
} else {
$values[] = $item;
Expand Down Expand Up @@ -212,7 +212,7 @@ public function Field($properties = [])
foreach ($items as $item) {
$idArray[] = $item->ID;
$titleArray[] = ($item instanceof ModelData)
? $item->obj($this->getLabelField())->forTemplate()
? $item->obj($this->getLabelField())?->forTemplate()
: Convert::raw2xml($item->{$this->getLabelField()});
}

Expand Down
4 changes: 3 additions & 1 deletion src/Model/List/ListDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ public function getList(): SS_List&Sortable&Filterable&Limitable
public function setList(SS_List&Sortable&Filterable&Limitable $list): ListDecorator
{
$this->list = $list;
$this->failover = $this->list;
if ($list instanceof ModelData) {
$this->setFailover($list);
}
return $this;
}

Expand Down
Loading

0 comments on commit d4e82cd

Please sign in to comment.