Skip to content

Commit

Permalink
Implement feature to allow for banner on specific page
Browse files Browse the repository at this point in the history
  • Loading branch information
satrun77 committed Oct 16, 2023
1 parent 9efc4ab commit 2f6dc0d
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 2 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,19 @@ Examples on the SilverStripe default theme:

![Alert styling](docs/_img/alert.png)

## Features

### Display banners only on the selected pages
`NZTA\SiteBanner\Extensions\PageSelectionExtension`

Add the followig to your YML file to enable the fature

```yml
NZTA\SiteBanner\Extensions\PageSelectionExtension:
enabled: true
```
Then you are going to have a tab with gridfield to select the pages a banner must be visible on that page only.
## Permissions
By default, every author with access to the "Settings" section (`EDIT_SITECONFIG` permission code)
Expand Down
10 changes: 10 additions & 0 deletions _config/_config.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
---
Name: sitebanner
---
NZTA\SiteBanner\Models\SiteBanner:
extensions:
- NZTA\SiteBanner\Extensions\PageSelectionExtension

NZTA\SiteBanner\Extensions\PageSelectionExtension:
enabled: false

# SilverStripe\SiteConfig\SiteConfig:
# extensions:
# - NZTA\SiteBanner\Extensions\SiteConfigExtension
Expand Down
11 changes: 11 additions & 0 deletions phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@
<exclude name="SlevomatCodingStandard.Arrays.AlphabeticallySortedByKeys.IncorrectKeyOrder"/>
</rule>

<rule ref="SlevomatCodingStandard.Functions.FunctionLength">
<properties>
<property name="maxLinesLength" type="int" value="30"/>
</properties>
</rule>
<rule ref="SlevomatCodingStandard.Files.FunctionLength">
<properties>
<property name="maxLinesLength" type="int" value="30"/>
</properties>
</rule>

<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">
<properties>
<property name="searchAnnotations" type="bool" value="true"/>
Expand Down
92 changes: 92 additions & 0 deletions src/Extensions/PageSelectionExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

namespace NZTA\SiteBanner\Extensions;

use NZTA\SiteBanner\Models\SiteBanner;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;

/**
* Extend site banner functionality to allow for limiting banner to selected pages
*
* @method SiteBanner getOwner()
*/
class PageSelectionExtension extends DataExtension
{

use Configurable;

/**
* Whether or not this extension is enabled
*
* @config
*/
private static bool $enabled = false;

private static array $many_many = [
'Pages' => SiteTree::class,
];

private static array $cascade_duplicates = [
'Pages',
];

public function updateCMSFields(FieldList $fields): void
{
$fields->removeByName('Pages');

if (!$this->getOwner()->isInDB() || !self::config()->get('enabled')) {
return;
}

$pagesField = GridField::create('Pages', $this->getOwner()->fieldLabel('Pages'));
$pagesField->setDescription(
'Select pages that you would like the banner to be visible in. ' .
'If none selected, then visible in all pages.',
);
$fields->addFieldToTab('Root.Pages', $pagesField);
}

/**
* Modify the query that returns the banner to be visible to the public user
*/
public function onFrontendQuery(DataList $query, ?int $pageId = null): DataList
{
// Skip implementation if no page is provided or extension disabled
if (!$pageId || !self::config()->get('enabled')) {
return $query;
}

$rightTable = DataObject::getSchema()->tableName(SiteBanner::class);
$pagesRelation = DataObject::getSchema()->manyManyComponent(SiteBanner::class, 'Pages');
$leftTable = $pagesRelation['join'];

// Search for banners that must be visible in current page only
$query1 = $query->innerJoin(
$leftTable,
sprintf('%s.%s = "%s"."ID"', $leftTable, $pagesRelation['parentField'], $rightTable),
$leftTable,
)->where([
'"' . $pagesRelation['join'] . '"."SiteTreeID" = ?' => $pageId,
]);

if ($query1->count()) {
return $query1;
}

// If no banner selected for current page, then return banners not defined to specific page
return $query->leftJoin(
$leftTable,
sprintf('%s.%s = "%s"."ID"', $leftTable, $pagesRelation['parentField'], $rightTable),
$leftTable,
)->where([
['"' . $pagesRelation['join'] . '"."SiteTreeID" IS NULL',],
]);
}

}
9 changes: 7 additions & 2 deletions src/Templates/TemplateProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ public static function get_template_global_variables(): array
/**
* Get all displayable site banners
*/
public static function getSiteBanners(): ArrayList
public static function getSiteBanners(?int $pageId = null): ArrayList
{
Requirements::css('nzta/silverstripe-sitebanner: client/css/site-banner.css');
Requirements::javascript('nzta/silverstripe-sitebanner: client/javascript/site-banner.js');

return SiteBanner::get()->filterByCallback(static function ($banner) {
$query = SiteBanner::get();

// Apply extension filters if any
$query = singleton(SiteBanner::class)->onFrontendQuery($query, $pageId);

return $query->filterByCallback(static function ($banner) {
return $banner->isActive();
});
}
Expand Down
93 changes: 93 additions & 0 deletions tests/PageSelectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

namespace NZTA\SiteBanner\Tests;

use NZTA\SiteBanner\Extensions\PageSelectionExtension;
use NZTA\SiteBanner\Models\SiteBanner;
use NZTA\SiteBanner\Templates\TemplateProvider;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\Queries\SQLInsert;

/**
* @phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
* @phpcs:disable SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingAnyTypeHint
* @phpcs:disable SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingAnyTypeHint
* @phpcs:disable SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingAnyTypeHint
*/
class PageSelectionTest extends SapphireTest
{
protected static $fixture_file = 'PageSelectionTest.yml';

public function testVisibleInHomepageOnly(): void
{
PageSelectionExtension::config()->set('enabled', true);

// All banners - we have 3
$banners = TemplateProvider::getSiteBanners();

// Pick a banner
$first = $banners->first();

// Fake page ID
$pageId = 3;

// Add the picked banner to be visible in $pageId
$pagesRelation = DataObject::getSchema()->manyManyComponent(SiteBanner::class, 'Pages');
SQLInsert::create($pagesRelation['join'], [
'SiteBannerID' => $first->ID,
'SiteTreeID' => $pageId,
])->execute();

// Assert on a page we see 2 banners as one visible in $pageId only
self::assertEquals(2, TemplateProvider::getSiteBanners(4)->count());

// Assert one banner visible in $pageId
self::assertEquals(1, TemplateProvider::getSiteBanners($pageId)->count());

// Assert banners other than the picked one are visible in other pages
self::assertEquals(
$banners->exclude('ID', $first->ID)->column('ID'),
TemplateProvider::getSiteBanners(4)->column('ID'),
);

// Move banners to $pageId
foreach ($banners as $banner) {
SQLInsert::create($pagesRelation['join'], [
'SiteBannerID' => $banner->ID,
'SiteTreeID' => $pageId,
])->execute();
}

// No banner to display
self::assertEquals(0, TemplateProvider::getSiteBanners(4)->count());

// All banners visible in $pageId
self::assertEquals($banners->count(), TemplateProvider::getSiteBanners($pageId)->count());

// Disable extension
PageSelectionExtension::config()->set('enabled', false);

// banners visible in all pages
self::assertEquals(3, TemplateProvider::getSiteBanners(4)->count());
}

public function testPagesField(): void
{
PageSelectionExtension::config()->set('enabled', false);

// Assert new records does not show grid field for pages
$siteBanner1 = SiteBanner::create();
$this->assertNull($siteBanner1->getCMSFields()->dataFieldByName('Pages'));

// Assert existing records does not show grid field for pages if extension not added
$siteBanner2 = $this->objFromFixture(SiteBanner::class, 'banner1');
$this->assertTrue($siteBanner2->exists());
$this->assertNull($siteBanner2->getCMSFields()->dataFieldByName('Pages'));

// Assert existing records does show grid field for pages if extension added
PageSelectionExtension::config()->set('enabled', true);
$this->assertInstanceOf(GridField::class, $siteBanner2->getCMSFields()->dataFieldByName('Pages'));
}
}
17 changes: 17 additions & 0 deletions tests/PageSelectionTest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
NZTA\SiteBanner\Models\SiteBanner:
banner1:
Sort: 1
Type: alert
Content: |
<p>Bold message text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean sodales posuere sed sit amet nibh.</p>
banner2:
Sort: 2
Type: info
Dismiss: 1
Content: |
<p><strong>Bold message text.</strong> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean sodales posuere sed sit <a href="/">amet nibh</a>.</p>
banner3:
Sort: 3
Type: warning
Content: |
<p><strong>Bold message text.</strong> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean sodales posuere sed sit <a href="/">amet nibh</a>.</p>

0 comments on commit 2f6dc0d

Please sign in to comment.