Webylon 3.1 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • auth
  • Booking
  • cart
    • shipping
    • steppedcheckout
  • Catalog
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • BaseObjectCategory
  • BookingAdminPage
  • BookingPage
  • ErrorPage
  • ErrorPage_Controller
  • MediawebPage
  • Notifications
  • Page
  • Room
  • RoomCatalog
  • SiteConfig
  • SiteTree
  • SubsitesSelectorPage
  • SubsitesVirtualPage
  • SubsitesVirtualPage_Controller
  • VideoBankPage
  • VirtualPage
  • VirtualPage_Controller
  • VirtualProduct_Controller

Interfaces

  • HiddenClass
  1 <?php
  2 /**
  3 * Virtual Page creates an instance of a  page, with the same fields that the original page had, but readonly.
  4 * This allows you can have a page in mulitple places in the site structure, with different children without duplicating the content
  5 * Note: This Only duplicates $db fields and not the $has_one etc.. 
  6 * @package cms
  7 */
  8 class VirtualPage extends Page {
  9     
 10     static $icon = array("cms/images/treeicons/page-shortcut-gold","file");
 11     
 12     public static $virtualFields;
 13     
 14     static $has_one = array(
 15         "CopyContentFrom" => "SiteTree",    
 16     );
 17     
 18     static $db = array(
 19         "VersionID" => "Int",
 20     );
 21     
 22     /** 
 23      * Generates the array of fields required for the page type.
 24      */
 25     function getVirtualFields() {
 26         $nonVirtualFields = array(
 27             "SecurityTypeID",
 28             "OwnerID",
 29             "URLSegment",
 30             "Sort",
 31             "Status",
 32             'ShowInMenus',
 33             // 'Locale'
 34             'ShowInSearch',
 35             'Version',
 36             "Embargo",
 37             "Expiry",
 38         );
 39 
 40         $allFields = $this->db();
 41         if($hasOne = $this->has_one()) foreach($hasOne as $link) $allFields[$link . 'ID'] = "Int";
 42         foreach($allFields as $field => $type) {
 43             if(!in_array($field, $nonVirtualFields)) $virtualFields[] = $field;
 44         }
 45         
 46         return $virtualFields;
 47     }
 48 
 49     function CopyContentFrom() {
 50         if(empty($this->record['CopyContentFromID'])) return new SiteTree();
 51         
 52         if(!isset($this->components['CopyContentFrom'])) {
 53             $this->components['CopyContentFrom'] = DataObject::get_by_id("SiteTree", 
 54                 $this->record['CopyContentFromID']);
 55 
 56             // Don't let VirtualPages point to other VirtualPages
 57             if($this->components['CopyContentFrom'] instanceof VirtualPage) {
 58                 $this->components['CopyContentFrom'] = null;
 59             }
 60                 
 61             // has_one component semantics incidate than an empty object should be returned
 62             if(!$this->components['CopyContentFrom']) {
 63                 $this->components['CopyContentFrom'] = new SiteTree();
 64             }
 65         }
 66         
 67         return $this->components['CopyContentFrom'];
 68     }
 69     function setCopyContentFromID($val) {
 70         if(DataObject::get_by_id('SiteTree', (int)$val) instanceof VirtualPage) $val = 0;
 71         return $this->setField("CopyContentFromID", $val);
 72     }
 73  
 74     function ContentSource() {
 75         return $this->CopyContentFrom();
 76     }
 77     
 78     function allowedChildren() {
 79         if($this->CopyContentFrom()) {
 80             return $this->CopyContentFrom()->allowedChildren();
 81         }
 82     }
 83     
 84     public function syncLinkTracking() {
 85         if($this->CopyContentFromID) {
 86             $this->HasBrokenLink = !(bool) DataObject::get_by_id('SiteTree', $this->CopyContentFromID);
 87         } else {
 88             $this->HasBrokenLink = true;
 89         }
 90     }
 91     
 92     /**
 93      * We can only publish the page if there is a published source page
 94      */
 95     public function canPublish($member = null) {
 96         return $this->isPublishable() && parent::canPublish($member);
 97     }
 98     
 99     /**
100      * Return true if we can delete this page from the live site, which is different from can
101      * we publish it.
102      */
103     public function canDeleteFromLive($member = null) {
104         return parent::canPublish($member);
105     }
106     
107     /**
108      * Returns true if is page is publishable by anyone at all
109      * Return false if the source page isn't published yet.
110      * 
111      * Note that isPublishable doesn't affect ete from live, only publish.
112      */
113     public function isPublishable() {
114         // No source
115         if(!$this->CopyContentFrom() || !$this->CopyContentFrom()->ID) {
116             return false;
117         }
118         
119         // Unpublished source
120         if(!Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->CopyContentFromID)) {
121             return false;
122         }
123         
124         // Default - publishable
125         return true;
126     }
127         
128     /**
129      * Generate the CMS fields from the fields from the original page.
130      */
131     function getCMSFields($cms = null) {
132         $fields = parent::getCMSFields($cms);
133         
134         // Setup the linking to the original page.
135         $copyContentFromField = new TreeDropdownField(
136             "CopyContentFromID", 
137             _t('VirtualPage.CHOOSE', "Choose a page to link to"), 
138             "SiteTree"
139         );
140         // filter doesn't let you select children of virtual pages as as source page
141         //$copyContentFromField->setFilterFunction(create_function('$item', 'return !($item instanceof VirtualPage);'));
142         
143         // Setup virtual fields
144         if($virtualFields = $this->getVirtualFields()) {
145             $roTransformation = new ReadonlyTransformation();
146             foreach($virtualFields as $virtualField) {
147                 if($fields->dataFieldByName($virtualField))
148                     $fields->replaceField($virtualField, $fields->dataFieldByName($virtualField)->transform($roTransformation));
149             }
150         }
151         
152         // Add fields to the tab
153         $fields->addFieldToTab("Root.Content.Main", 
154             new HeaderField('VirtualPageHeader',_t('VirtualPage.HEADER', "This is a virtual page")), 
155             "Title"
156         );
157         $fields->addFieldToTab("Root.Content.Main", $copyContentFromField, "Title");
158         
159         // Create links back to the original object in the CMS
160         if($this->CopyContentFrom()->ID) {
161             $linkToContent = "<a class=\"cmsEditlink\" href=\"admin/show/$this->CopyContentFromID\">" . 
162                 _t('VirtualPage.EDITCONTENT', 'click here to edit the content') . "</a>";
163             $fields->addFieldToTab("Root.Content.Main", 
164                 $linkToContentLabelField = new LabelField('VirtualPageContentLinkLabel', $linkToContent), 
165                 "Title"
166             );
167             $linkToContentLabelField->setAllowHTML(true);
168         }
169     
170         return $fields;
171     }
172     
173     /** 
174      * We have to change it to copy all the content from the original page first.
175      */
176     function onBeforeWrite() {
177         // On regular write, this will copy from published source.  This happens on every publish
178         if($this->extension_instances['Versioned']->migratingVersion
179             && Versioned::current_stage() == 'Live') {
180             if($this->CopyContentFromID) {
181                 $performCopyFrom = true;
182             
183             $stageSourceVersion = DB::query("SELECT \"Version\" FROM \"SiteTree\" WHERE \"ID\" = $this->CopyContentFromID")->value();
184             $liveSourceVersion = DB::query("SELECT \"Version\" FROM \"SiteTree_Live\" WHERE \"ID\" = $this->CopyContentFromID")->value();
185             
186                 // We're going to create a new VP record in SiteTree_versions because the published
187                 // version might not exist, unless we're publishing the latest version
188                 if($stageSourceVersion != $liveSourceVersion) {
189                     $this->extension_instances['Versioned']->migratingVersion = null;
190                 }
191             }
192 
193         // On regular write, this will copy from draft source.  This is only executed when the source
194         // page changeds
195         } else {
196             $performCopyFrom = $this->isChanged('CopyContentFromID') && $this->CopyContentFromID != 0;
197         }
198         
199         // On publish, this will copy from published source
200         if($performCopyFrom && $this instanceof VirtualPage) {
201             // This flush is needed because the get_one cache doesn't respect site version :-(
202             singleton('SiteTree')->flushCache();
203             $source = DataObject::get_one("SiteTree",sprintf('"SiteTree"."ID" = %d', $this->CopyContentFromID));
204             // Leave the updating of image tracking until after write, in case its a new record
205             $this->copyFrom($source, false);
206             $this->URLSegment = $source->URLSegment;
207         }
208         
209         parent::onBeforeWrite();
210     }
211     
212     function onAfterWrite() {
213         parent::onAfterWrite();
214 
215         // Don't do this stuff when we're publishing
216         if(!$this->extension_instances['Versioned']->migratingVersion) {
217             if(
218                 $this->isChanged('CopyContentFromID')
219                 && $this->CopyContentFromID != 0 
220                 && $this instanceof VirtualPage
221             ) {
222                 $this->updateImageTracking();
223             }
224         }
225         
226         FormResponse::add("$('Form_EditForm').reloadIfSetTo($this->ID);", $this->ID."_VirtualPage_onAfterWrite");
227     }
228     
229     /**
230      * Ensure we have an up-to-date version of everything.
231      */
232     function copyFrom($source, $updateImageTracking = true) {
233         if($source) {
234             foreach($this->getVirtualFields() as $virtualField) {
235                 $this->$virtualField = $source->$virtualField;
236             }
237             
238             // We also want to copy ShowInMenus, but only if we're copying the
239             // source page for the first time.
240             if($this->isChanged('CopyContentFromID')) {
241                 $this->ShowInMenus = $source->ShowInMenus;
242             }
243             
244             if($updateImageTracking) $this->updateImageTracking();
245         }
246     }
247     
248     function updateImageTracking() {
249         // Doesn't work on unsaved records
250         if(!$this->ID) return;
251 
252         // Remove CopyContentFrom() from the cache
253         unset($this->components['CopyContentFrom']);
254         
255         // Update ImageTracking
256         $ID = $this->CopyContentFrom()->ID;
257         $class = $this->CopyContentFrom()->ClassName;
258         
259         
260         if ($copyContentFromTracking = DataObjectFileTracking::get_track($ID, $class)) { // берем полный трекинг CopyContentFrom-страницы
261             $trackingData = array();
262             foreach($copyContentFromTracking as $entry) {
263                 if (isset($trackingData[$entry->FieldName])) {
264                     $trackingData[$entry->FieldName][] = $entry->FileID;
265                 } else {
266                     $trackingData[$entry->FieldName] = array($entry->FileID);
267                 }
268             }
269             
270             // трекаем только те поля VirtualPage, которые в ней непосредственно заведены
271             $virtualFields = $this->getVirtualFields();
272             foreach($trackingData as $fieldName=>$IDs) {
273                 if (in_array($fieldName, $virtualFields)) {
274                     DataObjectFileTracking::update_track($this->ID, $this->ClassName, $fieldName, $IDs);
275                 }
276             }
277         }
278     }
279     
280     /**
281      * Allow attributes on the master page to pass
282      * through to the virtual page
283      *
284      * @param string $field 
285      * @return mixed
286      */
287     function __get($field) {
288         if(parent::hasMethod($funcName = "get$field")) {
289             return $this->$funcName();
290         } else if(parent::hasField($field)) {
291             return $this->getField($field);
292         } else {
293             return $this->copyContentFrom()->$field;
294         }
295     }
296     
297     /**
298      * Pass unrecognized method calls on to the original data object
299      *
300      * @param string $method 
301      * @param string $args 
302      */
303     function __call($method, $args) {
304         if(parent::hasMethod($method)) {
305             return parent::__call($method, $args);
306         } else {
307             return call_user_func_array(array($this->copyContentFrom(), $method), $args);
308         }
309     }
310 
311     public function hasField($field) {
312         return (
313             array_key_exists($field, $this->record) 
314             || $this->hasDatabaseField($field) 
315             || array_key_exists($field, $this->db()) // Needed for composite fields
316             || parent::hasMethod("get{$field}")
317             || $this->CopyContentFrom()->hasField($field)
318         );
319     }   
320     /**
321      * Overwrite to also check for method on the original data object
322      *
323      * @param string $method 
324      * @return bool 
325      */
326     function hasMethod($method) {
327         if(parent::hasMethod($method)) return true;
328         return $this->copyContentFrom()->hasMethod($method);
329     }
330 }
331 
332 /**
333  * Controller for the virtual page.
334  * @package cms
335  */
336 class VirtualPage_Controller extends Page_Controller {
337     
338     static $allowed_actions = array(
339         'loadcontentall' => 'ADMIN',
340     );
341     
342     /**
343      * Reloads the content if the version is different ;-)
344      */
345     function reloadContent() {
346         $this->failover->copyFrom($this->failover->CopyContentFrom());
347         $this->failover->write();
348         return;
349     }
350     
351     function getViewer($action) {
352         $originalClass = get_class($this->CopyContentFrom());
353         if ($originalClass == 'SiteTree') $name = 'Page_Controller';
354         else $name = $originalClass."_Controller";
355         $controller = new $name();
356         return $controller->getViewer($action);
357     }
358     
359     /**
360      * When the virtualpage is loaded, check to see if the versions are the same
361      * if not, reload the content.
362      * NOTE: Virtual page must have a container object of subclass of sitetree.
363      * We can't load the content without an ID or record to copy it from.
364      */
365     function init(){
366         if(isset($this->record) && $this->record->ID){
367             if($this->record->VersionID != $this->failover->CopyContentFrom()->Version){
368                 $this->reloadContent();
369                 $this->VersionID = $this->failover->CopyContentFrom()->VersionID;
370             }
371         }
372         parent::init();
373     }
374 
375     function loadcontentall() {
376         $pages = DataObject::get("VirtualPage");
377         foreach($pages as $page) {
378             $page->copyFrom($page->CopyContentFrom());
379             $page->write();
380             $page->publish("Stage", "Live");
381             echo "<li>Published $page->URLSegment";
382         }
383     }
384     
385     /**
386      * Also check the original object's original controller for the method
387      *
388      * @param string $method 
389      * @return bool 
390      */
391     function hasMethod($method) {
392         $haveIt = parent::hasMethod($method);
393         if (!$haveIt) { 
394             $originalClass = get_class($this->CopyContentFrom());
395             if ($originalClass == 'SiteTree') $name = 'ContentController';
396             else $name = $originalClass."_Controller";
397             $controller = new $name($this->dataRecord->copyContentFrom());
398             $haveIt = $controller->hasMethod($method);
399         }
400         return $haveIt;
401     }
402     
403     /**
404      * Pass unrecognized method calls on to the original controller
405      *
406      * @param string $method 
407      * @param string $args 
408      */
409     function __call($method, $args) {
410         try {
411             return parent::__call($method, $args);
412         } catch (Exception $e) {
413             // Hack... detect exception type. We really should use exception subclasses.
414             // if the exception isn't a 'no method' error, rethrow it
415             if ($e->getCode() !== 2175) throw $e;
416             $original = $this->copyContentFrom();
417             $originalClass = get_class($original);
418             if ($originalClass == 'SiteTree') $name = 'ContentController';
419             else $name = $originalClass."_Controller";
420             $controller = new $name($this->dataRecord->copyContentFrom());
421             return call_user_func_array(array($controller, $method), $args);
422         }
423     }
424 }
425 
426 ?>
427 
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.1 API Docs API documentation generated by ApiGen 2.8.0