2008-08-11 01:17:51 +02:00
|
|
|
<?php
|
2008-08-17 03:08:10 +02:00
|
|
|
|
2016-08-19 00:51:35 +02:00
|
|
|
namespace SilverStripe\Dev;
|
|
|
|
|
|
|
|
use SilverStripe\Control\Director;
|
|
|
|
use SilverStripe\Core\ClassInfo;
|
2017-05-17 07:40:13 +02:00
|
|
|
use SilverStripe\Core\Injector\Injectable;
|
2015-09-08 17:07:56 +02:00
|
|
|
use Symfony\Component\Yaml\Parser;
|
2016-08-19 00:51:35 +02:00
|
|
|
use InvalidArgumentException;
|
2008-08-17 03:08:10 +02:00
|
|
|
|
2008-08-11 01:17:51 +02:00
|
|
|
/**
|
2015-09-08 17:07:56 +02:00
|
|
|
* Uses Symfony's YAML component to parse a YAML document (see http://yaml.org).
|
2016-03-08 21:50:18 +01:00
|
|
|
* YAML is a simple markup languages that uses tabs and colons instead of the more verbose XML tags,
|
2008-08-11 01:17:51 +02:00
|
|
|
* and because of this much better for developers creating files by hand.
|
2016-03-08 21:50:18 +01:00
|
|
|
*
|
2008-08-11 01:17:51 +02:00
|
|
|
* The contents of the YAML file are broken into three levels:
|
2016-03-08 21:50:18 +01:00
|
|
|
* - Top level: class names - Page and ErrorPage. This is the name of the dataobject class that should be created.
|
|
|
|
* The fact that ErrorPage is actually a subclass is irrelevant to the system populating the database.
|
|
|
|
* Each identifier you specify delimits a new database record.
|
2008-08-11 01:17:51 +02:00
|
|
|
* This means that every record needs to have an identifier, whether you use it or not.
|
2016-03-08 21:50:18 +01:00
|
|
|
* - Third level: fields - each field for the record is listed as a 3rd level entry.
|
|
|
|
* In most cases, the field's raw content is provided.
|
2008-08-11 01:17:51 +02:00
|
|
|
* However, if you want to define a relationship, you can do so using "=>"
|
2016-03-08 21:50:18 +01:00
|
|
|
*
|
2008-08-11 01:17:51 +02:00
|
|
|
* There are a couple of lines like this:
|
2010-04-23 02:11:41 +02:00
|
|
|
* <code>
|
|
|
|
* Parent: =>Page.about
|
|
|
|
* </code>
|
2012-09-26 23:34:00 +02:00
|
|
|
* This will tell the system to set the ParentID database field to the ID of the Page object with the identifier
|
2016-03-08 21:50:18 +01:00
|
|
|
* 'about'. This can be used on any has-one or many-many relationship.
|
2008-08-11 01:17:51 +02:00
|
|
|
* Note that we use the name of the relationship (Parent), and not the name of the database field (ParentID)
|
|
|
|
*
|
|
|
|
* On many-many relationships, you should specify a comma separated list of values.
|
2010-04-23 02:11:41 +02:00
|
|
|
* <code>
|
|
|
|
* MyRelation: =>Class.inst1,=>Class.inst2,=>Class.inst3
|
|
|
|
* </code>
|
2016-03-08 21:50:18 +01:00
|
|
|
*
|
|
|
|
* An crucial thing to note is that the YAML file specifies DataObjects, not database records.
|
|
|
|
* The database is populated by instantiating DataObject objects, setting the fields listed, and calling write().
|
|
|
|
* This means that any onBeforeWrite() or default value logic will be executed as part of the test.
|
2008-08-11 01:17:51 +02:00
|
|
|
* This forms the basis of our testURLGeneration() test above.
|
2016-03-08 21:50:18 +01:00
|
|
|
*
|
|
|
|
* For example, the URLSegment value of Page.staffduplicate is the same as the URLSegment value of Page.staff.
|
2008-08-11 01:17:51 +02:00
|
|
|
* When the fixture is set up, the URLSegment value of Page.staffduplicate will actually be my-staff-2.
|
2016-03-08 21:50:18 +01:00
|
|
|
*
|
|
|
|
* Finally, be aware that requireDefaultRecords() is not called by the database populator -
|
2008-08-11 01:17:51 +02:00
|
|
|
* so you will need to specify standard pages such as 404 and home in your YAML file.
|
2016-03-08 21:50:18 +01:00
|
|
|
*
|
2008-08-11 01:17:51 +02:00
|
|
|
* <code>
|
|
|
|
* Page:
|
|
|
|
* home:
|
|
|
|
* Title: Home
|
|
|
|
* about:
|
|
|
|
* Title: About Us
|
|
|
|
* staff:
|
|
|
|
* Title: Staff
|
|
|
|
* URLSegment: my-staff
|
|
|
|
* Parent: =>Page.about
|
|
|
|
* staffduplicate:
|
|
|
|
* Title: Staff
|
|
|
|
* URLSegment: my-staff
|
|
|
|
* Parent: =>Page.about
|
|
|
|
* products:
|
|
|
|
* Title: Products
|
|
|
|
* ErrorPage:
|
|
|
|
* 404:
|
|
|
|
* Title: Page not Found
|
|
|
|
* ErrorCode: 404
|
|
|
|
* </code>
|
|
|
|
*/
|
2017-05-17 07:40:13 +02:00
|
|
|
class YamlFixture
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2017-05-17 07:40:13 +02:00
|
|
|
use Injectable;
|
2016-11-29 00:31:16 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Absolute path to the .yml fixture file
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $fixtureFile;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* String containing fixture
|
|
|
|
*
|
|
|
|
* @var String
|
|
|
|
*/
|
|
|
|
protected $fixtureString;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $fixture Absolute file path, or relative path to {@link Director::baseFolder()}
|
|
|
|
*/
|
|
|
|
public function __construct($fixture)
|
|
|
|
{
|
|
|
|
if (false !== strpos($fixture, "\n")) {
|
|
|
|
$this->fixtureString = $fixture;
|
|
|
|
} else {
|
|
|
|
if (!Director::is_absolute($fixture)) {
|
2018-01-16 19:39:30 +01:00
|
|
|
$fixture = Director::baseFolder() . '/' . $fixture;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!file_exists($fixture)) {
|
|
|
|
throw new InvalidArgumentException('YamlFixture::__construct(): Fixture path "' . $fixture
|
|
|
|
. '" not found');
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->fixtureFile = $fixture;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return String Absolute file path
|
|
|
|
*/
|
|
|
|
public function getFixtureFile()
|
|
|
|
{
|
|
|
|
return $this->fixtureFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return String Fixture string
|
|
|
|
*/
|
|
|
|
public function getFixtureString()
|
|
|
|
{
|
|
|
|
return $this->fixtureString;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Persists the YAML data in a FixtureFactory,
|
|
|
|
* which in turn saves them into the database.
|
|
|
|
* Please use the passed in factory to access the fixtures afterwards.
|
|
|
|
*
|
|
|
|
* @param FixtureFactory $factory
|
|
|
|
*/
|
|
|
|
public function writeInto(FixtureFactory $factory)
|
|
|
|
{
|
|
|
|
$parser = new Parser();
|
|
|
|
if (isset($this->fixtureString)) {
|
|
|
|
$fixtureContent = $parser->parse($this->fixtureString);
|
|
|
|
} else {
|
2019-07-26 10:03:02 +02:00
|
|
|
if (!file_exists($this->fixtureFile) || is_dir($this->fixtureFile)) {
|
2016-11-29 00:31:16 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$contents = file_get_contents($this->fixtureFile);
|
|
|
|
$fixtureContent = $parser->parse($contents);
|
|
|
|
|
|
|
|
if (!$fixtureContent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($fixtureContent as $class => $items) {
|
|
|
|
foreach ($items as $identifier => $data) {
|
|
|
|
if (ClassInfo::exists($class)) {
|
|
|
|
$factory->createObject($class, $identifier, $data);
|
|
|
|
} else {
|
|
|
|
$factory->createRaw($class, $identifier, $data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-11 01:17:51 +02:00
|
|
|
}
|