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

Packages

  • 1c
    • exchange
      • catalog
  • auth
  • Booking
  • building
    • company
  • cart
    • shipping
    • steppedcheckout
  • Catalog
    • monument
  • 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

  • Aggregate
  • Aggregate_Relationship
  • AssetAdminQuotaExtension
  • AttachedFilesExtension
  • BookingWidget
  • ClassInfo
  • ControllerRedirectExtension
  • CSSContentParser
  • DisableJSValidation
  • Extension
  • HtmlEditorQuotaExtension
  • ManifestBuilder
  • MobileExtension
  • Object
  • PaymentMethodAutoHide
  • ProductSearchFormExtension
  • SS_Cache
  • TokenisedRegularExpression
  • ValidationResult
  • WebylonSiteSearchExtension
  • YamlFixture

Functions

  • __autoload
  • _t
  • array_fill_keys
  • getClassFile
  • getSysTempDir
  • getTempFolder
  • increase_memory_limit_to
  • increase_time_limit_to
  • project
  • singleton
  • stripslashes_recursively
  • translate_memstring
  1 <?php
  2 
  3 require_once 'thirdparty/spyc/spyc.php';
  4 
  5 /**
  6  * Uses the Spyc library to parse a YAML document (see http://yaml.org).
  7  * YAML is a simple markup languages that uses tabs and colons instead of the more verbose XML tags, 
  8  * and because of this much better for developers creating files by hand.
  9  * 
 10  * The contents of the YAML file are broken into three levels:
 11  * - Top level: class names - Page and ErrorPage. This is the name of the dataobject class that should be created. 
 12  *   The fact that ErrorPage is actually a subclass is irrelevant to the system populating the database. 
 13  *   Each identifier you specify delimits a new database record. 
 14  *   This means that every record needs to have an identifier, whether you use it or not.
 15  * - Third level: fields - each field for the record is listed as a 3rd level entry. 
 16  *   In most cases, the fieldŐs raw content is provided. 
 17  *   However, if you want to define a relationship, you can do so using "=>"
 18  * 
 19  * There are a couple of lines like this:
 20  * <code>
 21  * Parent: =>Page.about
 22  * </code>
 23  * This will tell the system to set the ParentID database field to the ID of the Page object with the identifier ŇaboutÓ. 
 24  * This can be used on any has-one or many-many relationship. 
 25  * Note that we use the name of the relationship (Parent), and not the name of the database field (ParentID)
 26  *
 27  * On many-many relationships, you should specify a comma separated list of values.
 28  * <code>
 29  * MyRelation: =>Class.inst1,=>Class.inst2,=>Class.inst3
 30  * </code>
 31  * An crucial thing to note is that the YAML file specifies DataObjects, not database records. 
 32  * The database is populated by instantiating DataObject objects, setting the fields listed, and calling write(). 
 33  * This means that any onBeforeWrite() or default value logic will be executed as part of the test. 
 34  * This forms the basis of our testURLGeneration() test above.
 35  * 
 36  * For example, the URLSegment value of Page.staffduplicate is the same as the URLSegment value of Page.staff. 
 37  * When the fixture is set up, the URLSegment value of Page.staffduplicate will actually be my-staff-2.
 38  * 
 39  * Finally, be aware that requireDefaultRecords() is not called by the database populator - 
 40  * so you will need to specify standard pages such as 404 and home in your YAML file.
 41  * 
 42  * <code>
 43  * Page:
 44  *    home:
 45  *       Title: Home
 46  *    about:
 47  *       Title: About Us
 48  *    staff:
 49  *       Title: Staff
 50  *       URLSegment: my-staff
 51  *       Parent: =>Page.about
 52  *    staffduplicate:
 53  *       Title: Staff
 54  *       URLSegment: my-staff
 55  *       Parent: =>Page.about
 56  *    products:
 57  *       Title: Products
 58  * ErrorPage:
 59  *    404:
 60  *      Title: Page not Found
 61  *      ErrorCode: 404
 62  * </code>
 63  * 
 64  * @package sapphire
 65  * @subpackage core
 66  * 
 67  * @see http://spyc.sourceforge.net/
 68  * 
 69  * @todo Write unit test for YamlFixture
 70  *  
 71  * @param $fixtureFile The location of the .yml fixture file, relative to the site base dir
 72  */
 73 class YamlFixture extends Object {
 74     
 75     /**
 76      * The location of the .yml fixture file, relative to the site base dir
 77      *
 78      * @var string
 79      */
 80     protected $fixtureFile;
 81 
 82     /**
 83      * Array of fixture items
 84      * 
 85      * @var array
 86      */
 87     protected $fixtureDictionary;
 88     
 89     function __construct($fixtureFile) {
 90         if(!file_exists(Director::baseFolder().'/'. $fixtureFile)) {
 91             user_error('YamlFixture::__construct(): Fixture path "' . $fixtureFile . '" not found', E_USER_ERROR);
 92         }
 93         
 94         $this->fixtureFile = $fixtureFile;
 95         parent::__construct();
 96     }
 97     
 98     /**
 99      * Get the ID of an object from the fixture.
100      * @param $className The data class, as specified in your fixture file.  Parent classes won't work
101      * @param $identifier The identifier string, as provided in your fixture file
102      */
103     public function idFromFixture($className, $identifier) {
104         if(isset($this->fixtureDictionary[$className][$identifier])) {
105             return $this->fixtureDictionary[$className][$identifier];
106         } else {
107             return false;
108         }
109         
110     }
111     
112     /**
113      * Return all of the IDs in the fixture of a particular class name.
114      * 
115      * @return A map of fixture-identifier => object-id
116      */
117     public function allFixtureIDs($className) {
118         if(isset($this->fixtureDictionary[$className])) {
119             return $this->fixtureDictionary[$className];
120         } else {
121             return false;
122         }
123         
124     }
125 
126     /**
127      * Get an object from the fixture.
128      * 
129      * @param $className The data class, as specified in your fixture file.  Parent classes won't work
130      * @param $identifier The identifier string, as provided in your fixture file
131      */
132     public function objFromFixture($className, $identifier) {
133         $id = $this->idFromFixture($className, $identifier);
134         if($id) return DataObject::get_by_id($className, $id);
135     }
136     
137     /**
138      * Load a YAML fixture file into the database.
139      * Once loaded, you can use idFromFixture() and objFromFixture() to get items from the fixture.
140      * 
141      * Caution: In order to support reflexive relations which need a valid object ID,
142      * the record is written twice: first after populating all non-relational fields,
143      * then again after populating all relations (has_one, has_many, many_many).
144      */
145     public function saveIntoDatabase() {
146         // We have to disable validation while we import the fixtures, as the order in
147         // which they are imported doesnt guarantee valid relations until after the
148         // import is complete.
149         $validationenabled = DataObject::get_validation_enabled();
150         DataObject::set_validation_enabled(false);
151         
152         $parser = new Spyc();
153         $fixtureContent = $parser->loadFile(Director::baseFolder().'/'.$this->fixtureFile);
154 
155         $this->fixtureDictionary = array();
156         foreach($fixtureContent as $dataClass => $items) {
157             if(ClassInfo::exists($dataClass)) {
158                 $this->writeDataObject($dataClass, $items);
159             } else {
160                 $this->writeSQL($dataClass, $items);
161             }
162         }
163         
164         DataObject::set_validation_enabled($validationenabled);
165     }
166     
167     /**
168      * Writes the fixture into the database using DataObjects
169      *
170      * @param string $dataClass
171      * @param array $items
172      */
173     protected function writeDataObject($dataClass, $items) {
174         foreach($items as $identifier => $fields) {
175             $obj = new $dataClass();
176             
177             // If an ID is explicitly passed, then we'll sort out the initial write straight away
178             // This is just in case field setters triggered by the population code in the next block
179             // Call $this->write().  (For example, in FileTest)
180             if(isset($fields['ID'])) {
181                 $obj->ID = $fields['ID'];
182                 
183                 // The database needs to allow inserting values into the foreign key column (ID in our case)
184                 $conn = DB::getConn();
185                 if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing(ClassInfo::baseDataClass($dataClass), true);
186                 $obj->write(false, true);
187                 if(method_exists($conn, 'allowPrimaryKeyEditing')) $conn->allowPrimaryKeyEditing(ClassInfo::baseDataClass($dataClass), false);
188             }
189             
190             // Populate the dictionary with the ID
191             if($fields) foreach($fields as $fieldName => $fieldVal) {
192                 if($obj->many_many($fieldName) || $obj->has_many($fieldName) || $obj->has_one($fieldName)) continue;
193                 $obj->$fieldName = $this->parseFixtureVal($fieldVal);
194             }
195             $obj->write();
196             
197             // has to happen before relations in case a class is referring to itself
198             $this->fixtureDictionary[$dataClass][$identifier] = $obj->ID;
199             
200             // Populate all relations
201             if($fields) foreach($fields as $fieldName => $fieldVal) {
202                 if($obj->many_many($fieldName) || $obj->has_many($fieldName)) {
203                     $parsedItems = array();
204                     $items = preg_split('/ *, */',trim($fieldVal));
205                     foreach($items as $item) {
206                         $parsedItems[] = $this->parseFixtureVal($item);
207                     }
208                     $obj->write();
209                     if($obj->has_many($fieldName)) {
210                         $obj->getComponents($fieldName)->setByIDList($parsedItems);
211                     } elseif($obj->many_many($fieldName)) {
212                         $obj->getManyManyComponents($fieldName)->setByIDList($parsedItems);
213                     }
214                 } elseif($obj->has_one($fieldName)) {
215                     $obj->{$fieldName . 'ID'} = $this->parseFixtureVal($fieldVal);
216                 }
217             }
218             $obj->write();
219         }
220     }
221     
222     /**
223      * Writes the fixture into the database directly using a database manipulation
224      *
225      * @param string $table
226      * @param array $items
227      */
228     protected function writeSQL($table, $items) {
229         foreach($items as $identifier => $fields) {
230             $manipulation = array($table => array("fields" => array(), "command" => "insert")); 
231             foreach($fields as $fieldName=> $fieldVal) { 
232                 $manipulation[$table]["fields"][$fieldName] = "'".$this->parseFixtureVal($fieldVal)."'"; 
233             }
234             DB::manipulate($manipulation);
235             $this->fixtureDictionary[$table][$identifier] = DB::getGeneratedID($table);
236         }
237     }
238     
239     /**
240      * Parse a value from a fixture file.  If it starts with => it will get an ID from the fixture dictionary
241      */
242     protected function parseFixtureVal($fieldVal) {
243         // Parse a dictionary reference - used to set foreign keys
244         if(substr($fieldVal,0,2) == '=>') {
245             list($a, $b) = explode('.', substr($fieldVal,2), 2);
246             return $this->fixtureDictionary[$a][$b];
247 
248         // Regular field value setting
249         } else {
250             return $fieldVal;
251         }
252     }
253 }
254 
[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.2 API Docs API documentation generated by ApiGen 2.8.0