Skip to content

Commit

Permalink
progress on classes with related records
Browse files Browse the repository at this point in the history
  • Loading branch information
jsirish committed Feb 21, 2025
1 parent 98a26e5 commit 6bf2d80
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 130 deletions.
185 changes: 63 additions & 122 deletions src/Extension/BaseElementDataExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ public function onBeforeWrite(): void
{
parent::onBeforeWrite();

$logger = Injector::inst()->get(LoggerInterface::class);
$logger->info("TEST: SilverStripe logging system is working.");

try {
$this->populateElementData();
} catch (\Exception $e) {
Expand Down Expand Up @@ -181,7 +178,10 @@ protected function createRelatedRecords(string $ownerClass, array $populateData,
continue;
}

if ($this->owner->$relationName()->count() > 0) {
$expectedCount = count($populateData[$relationName]);
$existingCount = $this->owner->$relationName()->count();

if ($existingCount >= $expectedCount) {
continue;
}

Expand All @@ -198,6 +198,57 @@ protected function createRelatedRecords(string $ownerClass, array $populateData,
$this->owner->$relationName()->add($relatedObject);
$this->logAction("Created has_many relation {$relatedClassName} for {$relationName}", 'info');

// Handle Image for GalleryImage
if ($relatedObject->ClassName === 'Dynamic\Elements\Gallery\Model\GalleryImage' && isset($itemData['Image']['Filename'])) {
$this->logAction("Processing GalleryImage: Checking image assignment...", 'debug');

$image = $this->createImageFromFile($itemData['Image']['Filename']);
if ($image) {
$relatedObject->ImageID = $image->ID;
$relatedObject->write();
$this->logAction("Assigned Image ID {$image->ID} to GalleryImage (Image ID: {$relatedObject->ID})", 'info');
} else {
$this->logAction("Image creation failed, no Image assigned to GalleryImage", 'error');
}
}

// Handle SiteTreeLink for LinkListObject
if ($relatedObject->ClassName === 'Dynamic\Elements\Links\Model\LinkListObject') {
$this->logAction("LinkListObject detected. Checking for Link data...", 'debug');
$this->logAction("Link data: " . json_encode($itemData['Link']), 'debug');

if (isset($itemData['Link'])) {
$this->logAction("Processing LinkListObject: Checking SiteTreeLink assignment...", 'debug');

$linkData = $itemData['Link'];
if (!isset($linkData['ClassName'])) {
$this->logAction("Link data does not contain ClassName. Skipping Link creation.", 'warning');
continue;
}

$linkClassName = $linkData['ClassName'];
if (!class_exists($linkClassName)) {
$this->logAction("Link class {$linkClassName} does not exist. Skipping Link creation.", 'error');
continue;
}

$linkObject = $linkClassName::create();
foreach ($linkData as $linkField => $linkValue) {
if ($linkField !== 'ClassName' && $linkObject->hasField($linkField)) {
$linkObject->$linkField = $linkValue;
}
}
$linkObject->write();
$this->logAction("Created SiteTreeLink with ID: {$linkObject->ID}", 'info');

$relatedObject->LinkID = $linkObject->ID; // Ensure we are setting the ID
$relatedObject->write();
$this->logAction("Assigned LinkID: {$linkObject->ID} to LinkListObject with ID: {$relatedObject->ID}", 'info');
} else {
$this->logAction("No Link data found for LinkListObject.", 'warning');
}
}

// Recurse for nested relationships
$this->createRelatedRecords($relatedClassName, $itemData, $depth + 1);
}
Expand All @@ -209,7 +260,10 @@ protected function createRelatedRecords(string $ownerClass, array $populateData,
continue;
}

if ($this->owner->$relationName()->count() > 0) {
$expectedCount = count($populateData[$relationName]);
$existingCount = $this->owner->$relationName()->count();

if ($existingCount >= $expectedCount) {
continue;
}

Expand All @@ -226,17 +280,17 @@ protected function createRelatedRecords(string $ownerClass, array $populateData,
$this->owner->$relationName()->add($relatedObject);
$this->logAction("Created many_many relation {$relatedClassName} for {$relationName}", 'info');

// Handle Image for ImageSlide
// Handle Image for ImageSlide
if ($relatedObject->ClassName === 'Dynamic\Carousel\Model\ImageSlide' && isset($itemData['Image']['Filename'])) {
$this->logAction("🔍 Processing ImageSlide: Checking image assignment...", 'debug');
$this->logAction("Processing ImageSlide: Checking image assignment...", 'debug');

$image = $this->createImageFromFile($itemData['Image']['Filename']);
if ($image) {
$relatedObject->ImageID = $image->ID;
$relatedObject->write();
$this->logAction("Assigned Image ID {$image->ID} to ImageSlide (Slide ID: {$relatedObject->ID})", 'info');
$this->logAction("Assigned Image ID {$image->ID} to ImageSlide (Slide ID: {$relatedObject->ID})", 'info');
} else {
$this->logAction("⚠️ Image creation failed, no Image assigned to ImageSlide", 'error');
$this->logAction("Image creation failed, no Image assigned to ImageSlide", 'error');
}
}

Expand Down Expand Up @@ -339,119 +393,6 @@ protected function getOwnerPageSafe(): mixed
return $this->getOwner()->getPage();
}




/**
* Populates default values for new Elemental blocks based on YAML configuration.
*
* @return void
*/
protected function populateDefaultValues(): void
{
$manager = $this->getOwnerPage();
if (!$manager) {
return;
}

if ($manager instanceof Template) {
$populate = Config::inst()->get(Template::class, 'populate');
if (!$populate) {
return;
}

$ownerClass = $this->owner->ClassName;

if (isset($populate[$ownerClass])) {
// Populate standard fields
foreach ($populate[$ownerClass] as $field => $value) {
if ($this->owner->hasField($field)) {
$this->owner->$field = $value;
}
}

// Handle has_one relations
foreach ($this->owner->hasOne() as $relationName => $relatedClass) {
if (!isset($populate[$ownerClass][$relationName])) {
continue;
}

$relatedData = $populate[$ownerClass][$relationName];

// Check if ClassName is specified, otherwise use the default relation class
$relatedClassName = $relatedData['ClassName'] ?? $relatedClass;

// Ensure the relation does not already exist
if ($this->owner->getComponent($relationName)->exists()) {
continue;
}

// Create related object and assign it
$relatedObject = $relatedClassName::create();
foreach ($relatedData as $field => $value) {
if ($field !== 'ClassName' && $relatedObject->hasField($field)) {
$relatedObject->$field = $value;
}
}
$relatedObject->write();
$this->owner->setField("{$relationName}ID", $relatedObject->ID);
}

// Handle has_many relations
foreach ($this->owner->hasMany() as $relationName => $relatedClass) {
if (!isset($populate[$ownerClass][$relationName]) || !$this->owner->hasMethod($relationName)) {
continue;
}

$existingRecords = $this->owner->$relationName();
if ($existingRecords->count() > 0) {
continue;
}

foreach ($populate[$ownerClass][$relationName] as $itemData) {
// Check if ClassName is specified, otherwise use the default relation class
$relatedClassName = $itemData['ClassName'] ?? $relatedClass;

$relatedObject = $relatedClassName::create();
foreach ($itemData as $field => $value) {
if ($field !== 'ClassName' && $relatedObject->hasField($field)) {
$relatedObject->$field = $value;
}
}
$relatedObject->write();
$this->owner->$relationName()->add($relatedObject);
}
}

// Handle many_many relations
foreach ($this->owner->manyMany() as $relationName => $relatedClass) {
if (!isset($populate[$ownerClass][$relationName]) || !$this->owner->hasMethod($relationName)) {
continue;
}

$existingRecords = $this->owner->$relationName();
if ($existingRecords->count() > 0) {
continue;
}

foreach ($populate[$ownerClass][$relationName] as $itemData) {
// Check if ClassName is specified, otherwise use the default relation class
$relatedClassName = $itemData['ClassName'] ?? $relatedClass;

$relatedObject = $relatedClassName::create();
foreach ($itemData as $field => $value) {
if ($field !== 'ClassName' && $relatedObject->hasField($field)) {
$relatedObject->$field = $value;
}
}
$relatedObject->write();
$this->owner->$relationName()->add($relatedObject);
}
}
}
}
}

/**
* @return mixed
*/
Expand Down
36 changes: 28 additions & 8 deletions src/Models/Template.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@

namespace Dynamic\ElememtalTemplates\Models;

use DNADesign\Elemental\Extensions\ElementalAreasExtension;
use DNADesign\Elemental\Models\ElementalArea;
use LeKoala\CmsActions\CustomAction;
use SilverStripe\Assets\Image;
use SilverStripe\Control\Controller;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Forms\DropdownField;
use SilverStripe\ORM\DataObject;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\TreeDropdownField;
use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\Security\PermissionProvider;
use SilverStripe\Security\Security;
use LeKoala\CmsActions\CustomAction;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Security\Permission;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Forms\TreeDropdownField;
use DNADesign\Elemental\Models\ElementalArea;
use SilverStripe\Security\PermissionProvider;
use DNADesign\Elemental\Extensions\ElementalAreasExtension;

/**
* Creates a Template of elements that can be used to set up a page
Expand Down Expand Up @@ -304,6 +305,25 @@ public function canView($member = null): bool
return true;
}

/**
* Determine if the current user can archive this template.
*
* @param null $member
* @return bool
*/
public function canArchive($member = null)
{
if ($member === null) {
$member = $this->getUser();
}

if ($member->can('ELEMENTAL_TEMPLATE_DELETE')) {
return true;
}

return parent::canDelete($member);
}

/**
* @return Member|null
*/
Expand Down
108 changes: 108 additions & 0 deletions tests/Extension/BaseElementDataExtensionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace Dynamic\ElememtalTemplates\Tests;

use SilverStripe\Dev\SapphireTest;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataObject;
use Dynamic\ElememtalTemplates\Extension\BaseElementDataExtension;
use Dynamic\ElememtalTemplates\Models\Template;
use Dynamic\Elements\Accordion\Elements\ElementAccordion; // Add this line
use Psr\Log\LoggerInterface;

class BaseElementDataExtensionTest extends SapphireTest
{
protected function setUp(): void
{
parent::setUp();

// Mock the logger
$logger = $this->createMock(LoggerInterface::class);
$logger->expects($this->any())
->method('log')
->will($this->returnCallback(function ($level, $message) {
echo "[$level] $message\n";
}));
Injector::inst()->registerService($logger, LoggerInterface::class);

// Load the skeleton-populate.yml configuration from Template class
$populateConfig = Config::inst()->get(Template::class, 'populate');
Config::modify()->set(Template::class, 'populate', $populateConfig);
}

public function testPopulateElementData()
{
$populateConfig = Config::inst()->get(Template::class, 'populate');

foreach ($populateConfig as $className => $data) {
if (!class_exists($className)) {
$this->markTestSkipped("Class $className does not exist.");
continue;
}

// Create a Template instance and associate the element with it
$template = Template::create();
$template->write();

$element = $className::create();
$element->ParentID = $template->ID;
$element->write();

$extension = new TestableBaseElementDataExtension();
$extension->setOwner($element);

$extension->populateElementData();

// Reload the element to ensure the fields are saved
$element = DataObject::get_by_id($className, $element->ID);

foreach ($data as $field => $value) {
if (is_array($value)) {
continue; // Skip related records for this test
}
$this->assertEquals($value, $element->$field, "Failed asserting that field '$field' of '$className' is populated correctly.");
}
}
}

public function testCreateRelatedRecords()
{
$element = new ElementAccordion();
$element->write();

$populateData = [
'Panels' => [
[
'ClassName' => AccordionPanel::class,
'Title' => 'Panel 1',
'Content' => 'Content for panel 1'
],
[
'ClassName' => AccordionPanel::class,
'Title' => 'Panel 2',
'Content' => 'Content for panel 2'
]
]
];

$extension = new TestableBaseElementDataExtension();
$extension->setOwner($element);
$extension->createRelatedRecords($element, $populateData);

$this->assertGreaterThan(0, $element->Panels()->count(), "Failed asserting that relation 'Panels' of 'Dynamic\Elements\Accordion\Elements\ElementAccordion' is populated correctly.");
}
}

class TestableBaseElementDataExtension extends BaseElementDataExtension
{
public function populateElementData(): void
{
parent::populateElementData();
}

public function createRelatedRecords(DataObject $owner, array $populateData, int $depth = 0): void
{
parent::createRelatedRecords($owner, $populateData, $depth);
}
}

0 comments on commit 6bf2d80

Please sign in to comment.