Source of file MediaPage.php
Size: 13,484 Bytes - Last Modified: 2021-12-23T10:06:09+00:00
/var/www/docs.ssmods.com/process/src/src/pages/MediaPage.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 | <?php namespace nglasl\mediawesome; use SilverStripe\Assets\File; use SilverStripe\Assets\Image; use SilverStripe\Control\Controller; use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Core\Injector\Injector; use SilverStripe\Forms\DateField; use SilverStripe\Forms\FileHandleField; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldAddNewButton; use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; use SilverStripe\Forms\ListboxField; use SilverStripe\Forms\LiteralField; use SilverStripe\Forms\ReadonlyField; use SilverStripe\Forms\TextareaField; use SilverStripe\Forms\TextField; use SilverStripe\ORM\DB; use SilverStripe\ORM\Queries\SQLDelete; use SilverStripe\ORM\Queries\SQLSelect; use SilverStripe\ORM\Queries\SQLUpdate; use SilverStripe\Versioned\Versioned; use SilverStripe\View\Requirements; /** * Displays customised media content relating to the respective media type. * @author Nathan Glasl <nathan@symbiote.com.au> */ class MediaPage extends \Page { private static $table_name = 'MediaPage'; private static $db = array( 'ExternalLink' => 'Varchar(255)', 'Abstract' => 'Text', 'Date' => 'Date' ); private static $has_one = array( 'MediaType' => MediaType::class ); private static $many_many = array( 'MediaAttributes' => array( 'through' => MediaPageAttribute::class, // This is essentially the versioned join. 'from' => 'MediaPage', 'to' => 'MediaAttribute' ), 'Images' => Image::class, 'Attachments' => File::class, 'Categories' => MediaTag::class, 'Tags' => MediaTag::class ); private static $owns = array( 'MediaPageAttributes', 'Images', 'Attachments' ); private static $defaults = array( 'ShowInMenus' => 0 ); private static $searchable_fields = array( 'Title', 'ExternalLink', 'Abstract', 'Tagging' ); private static $can_be_root = false; private static $allowed_children = 'none'; private static $default_parent = MediaHolder::class; private static $description = 'Blog, Event, News, Publication <strong>or Custom Media</strong>'; private static $icon = 'nglasl/silverstripe-mediawesome: client/images/page.png'; /** * The default media types and their respective attributes. */ private static $type_defaults = array(); public function requireDefaultRecords() { parent::requireDefaultRecords(); // Determine whether this requires an SS3 to SS4 migration. if(MediaAttribute::get()->filter('MediaTypeID', 0)->exists()) { // The problem is that class name mapping happens after this, but we need it right now to query pages. foreach(array( 'SiteTree', 'SiteTree_Live', 'SiteTree_Versions' ) as $table) { $update = new SQLUpdate( $table, array( 'ClassName' => MediaPage::class ), array( 'ClassName' => 'MediaPage' ) ); $update->execute(); } // Retrieve the existing media attributes. $attributes = new SQLSelect( '*', 'MediaAttribute', 'LinkID <> 0 AND MediaPageID <> 0', 'LinkID ASC' ); $attributes = $attributes->execute(); if(count($attributes)) { // With the results from above, delete these to prevent data integrity issues. $delete = new SQLDelete( 'MediaAttribute', 'LinkID <> 0 AND MediaPageID <> 0' ); $delete->execute(); // Migrate the existing media attributes. foreach($attributes as $existing) { $page = MediaPage::get()->byID($existing['MediaPageID']); if(!$page) { // This page may no longer exist. continue; } if($existing['LinkID'] == -1) { // Instantiate a new attribute for each "master" attribute. $attribute = MediaAttribute::create(); $attribute->ID = $existing['ID']; $attribute->Created = $existing['Created']; $attribute->Title = $existing['Title']; $attribute->OriginalTitle = $existing['OriginalTitle']; $attribute->MediaTypeID = $page->MediaTypeID; $attribute->write(); } else { $attribute = MediaAttribute::get()->byID($existing['LinkID']); } // Each page will have different content for a media attribute. $content = isset($existing['Content']) ? $existing['Content'] : null; $page->MediaAttributes()->add($attribute, array( 'Content' => $content )); // The attributes are versioned, but should only be published when it's considered safe to do so. if($page->isPublished() && !$page->isModifiedOnDraft()) { $page->publishRecursive(); } } } } // Retrieve existing "start time" attributes. $attributes = MediaAttribute::get()->filter(array( 'MediaType.Title' => 'Event', 'OriginalTitle' => 'Start Time' )); foreach($attributes as $attribute) { // These should now be "time" attributes. $attribute->Title = 'Time'; $attribute->OriginalTitle = 'Time'; $attribute->write(); } // Instantiate the default media types and their respective attributes. foreach($this->config()->type_defaults as $name => $attributes) { // Confirm that the media type doesn't already exist before creating it. $type = MediaType::get()->filter(array( 'Title' => $name ))->first(); if(!$type) { $type = MediaType::create(); $type->Title = $name; $type->write(); DB::alteration_message("\"{$name}\" Media Type", 'created'); } if(is_array($attributes)) { foreach($attributes as $attribute) { // Confirm that the media attributes don't already exist before creating them. if(!MediaAttribute::get()->filter(array( 'MediaTypeID' => $type->ID, 'OriginalTitle' => $attribute ))->first()) { $new = MediaAttribute::create(); $new->Title = $attribute; $new->MediaTypeID = $type->ID; $new->write(); DB::alteration_message("\"{$name}\" > \"{$attribute}\" Media Attribute", 'created'); } } } } } public function getCMSFields() { $fields = parent::getCMSFields(); // Display the media type as read only. $fields->addFieldToTab('Root.Main', ReadonlyField::create( 'Type', 'Type', $this->MediaType()->Title ), 'Title'); // Display a notification that the parent holder contains mixed children. $parent = $this->getParent(); if($parent && $parent->getMediaHolderChildren()->exists()) { Requirements::css('nglasl/silverstripe-mediawesome: client/css/mediawesome.css'); $fields->addFieldToTab('Root.Main', LiteralField::create( 'MediaNotification', "<p class='mediawesome notification'><strong>Mixed {$this->MediaType()->Title} Holder</strong></p>" ), 'Type'); } // Display the remaining media page fields. $fields->addFieldToTab('Root.Main', TextField::create( 'ExternalLink' )->setDescription('An <strong>optional</strong> redirect URL to the media source. If this field is not empty, it will make this page act like a RedirectorPage.'), 'URLSegment'); $fields->addFieldToTab('Root.Main', DateField::create( 'Date' ), 'Content'); // Allow customisation of categories and tags respective to the current page. $tags = MediaTag::get()->map()->toArray(); $fields->findOrMakeTab('Root.CategoriesTags', 'Categories and Tags'); $fields->addFieldToTab('Root.CategoriesTags', $categoriesList = ListboxField::create( 'Categories', 'Categories', $tags )); $fields->addFieldToTab('Root.CategoriesTags', $tagsList = ListboxField::create( 'Tags', 'Tags', $tags )); if(!$tags) { $categoriesList->setAttribute('disabled', 'true'); $tagsList->setAttribute('disabled', 'true'); } // Display an abstract field for content summarisation. $fields->addfieldToTab('Root.Main', $abstract = TextareaField::create( 'Abstract' ), 'Content'); $abstract->setDescription('A concise summary of the content'); // Allow customisation of the media type attributes. $fields->addFieldToTab('Root.Main', GridField::create( 'MediaPageAttributes', "{$this->MediaType()->Title} Attributes", $this->MediaPageAttributes(), GridFieldConfig_RecordEditor::create()->removeComponentsByType(GridFieldAddNewButton::class) )->addExtraClass('pb-2'), 'Content'); // Allow customisation of images and attachments. $type = strtolower($this->MediaType()->Title); $fields->findOrMakeTab('Root.ImagesAttachments', 'Images and Attachments'); $fields->addFieldToTab('Root.ImagesAttachments', $images = Injector::inst()->create( FileHandleField::class, 'Images' )); $images->setAllowedFileCategories('image/supported'); $images->setFolderName("media-{$type}/{$this->ID}/images"); $fields->addFieldToTab('Root.ImagesAttachments', $attachments = Injector::inst()->create( FileHandleField::class, 'Attachments' )); $attachments->setFolderName("media-{$type}/{$this->ID}/attachments"); // Allow extension customisation. $this->extend('updateMediaPageCMSFields', $fields); return $fields; } /** * Confirm that the current page is valid. */ public function validate() { $parent = $this->getParent(); // The URL segment will conflict with a year/month/day/media format when numeric. if(is_numeric($this->URLSegment) || !($parent instanceof MediaHolder) || ($this->MediaTypeID && ($parent->MediaTypeID != $this->MediaTypeID))) { // Customise a validation error message. if(is_numeric($this->URLSegment)) { $message = '"URL Segment" must not be numeric!'; } else if(!($parent instanceof MediaHolder)) { $message = 'The parent needs to be a published media holder!'; } else { $message = "The media holder type doesn't match this!"; } $error = new HTTPResponse_Exception($message, 403); $error->getResponse()->addHeader('X-Status', rawurlencode($message)); // Allow extension customisation. $this->extend('validateMediaPage', $error); throw $error; } return parent::validate(); } public function onBeforeWrite() { parent::onBeforeWrite(); // Set the default media page date. if(!$this->Date) { $this->Date = date('Y-m-d'); } // Confirm that the external link exists. if($this->ExternalLink) { // The following code was taken from RedirectorPage::onBeforeWrite() // on SilverStripe 4.1.1 if ($this->ExternalLink && substr($this->ExternalLink, 0, 2) !== '//') { $urlParts = parse_url($this->ExternalLink); if ($urlParts) { if (empty($urlParts['scheme'])) { // no scheme, assume http $this->ExternalLink = 'http://' . $this->ExternalLink; } elseif (!in_array($urlParts['scheme'], array( 'http', 'https', ))) { // we only allow http(s) urls $this->ExternalLink = ''; } } else { // malformed URL to reject $this->ExternalLink = ''; } } $file_headers = @get_headers($this->ExternalLink); if(!$file_headers || strripos($file_headers[0], '404 Not Found')) { $this->ExternalLink = null; } } // Apply the parent holder media type. $parent = $this->getParent(); if($parent) { $type = $parent->MediaType(); if($type->exists()) { $this->MediaTypeID = $type->ID; } } } public function onAfterWrite() { parent::onAfterWrite(); // This triggers for both a save and publish, causing duplicate attributes to appear. if(Versioned::get_stage() === 'Stage') { // The attributes of the respective type need to appear on this page. foreach($this->MediaType()->MediaAttributes() as $attribute) { $this->MediaAttributes()->add($attribute); } } } /** * Determine the URL by using the media holder's defined URL format. */ public function Link($action = null) { if($this->ExternalLink) { return $this->ExternalLink; } $parent = $this->getParent(); if(!$parent) { return null; } $date = ($parent->URLFormatting !== '-') ? $this->dbObject('Date')->Format($parent->URLFormatting ?: 'y/MM/dd/') : ''; $join = array( $parent->Link(), "{$date}{$this->URLSegment}/" ); if($action && is_string($action)) { $join[] = "{$action}/"; } $link = Controller::join_links($join); return $link; } /** * Determine the absolute URL by using the media holder's defined URL format. */ public function AbsoluteLink($action = null) { if($this->ExternalLink) { return $this->ExternalLink; } $parent = $this->getParent(); if(!$parent) { return null; } $date = ($parent->URLFormatting !== '-') ? $this->dbObject('Date')->Format($parent->URLFormatting ?: 'y/MM/dd/') : ''; $link = $parent->AbsoluteLink() . "{$date}{$this->URLSegment}/"; if($action && is_string($action)) { $link .= "{$action}/"; } return $link; } /** * Retrieve the versioned attribute join records, since these are what we're editing. * * @return media page attribute */ public function MediaPageAttributes() { return MediaPageAttribute::get()->filter('MediaPageID', $this->ID); } /** * Retrieve a specific attribute for use in templates. * * @parameter <{ATTRIBUTE}> string * @return media attribute */ public function getAttribute($title) { return $this->MediaAttributes()->filter('OriginalTitle', $title)->first(); } /** * Retrieve a specific attribute for use in templates. * * @parameter <{ATTRIBUTE}> string * @return media attribute */ public function Attribute($title) { // This provides consistency when it comes to defining parameters from the template. return $this->getAttribute($title); } } |