Skip to content

Instantly share code, notes, and snippets.

@maxime-rainville
Last active October 22, 2020 21:56
Show Gist options
  • Save maxime-rainville/26785a996331af41298c71eaee7e52b4 to your computer and use it in GitHub Desktop.
Save maxime-rainville/26785a996331af41298c71eaee7e52b4 to your computer and use it in GitHub Desktop.
Creating lots of relations to file
<?php
use DNADesign\Elemental\Models\ElementContent;
use SilverStripe\Assets\Image;
use SilverStripe\Dev\BuildTask;
use SilverStripe\ElementalBannerBlock\Block\BannerBlock;
use SilverStripe\ORM\DB;
class CreateRelated extends BuildTask
{
private static $pageTypes = [ ];
public function run($request)
{
$pageTypes = self::config()->get('pageTypes');
$fileID = 1;
/** @var Image $file */
$file = Image::get()->byID($fileID);
$this->deleteExisting($pageTypes);
$this->hasOne($pageTypes, $fileID);
$this->hasMany($pageTypes, $file);
$this->manyMany($pageTypes, $file);
$this->manyManyOrphan($pageTypes, $file);
$this->content($pageTypes, $file);
$this->blocks($pageTypes, $file);
$this->hasOnePoly($pageTypes, $file);
$this->manyManyThrough($pageTypes, $file);
$this->allInOne($pageTypes, $file);
$file->Self = $file;
$file->write();
}
public function findOrCreate(string $title)
{
$page = Page::get()->filter('Title', $title)->first();
if (!$page) {
$page = Page::create();
$page->Title = $title;
$page->write();
}
return $page;
}
public function deleteExisting(array $pageTypes)
{
$pages = Page::get()->filter('Classname', $pageTypes);
foreach ($pages as $page) {
$page->delete();
}
foreach ($pageTypes as $type) {
DB::query("TRUNCATE \"{$type}_MyManyFiles\";");
DB::query("TRUNCATE \"{$type}_MyManyImages\";");
}
}
public function hasOne($pageTypes, $fileID)
{
$parent = $this->findOrCreate('has ones');
foreach ($pageTypes as $type) {
/** @var Page $page */
$page = new $type();
$page->Title = $type . ' has one';
$page->MyImageID = $fileID;
$page->MyFileID = $fileID;
$page->ParentID = $parent->ID;
$page->write();
}
}
public function hasMany($pageTypes, Image $file)
{
$parent = $this->findOrCreate('has manys');
foreach ($pageTypes as $type) {
$page = new $type();
$page->Title = $type . ' has many';
$page->ParentID = $parent->ID;
$page->write();
$file->{$type . 'ID'} = $page->ID;
$file->{$type . 'ImageID'} = $page->ID;
}
}
public function manyMany($pageTypes, Image $file)
{
$parent = $this->findOrCreate('many manys');
foreach ($pageTypes as $type) {
$page = new $type();
$page->Title = $type . ' many many';
$page->ParentID = $parent->ID;
$page->write();
$page->MyManyImages()->add($file);
$page->MyManyFiles()->add($file);
}
}
public function manyManyOrphan($pageTypes, Image $file)
{
foreach ($pageTypes as $type) {
$page = new $type();
$page->Title = $type . ' many many orphan';
$page->write();
$page->MyManyImages()->add($file);
$page->MyManyFiles()->add($file);
$page->delete();
}
}
public function content($pageTypes, Image $file)
{
$parent = $this->findOrCreate('Content');
foreach ($pageTypes as $type) {
$page = new $type();
$page->Title = $type . ' content';
$page->Content = <<<HTML
<p>
<a href="[file_link,id={$file->ID}]">Link file</a>
</p>
<p>
[image src="{$file->Link()}" id="{$file->ID}" width="600" height="420" class="leftAlone ss-htmleditorfield-file image"]
</p>
HTML;
$page->ParentID = $parent->ID;
$page->write();
}
}
public function blocks($pageTypes, Image $file)
{
$parent = $this->findOrCreate('Blocks');
foreach ($pageTypes as $type) {
$page = new $type();
$page->Title = $type . ' blocks';
$page->ParentID = $parent->ID;
$page->write();
$areaID = $page->ElementalAreaID;
$this->contentBlock($areaID, $file);
$this->bannerBlock($areaID, $file);
}
}
public function contentBlock(int $areaID, Image $file)
{
$block = ElementContent::create();
$block->Title = 'Content block';
$block->ParentID = $areaID;
$block->HTML = <<<HTML
<p>
<a href="[file_link,id={$file->ID}]">Link file</a>
</p>
<p>
[image src="{$file->Link()}" id="{$file->ID}" width="600" height="420" class="leftAlone ss-htmleditorfield-file image"]
</p>
HTML;
$block->write();
}
public function bannerBlock(int $areaID, Image $file)
{
$block = BannerBlock::create();
$block->Title = 'Banner block';
$block->ParentID = $areaID;
$block->FileID = $file->ID;
$block->write();
}
public function hasOnePoly($pageTypes, Image $file)
{
$parent = $this->findOrCreate('has one poly');
foreach ($pageTypes as $type) {
/** @var Page $page */
$page = new $type();
$page->Title = $type . ' has one poly';
$page->ParentID = $parent->ID;
$page->PolyToMe = $file;
$page->write();
$file->{'PolyTo' . $type . 'OnImage'} = $page;
}
}
public function manyManyThrough($pageTypes, Image $file)
{
$parent = $this->findOrCreate('many many through');
foreach ($pageTypes as $type) {
/** @var Page $page */
$page = new $type();
$page->Title = $type . ' many many through';
$page->ParentID = $parent->ID;
$page->write();
$page->ManyManyThrough()->add($file, ['ThirdLink' => $file]);
}
}
public function allInOne($pageTypes, Image $file)
{
$parent = $this->findOrCreate('All in one');
foreach ($pageTypes as $type) {
/** @var Page $page */
$page = new $type();
$page->Title = $type . ' all in one';
$page->ParentID = $parent->ID;
$page->MyImageID = $file->ID;
$page->MyFileID = $file->ID;
$page->MyManyImages()->add($file);
$page->MyManyFiles()->add($file);
$page->Content = <<<HTML
<p>
<a href="[file_link,id={$file->ID}]">Link file</a>
</p>
<p>
[image src="{$file->Link()}" id="{$file->ID}" width="600" height="420" class="leftAlone ss-htmleditorfield-file image"]
</p>
HTML;
$page->PolyToMe = $file;
$page->write();
$file->{'PolyTo' . $type . 'OnImage'} = $page;
$file->{$type . 'ID'} = $page->ID;
$file->{$type . 'ImageID'} = $page->ID;
$areaID = $page->ElementalAreaID;
$this->contentBlock($areaID, $file);
$this->bannerBlock($areaID, $file);
$page->ManyManyThrough()->add($file, ['ThirdLink' => $file]);
}
}
}
<?php
use SilverStripe\Dev\BuildTask;
use Faker\Factory;
use SilverStripe\Control\HTTPRequest;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use SilverStripe\Core\Manifest\ModuleLoader;
use Symfony\Component\Filesystem\Exception\IOException;
class PageMaker extends BuildTask
{
/**
* @var \Faker\Factory
*/
protected $faker;
/**
* @var Filesystem
*/
protected $fs;
/**
* @var Finder
*/
protected $finder;
/**
* FTPageTypeCreatorTask constructor.
*/
public function __construct()
{
parent::__construct();
$this->fs = new Filesystem();
$this->faker = Factory::create();
$this->finder = new Finder();
}
/**
* @param HTTPRequest $request
*/
public function run($request)
{
$count = $request->getVar('count') ?: 20;
$testPageDir = BASE_PATH . '/app/src/test-pages';
if ($this->fs->exists($testPageDir)) {
$this->fs->remove($testPageDir);
}
$this->fs->mkdir($testPageDir);
$pageTypes = $this->getExistingClassNames($testPageDir);
$created = 0;
while ($created < $count) {
$className = null;
while (
!$className ||
in_array($className, $pageTypes) ||
class_exists(basename($className, 'php'))
) {
$className = $this->generateClassName();
}
$pageTypes[] = $className;
$code = $this->generateClassCode($className);
$filePath = sprintf('%s/%s.php', $testPageDir, $className);
try {
$this->fs->dumpFile($filePath, $code);
$created++;
} catch (IOException $e) {
echo "Could not write to file $filePath. Got error: {$e->getMessage()}\n";
die();
}
echo "Created page type $className\n";
}
$configFile = BASE_PATH . '/app/_config/pages.yml';
if ($this->fs->exists($configFile)) {
$this->fs->remove($configFile);
}
$this->fs->dumpFile($configFile, $this->generateMatchingYml($pageTypes));
}
private function getExistingClassNames($dir)
{
$files = $this->finder
->in($dir)
->files()
->name('*Page.php');
return array_map(function ($file) {
/* @var SplFileInfo $file */
return $file->getBasename();
}, iterator_to_array($files));
}
private function generateClassName()
{
return ucfirst($this->faker->word . 'Page');
}
private function generateClassCode($className)
{
$self = __CLASS__;
$code = <<<PHP
<?php
use SilverStripe\Assets\Image;
use SilverStripe\Assets\File;
use DNADesign\Elemental\Extensions\ElementalPageExtension;
use SilverStripe\ORM\DataObject;
/**
* Generated by $self
*/
class $className extends Page
{
private static \$extensions = [ElementalPageExtension::class];
private static \$has_one = [
'MyImage' => Image::class,
'MyFile' => File::class,
'PolyToMe' => DataObject::class,
];
private static \$belongs_to = ['PolyToImage' => Image::class . ".PolyTo{$className}OnImage"];
private static \$has_many = ['MyImages' => Image::class, 'MyFiles' => File::class];
private static \$many_many = [
'MyManyImages' => Image::class,
'MyManyFiles' => File::class,
'ManyManyThrough' => [
'through' => {$className}Through::class,
'from' => 'Page',
'to' => 'File',
]
];
}
class {$className}Through extends DataObject
{
private static \$db = [
'Ranking' => 'Int',
];
private static \$has_one = [
'Page' => $className::class,
'File' => File::class,
'ThirdLink' => Image::class,
];
}
PHP;
return $code;
}
private function generateMatchingYml(array $pages)
{
$pages = array_map(function($page) {
return str_replace('.php', '', $page);
}, $pages);
$yml = "SilverStripe\Assets\File:\n has_one:\n";
foreach ($pages as $page) {
$yml .= " $page: $page\n";
}
$yml .= " Self: SilverStripe\Assets\File\n";
$yml .= " belongs_to:\n";
foreach ($pages as $page) {
$yml .= " PolyTo{$page}: $page.PolyToMe\n";
}
$yml .= " belongs_many_many:\n";
foreach ($pages as $page) {
$yml .= " {$page}s: $page\n";
$yml .= " {$page}sThrough: $page.ManyManyThrough\n";
}
$yml .= "SilverStripe\Assets\Image:\n has_one:\n";
foreach ($pages as $page) {
$yml .= " {$page}Image: $page\n";
$yml .= " PolyTo{$page}OnImage: SilverStripe\ORM\DataObject\n";
}
$yml .= " belongs_many_many:\n";
foreach ($pages as $page) {
$yml .= " {$page}sImage: $page\n";
}
$yml .= "CreateRelated:\n pageTypes:\n";
foreach ($pages as $page) {
$yml .= " - {$page}\n";
}
return $yml;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment