diff --git a/documents/APIs.md b/documents/APIs.md index 065f323..cab7e0d 100644 --- a/documents/APIs.md +++ b/documents/APIs.md @@ -26,33 +26,27 @@ __construct($root?, array $options?); ->query(...$xpath); -->appendChild($child, ...$optionals); -// alias: ->add($child, ...$optionals); +->appendChild($child, ...$optionals); -->prependSibling($sibling, ...$optionals); -// aliases: ->prepend($sibling, ...$optionals); +->prependSibling($sibling, ...$optionals); ->insertSiblingBefore($sibling, ...$optionals); -->appendSibling($sibling, ...$optionals); -// aliases: ->append($sibling, ...$optionals); +->appendSibling($sibling, ...$optionals); ->insertSiblingAfter($sibling, ...$optionals); -->setAttribute(...$arguments); -// alias: ->attr(...$arguments); +->setAttribute(...$arguments); -->setText($text); -// alias: ->text($text); +->setText($text); ->appendText($text); -->setCdata($text); -// alias: ->cdata($text); +->setCdata($text); ->appendCdata($text); @@ -65,6 +59,8 @@ __construct($root?, array $options?); ->dom(); ->xml($strip = false); + +->save($file, $strip = false); ``` diff --git a/documents/Changelog.txt b/documents/Changelog.txt index 1c7dca2..817433b 100644 --- a/documents/Changelog.txt +++ b/documents/Changelog.txt @@ -1,20 +1,26 @@ [+]: new [~]: changed [-]: removed [#]: fixed [@]: internal -1.12.4: (2016-01-23) -Internal cleanup. +1.13: (2016-01-24) +introduces the '->save()' method. + + * [+] ->save() is part of the family. + + +1.12.4: +internal cleanup. * [@] cleanup. 1.12.3: -Refactoring improving the code design. +refactoring improving the code design. * [@] refactoring. 1.12.2: -Internal refactoring and performance regression fix. +internal refactoring and performance regression fix. * [@] refactoring. Performances are normal. diff --git a/documents/Getting-Started.md b/documents/Getting-Started.md index 8db32a9..78b9a65 100644 --- a/documents/Getting-Started.md +++ b/documents/Getting-Started.md @@ -608,7 +608,7 @@ The document can be exported as `DOMDocument`. $dom = $book->dom(); ``` -Or as XML string. +Or as **XML string**. ```php $xml = $book->xml(); @@ -645,6 +645,34 @@ $xml = $book->query('//chapter')->xml(); The Expanding Universe ``` +The document can be **saved on a file** too. + +```php +$book->save('book.xml'); +``` + +As for `->xml()`, the output document can be saved without the XML declaration + +```php +$book->save('book.xml', true); +``` + +or only specific nodes can be saved. + +```php +$book->query('//chapter') + ->save('book_chapters.xml'); +``` + +Saving is fluid too. + +```php +$book->save('book.xml') + ->save('book_tidy.xml', true) + ->query('//chapter') + ->save('book_chapters.xml'); +``` + ## Importing Existing Documents diff --git a/source/FluidXml.php b/source/FluidXml.php index ac52530..9520daf 100644 --- a/source/FluidXml.php +++ b/source/FluidXml.php @@ -46,6 +46,7 @@ use \FluidXml\Core\FluidInsertionHandler; use \FluidXml\Core\FluidContext; use \FluidXml\Core\NewableTrait; +use \FluidXml\Core\SaveableTrait; use \FluidXml\Core\ReservedCallTrait; use \FluidXml\Core\ReservedCallStaticTrait; @@ -137,6 +138,7 @@ function simplexml_to_string_without_headers(\SimpleXMLElement $element) class FluidXml implements FluidInterface { use NewableTrait, + SaveableTrait, ReservedCallTrait, // For compatibility with PHP 5.6. ReservedCallStaticTrait; // For compatibility with PHP 5.6. @@ -571,6 +573,7 @@ public function setCdata($text); public function appendCdata($text); public function remove(...$xpath); public function xml($strip = false); + public function save($file, $strip = false); // Aliases: public function add($child, ...$optionals); public function prepend($sibling, ...$optionals); @@ -620,6 +623,20 @@ public static function new_(...$arguments) } } +trait SaveableTrait +{ + public function save($file, $strip = false) + { + $status = \file_put_contents($file, $this->xml($strip)); + + if (! $status) { + throw new \Exception("The file '$file' is not writable."); + } + + return $this; + } +} + class FluidDocument { public $dom; @@ -1058,6 +1075,7 @@ protected function insertIntegerFluidcontext($parent, $k, $v, $fn) class FluidContext implements FluidInterface, \ArrayAccess, \Iterator { use NewableTrait, + SaveableTrait, ReservedCallTrait, // For compatibility with PHP 5.6. ReservedCallStaticTrait; // For compatibility with PHP 5.6. diff --git a/specs/FluidXml.php b/specs/FluidXml.php index c6dd594..ed7ca86 100644 --- a/specs/FluidXml.php +++ b/specs/FluidXml.php @@ -153,6 +153,9 @@ }); describe('FluidXml', function() { + $ds = \DIRECTORY_SEPARATOR; + $this->out_dir = __DIR__ . "{$ds}..{$ds}sandbox{$ds}"; + it('should throw invoking not existing staic method', function() { try { FluidXml::lload(); @@ -188,8 +191,7 @@ }); it('should import an XML file', function() use ($doc) { - $ds = \DIRECTORY_SEPARATOR; - $file = __DIR__ . "{$ds}..{$ds}sandbox{$ds}.fixture.xml"; + $file = "{$this->out_dir}.test_load.xml"; \file_put_contents($file, $doc); $xml = FluidXml::load($file); \unlink($file); @@ -1685,6 +1687,63 @@ function addchild($parent, $i) }); }); + describe('.save', function() { + it('should be fluid', function() { + $file = "{$this->out_dir}.test_save0.xml"; + assert_is_fluid('save', $file); + \unlink($file); + }); + + it('should store the entire XML document in a file', function() { + $xml = new FluidXml(); + $xml->appendChild('parent', true) + ->appendChild('child', 'content'); + + $file = "{$this->out_dir}.test_save1.xml"; + $xml->save($file); + + $actual = \trim(\file_get_contents($file)); + $expected = "\n" + . "\n" + . " \n" + . " content\n" + . " \n" + . ""; + + \unlink($file); + + \assert($actual === $expected, __($actual, $expected)); + }); + + it('should store a fragment of the XML document in a file', function() { + $xml = new FluidXml(); + $xml->appendChild('parent', true) + ->appendChild('child', 'content'); + + $file = "{$this->out_dir}.test_save2.xml"; + $xml->query('//child')->save($file); + + $actual = \trim(\file_get_contents($file)); + $expected = "content"; + + \unlink($file); + + \assert($actual === $expected, __($actual, $expected)); + }); + + it('should throw for not writable file', function() { + $xml = new FluidXml(); + + try { + $xml->save('/.impossible/tmp/out.xml'); + } catch (\Exception $e) { + $actual = $e; + } + + assert_is_a($actual, \Exception::class); + }); + }); + describe('.add', function() { it('should be fluid', function() { assert_is_fluid('add', 'a');