PHP Classes

FluidXML: Manipulate XML documents using a fluent interface

Recommend this page to a friend!
     
  Info   Example   View files Files   Install with Composer Install with Composer   Download Download   Reputation   Support forum   Blog    
Ratings Unique User Downloads Download Rankings
StarStarStarStar 74%Total: 260 All time: 7,813 This week: 54Up
Version License PHP version Categories
fluidxml 1.20.4BSD License5.6XML, PHP 5, Templates, Data types
Description 

Author

This package is a PHP library designed to manipulate XML documents with a concise and fluent API.

It can manipulate XML documents using a fluent interface supporting

- XML namespaces support
- XPath or CSS selectors
- Map PHP arrays to XML
- Import and export to or from DOMDocument, SimpleXMLElement, XML string

Picture of Daniele Orlando
Name: Daniele Orlando <contact>
Classes: 1 package by
Country: Italy Italy
Age: 36
All time rank: 3955160 in Italy Italy
Week rank: 132 Up1 in Italy Italy Up

Recommendations

What is the best PHP html table parser class?
Does a class exist that can process an HTML table?

Example

<?php

$DS
= DIRECTORY_SEPARATOR;
$back = '..' . $DS;
$source = __DIR__ . $DS . $back . $back . 'source';
\
set_include_path($source . PATH_SEPARATOR . \get_include_path());

////////////////////////////////////////////////////////////////////////////////


require_once 'FluidXml.php';

use \
FluidXml\FluidXml;
use \
FluidXml\FluidNamespace;
use function \
FluidXml\fluidxml;
use function \
FluidXml\fluidns;
use function \
FluidXml\fluidify;

/*****************************
 * Creating An XML Document. *
******************************/

$book = new FluidXml('book');
// or
$book = new FluidXml(null, ['root' => 'book']);

// $book is an XML document with 'book' as root node.

// The default options are:
// [ 'root' => 'doc', // The root node of the document.
// 'version' => '1.0', // The version for the XML header.
// 'encoding' => 'UTF-8', // The encoding for the XML header.
// 'stylesheet' => null ]; // An url pointing to an XSL file.

$booksheet = new FluidXml('book', ['stylesheet' => 'http://domain.com/style.xsl']);
// With PHP 7 this is valid too:
// $booksheet = FluidXml::new('book', ['stylesheet' => 'http://domain.com/style.xsl']);

$book->setAttribute('type', 'science') // It sets an attribute of the root node ('book').
    
->addChild([ 'title' => 'The Theory Of Everything',
                    
'author' => 'S. Hawking' ]); // It creates two nodes, each one with some text inside.

echo $book->xml(); // Exports the xml document as a string.
echo "????????????????????????????????????????????????????????????????????????????????\n";



/**********************
 * Context Switching. *
***********************/

/*
* Passing a 'true' boolean value to any method that performs an insertion of a node,
* returns the newly created node instead of the parent.
* This operation is called Context Switch.
* Methods that support this context switch are:
* - addChild($child, ...$optionals);
* - prependSibling($sibling, ...$optionals);
* - appendSibling($sibling, ...$optionals);
* and their alias methods (of course).
*/

$book->addChild('chapters', true) // true forces the return of the 'chapters' node.
       
->addChild('chapter', 'Ideas About The Universe', ['id' => 123, 'first' => ''])
        ->
addChild('chapter', 'The Expanding Universe', ['id' => 321])
        ->
addChild('chapter', 'Black Holes', ['id' => 432])
        ->
addChild('chapter', 'Black Holes Ain\'t So Black', ['id' =>234]);



/********************
 * Appending Nodes. *
*********************/

/*
* Inserting a node can be performed in different ways,
* each one with its pros and cons.
*/

/*
* In this examples, it is used the concise syntax, but the same concepts
* are applicable to the standard syntax.
*/

$food = fluidxml('food');

$food->add('fruit') // A 'fruit' node with an empty content.
    
->add('fruit', 'orange'); // A 'fruit' node with 'orange' as content.

// A node can have even a bunch of attributes.
$food->add('fruit', 'apple', [ 'price' => 'expensive',
                              
'color' => 'red' ]);

// Batch insertion of nodes.
$food->add([ 'cake' => 'Tiramisu',
            
'pizza' => 'Margherita' ]);

// PHP arrays can't contain identical keys.
// But it's still possible to create, in a batch operation, nodes with the same tag.
$food->add([ [ 'pasta' => 'Carbonara' ],
             [
'pasta' => 'Matriciana' ] ]);

// A bunch of egg's all with the same price.
$food->add([ ['egg'], ['egg'], ['egg'] ], ['price' => '0.25']);

// Complex array structures are supported too.
$food->add([ 'menu' => [
                
'pasta' => [
                    
'spaghetti' => [
                        
'@id' => '123',
                        
'@country' => 'Italy',
                        
'@' => 'Spaghetti are an Italian dish...',

                        
'variants' => [
                            
'tomato' => [ '@type' => 'vegan' ],
                            
'egg' => [ '@type' => 'vegetarian' ] ]]]]]);

echo
$food->xml();
echo
"????????????????????????????????????????????????????????????????????????????????\n";



/*************************
 * Importing XML strings.*
**************************/

/*
* Raw XML/XHTML strings che be injected at any point of the document too.
*/

$book->add('cover', true)
        ->
add(<<<XML
<h1>The Theory Of Everything</h1>
                <img src="http://goo.gl/kO3Iov"/>
XML
);


/*
* The document can be filled with a raw XML string.
*/
$html = fluidxml(null);
$html->add(<<<XML
<html>
    <head>
        <meta/>
    </head>
    <body>
        <p/>
    </body>
</html>
XML
);


/*
* Sometimes XML/XHTML comes from legacy templating systems or external sources.
*/

$string = $html->xml();
// XML string import.
$fluid = fluidxml($string);
echo
$fluid->xml();
echo
"????????????????????????????????????????????????????????????????????????????????\n";


$dom = new DOMDocument();
$dom->loadXML($fluid->xml());
$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;
// DOMDocument import.
$fluid = fluidxml($dom);
echo
$fluid->xml();
echo
"????????????????????????????????????????????????????????????????????????????????\n";


$simplexml = new SimpleXMLElement($fluid->xml());
// SimpleXMLElement import.
$fluid = fluidxml($simplexml);
echo
$fluid->xml();
echo
"????????????????????????????????????????????????????????????????????????????????\n";


// XML file import.
// $fluid = fluidify('path/to/file.xml');

$other = fluidxml($fluid->xml());
$fluid = fluidxml();

$fluid->add($other) // Imports a FluidXml instance.
     
->add([ 'query' => $fluid->query('//meta'), // Imports a FluidXml query.
             
'dom' => $dom, // Imports a DOMDocument.
             
'domnodes' => $dom->childNodes, // Imports a DOMNodeList.
             
'simplexml' => $simplexml ]); // Imports a SimpleXMLElement.



/******************
 * XPath Queries. *
*******************/

/*
* XPath queries can be absolute or relative to the context over they are executed.
*/

$eggs = $food->query('//egg');
$fruits = $food->query('//fruit[@price="expensive"]');

echo
"We have {$eggs->length()} eggs and {$fruits->length()} expensive fruit.\n";
echo
"????????????????????????????????????????????????????????????????????????????????\n";

$book->query('//chapter')
        ->
attr('lang', 'en')
     ->
query('..')
        ->
attr('lang', 'en')
     ->
query('../title')
        ->
attr('lang', 'en');

/*
* The previous code presents a repetition: all 'setAttribute' calls are identical.
* It can be refactored taking advantage of an advanced feature of 'query'.
*/
$book->query('//chapter', '//chapters', '/book/title')
        ->
attr('lang', 'en');



/*******************************
 * Accessing The Node Content. *
********************************/

/*
* The result of a query can be accessed even as array.
* Accessing the result of a query as array performs the unwrapping of the node
* and returns a raw instance of DOMNode.
* You loose the FluidXML interface but gain direct access to the DOMNode apis.
*/

$chapters = $book->query('//chapter');

$l = $chapters->length();

// DOMNode access.
$chapters[0]->setAttribute('first', '');
$chapters[$l - 1]->setAttribute('last', '');

/*
* The previous ->setAttribute is the DOMNode::setAttribute.
* not the FluidXml::setAttribute().
* Many other methods/properties are available like:
* - hasAttribute()
* - getAttribute()
* - nodeValue
* See http://php.net/manual/en/class.domnode.php for the reference documentation.
*/

echo $book->xml();
echo
"????????????????????????????????????????????????????????????????????????????????\n";

/*
* Because the result of a query behaves like an array, it can be iterated too.
*/
foreach ($chapters as $i => $chapter) {
       
// $chapter is an instance of DOMNode.

       
$title = $chapter->nodeValue;
       
$id = $chapter->getAttribute('id');
       
$has_first_attr = $chapter->hasAttribute('first');

        if (
$has_first_attr) {
                echo
"The first chapter has title '{$title}' with id '{$id}'.\n";
        } else {
               
$ii = $i + 1;
                echo
"Chapter {$ii} has title '{$title}' with id '{$id}'.\n";
        }
}

/*
* To retrieve all DOMNode in one operation there is the ->asArray() method.
*/
$chapters_nodes = $chapters->array(); // Returns an array of DOMNode.

echo "????????????????????????????????????????????????????????????????????????????????\n";



/***************
 * Namespaces. *
 ***************/


/*
* To use a namespace you have to register its identifier together with its uri.
*/

$xhtml = fluidns('xhtml', 'http://www.w3.org/1999/xhtml');
$book->namespace($xhtml)
     ->
namespace('svg', 'http://www.w3.org/2000/svg')
     ->
namespace('xsl', 'http://www.w3.org/TR/xsl', FluidNamespace::MODE_IMPLICIT)
     ->
add('xhtml:h1')
     ->
add([ 'xsl:template' => [ 'xsl:variable' ] ])
     ->
query('//xhtml:h1')
     ->
add('svg:shape');

echo
$book->xml();
echo
"????????????????????????????????????????????????????????????????????????????????\n";



/*******************
 * Removing Nodes. *
 *******************/

$food->remove('//egg'); // Removes all the eggs.

// Which is the same of
// $food->query('//egg')->remove(); // Removes all the eggs using a query.
// $food->query('/doc')->remove('egg'); // Removes all the eggs using a relative XPath.

/* ->remove(...$xpath)
 * accepts the same arguments of
 * ->query(...$xpath)
 * Remember that, like `->query()`, even `->remove()` accepts multiple XPath strings.
 */
$food->remove('//fruit', '//cake', '//pasta', '//pizza');

echo
$food->xml();
echo
"????????????????????????????????????????????????????????????????????????????????\n";


Details

[apis]: https://github.com/servo-php/fluidxml/wiki/APIs [gettingstarted]: https://github.com/servo-php/fluidxml/wiki/Getting-Started [examples]: https://github.com/servo-php/fluidxml/blob/master/documents/Examples/ [specs]: https://github.com/servo-php/fluidxml/blob/master/specs/FluidXml.php [wiki]: https://github.com/servo-php/fluidxml/wiki [bsd]: https://opensource.org/licenses/BSD-2-Clause [license]: https://github.com/servo-php/fluidxml/blob/master/documents/License.txt [changelog]: https://github.com/servo-php/fluidxml/blob/master/documents/Changelog.txt [codecoverage]: https://bytebucket.org/daniele_orlando/bithosting/raw/master/FluidXML_code_coverage.png [donate-button]: https://bytebucket.org/daniele_orlando/bithosting/raw/master/Donate_button.png [donate-link]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UUBXYHQRVJE28 [donate-link-alt]: https://www.paypal.me/danieleorlando [ninja]: http://1.viki.io/d/1863c/8b75dc48c9.gif [thankyou]: https://upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Heart_corazón.svg/2000px-Heart_corazón.svg.png

[packagist]: https://packagist.org/packages/servo/fluidxml [travis]: https://travis-ci.org/servo-php/fluidxml [scrutinizer]: https://scrutinizer-ci.com/g/servo-php/fluidxml/?branch=master [coveralls]: https://coveralls.io/github/servo-php/fluidxml?branch=master [codeclimate]: https://codeclimate.com/github/servo-php/fluidxml [codeship]: https://codeship.com/projects/129206 [circle]: https://circleci.com/gh/servo-php/fluidxml

[packagist-license-badge]: https://poser.pugx.org/servo/fluidxml/license [packagist-release-badge]: https://poser.pugx.org/servo/fluidxml/v/stable [packagist-downloads-badge]: https://poser.pugx.org/servo/fluidxml/downloads [packagist-license-badge-alt]: https://img.shields.io/packagist/l/servo/fluidxml.svg?style=flat-square [packagist-release-badge-alt]: https://img.shields.io/packagist/v/servo/fluidxml.svg?style=flat-square [packagist-downloads-badge-alt]: https://img.shields.io/packagist/dt/servo/fluidxml.svg?style=flat-square [travis-build-badge]: https://travis-ci.org/servo-php/fluidxml.svg?branch=master [scrutinizer-coverage-badge]: https://scrutinizer-ci.com/g/servo-php/fluidxml/badges/coverage.png?b=master [scrutinizer-quality-badge]: https://scrutinizer-ci.com/g/servo-php/fluidxml/badges/quality-score.png?b=master [coveralls-coverage-badge]: https://coveralls.io/repos/github/servo-php/fluidxml/badge.svg?branch=master [codeclimate-quality-badge]: https://codeclimate.com/github/servo-php/fluidxml/badges/gpa.svg [codeship-build-badge]: https://codeship.com/projects/8f977260-a359-0133-4946-1ac8bff03ae9/status?branch=master [circle-build-badge]: https://circleci.com/gh/servo-php/fluidxml.svg?style=svg

[![Travis Build][travis-build-badge]][travis] [![Coveralls Coverage][coveralls-coverage-badge]][coveralls] [![Scrutinizer Quality][scrutinizer-quality-badge]][scrutinizer] [![Code Climate Quality][codeclimate-quality-badge]][codeclimate]

[![Packagist License][packagist-license-badge]][packagist] [![Packagist Last Release][packagist-release-badge]][packagist] [![Packagist Total Downloads][packagist-downloads-badge]][packagist]

Changelog

1.20.3 (2016-07-12): _fixes wrong handling of null/empty node value._

...

[The full changes list.][changelog]

<br/>

<a href='https://ko-fi.com/2216WXOPLSZER' target='_blank'> <img height='32' src='https://az743702.vo.msecnd.net/cdn/kofi5.png?v=a' border='0' alt='Buy Me a Coffee at ko-fi.com'/> </a>

FluidXML

<img src="https://bytebucket.org/daniele_orlando/bithosting/raw/master/Servo_logo.png" height="64px" alt="Servo-PHP Logo"/> <span>      </span> <img src="https://bytebucket.org/daniele_orlando/bithosting/raw/master/Fluidxml_logo.png" height="64px" alt="FluidXML Logo"/>

FluidXML is a PHP library designed to manipulate XML documents with a concise and fluent API.<br/> It leverages the fluent programming pattern to be fun and effective.

$book = fluidxml();

$book->add('title', 'The Theory Of Everything')
     ->add('author', 'S. Hawking')
     ->add('chapters', true)
         ->add('chapter', 'Ideas About The Universe', ['id' => 1])
         ->add('chapter', 'The Expanding Universe',   ['id' => 2]);

Or, if you prefer, there is an extended syntax.

$book = new FluidXml();

$book->addChild('title', 'The Theory Of Everything')
     ->addChild('author', 'S. Hawking')
     ->addChild('chapters', true)
         ->addChild('chapter', 'Ideas About The Universe', ['id' => 1])
         ->addChild('chapter', 'The Expanding Universe',   ['id' => 2]);

With FluidXML the DOM manipulation becomes fast, clear and expressive.

PHP Arrays are first class citizens.

$book->add([ 'title'  => 'The Theory Of Everything',
             'author' => 'S. Hawking',
             'chapters' => [
                    [ 'chapter' => [
                            '@id' => '1',
                            '@'   => 'Ideas About The Universe' ] ],
                    [ 'chapter' => [
                            '@id' => '2',
                            '@'   => 'The Expanding Universe' ] ],
           ]]);

echo $book;

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <title>The Theory Of Everything</title>
  <author>S. Hawking</author>
  <chapters>
    <chapter id="1">Ideas About The Universe</chapter>
    <chapter id="2">The Expanding Universe</chapter>
  </chapters>
</doc>

XPath is king.

$book->query('//title', '//author', '//chapter')
        ->attr('lang', 'en');

And CSS Selectors rock.

$book->query('#id', '.class1.class2', 'div p > span')
        ->attr('lang', 'en');

// Many other selectors are available.

XML/CSS Namespaces are fully covered.

$book->namespace('xhtml', 'http://www.w3.org/1999/xhtml')
     ->add('xhtml:h1')
     ->query('//xhtml:h1')  // XPath namespace.
     ->query('xhtml|h1');   // CSS namespace.

And sometimes XML Fragments are the fastest way.

$book->add(<<<XML
    <cover class="front">
        <img src="http://goo.gl/kO3Iov"/>
    </cover>
    <cover class="back">
        <img src="http://goo.gl/kO3Iov"/>
    </cover>
XML
);

Everything is fluent, even iterations.

$book->query('//chapter')
        ->each(function ($i) {
             $this->attr('id', $i);
        });

$book->query('//chapters')
        ->times(3)
            ->add('chapter')
        ->times(4, function ($i) {
            $this->add('chapter');
            $this->add('illustration');
        });

Whether some queries are too complex to express with XPath/CSS,<br/> filtering is your friend.

$book->query('//chapters')
        ->filter(function ($i, $node) {
            return $i % 2 === 0;
        })
        ->attr('even');

Interoperability with existing DOMDocument and SimpleXML is simply magic.<br/> Import them or inject them in any point of the FluidXML flow just like that.

fluidxml($domdocument)
    ->query('/html/body')
         ->add($simplexml);

// Yes, we merged a DOMDocument with a SimpleXMLElement
// and everything is still fluid.

Don't be shy and tell it: « IT'S AWESOME! » ^\_^

Many other [APIs][apis] are available: - __invoke() - append()/appendSibling() - prepend()/prependSibling() - addText() - text()/setText() - addCdata() - cdata()/setCdata() - addComment() - comment()/setComment() - remove() - size()/length() - load() - save() - dom() - xml() - html() - __toString() - array() - ...

Still doubts?

FluidXML is fun to use, concise and effective.

If it's not enough, it has a comprehensive test suite with a 100% code coverage.

But you'll have the best answer trying it yourself.

![100% Code Coverage][codecoverage]

Requirements

  • PHP 5.6

Installation

  • Cloning the repository:
git clone https://github.com/servo-php/fluidxml.git

  • Using Composer:
composer require servo/fluidxml

Getting Started

  • Cloning the repository:
require_once 'FluidXml.php';

  • Using Composer:
require_once 'vendor/autoload.php';

use classes and functions as you need.

use function \FluidXml\fluidxml;
use function \FluidXml\fluidns;
use function \FluidXml\fluidify;
use \FluidXml\FluidXml;
use \FluidXml\FluidNamespace;

See the documentation to get started and become a [ninja][ninja].

Documentation

_10 minutes reading_<br/> Follow the [Getting Started tutorial][gettingstarted] to become a [ninja][ninja] in no time.

Many other examples are available: - inside the [documents/Examples/][examples] folder - inside the [specs/FluidXml.php][specs] file (as test cases)

All them cover from the simplest case to the most complex scenario.

Take a look at the [APIs][apis] to discover all the available manipulation operations,<br/> and go to the [Wiki Page][wiki] for more reading.

Donation

If you think this code is awesome or if you want to demonstrate<br/> your immense gratitude [?][thankyou], _buy me a coffe_.

<a href='https://ko-fi.com/2216WXOPLSZER' target='_blank'>

<img height='32' src='https://az743702.vo.msecnd.net/cdn/kofi5.png?v=a' border='0' alt='Buy Me a Coffee at ko-fi.com'/>

</a>

[//]: # ([![Donate][donate-button]][donate-link]<br/>) [//]: # (1$ or more<span style="color: gray;">, due to the PayPal fees.</span>)

<a-off href='https://pledgie.com/campaigns/30607'>

<img-off alt='Click here to lend your support to: FluidXML and make a donation at pledgie.com !' src='https://pledgie.com/campaigns/30607.png?skin_name=chrome' border='0'/>

</a-off>

Roadmap

  • [x] PHP 5.6 backport
  • [ ] Extending the documentation
  • [ ] Expanding the APIs

Author

Daniele Orlando &lt;fluidxml@danieleorlando.com&gt;

License

FluidXML is licensed under the [BSD 2-Clause License][bsd].

See [documents/License.txt][license] for the details.


  Files folder image Files (55)  
File Role Description
Files folder imagedocuments (5 files, 1 directory)
Files folder imagesource (1 file, 1 directory)
Files folder imagespecs (2 files)
Files folder imagesupport (12 files, 1 directory)
Accessible without login Plain text file .codeclimate.yml Data Auxiliary data
Accessible without login Plain text file .coveralls.yml Data Auxiliary data
Accessible without login Plain text file .editorconfig Data Auxiliary data
Accessible without login Plain text file .scrutinizer.yml Data Auxiliary data
Accessible without login Plain text file .travis.yml Data Auxiliary data
Accessible without login Plain text file .vimrc Data Auxiliary data
Accessible without login Plain text file circle.yml Data Auxiliary data
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file README.md Data Auxiliary data

  Files folder image Files (55)  /  documents  
File Role Description
Files folder imageExamples (1 file)
  Accessible without login Plain text file APIs.md Data Auxiliary data
  Accessible without login Plain text file Changelog.txt Doc. Documentation
  Accessible without login Plain text file Getting-Started.md Data Auxiliary data
  Accessible without login Plain text file License.txt Doc. Documentation
  Accessible without login Plain text file ReadMe.md Data Auxiliary data

  Files folder image Files (55)  /  documents  /  Examples  
File Role Description
  Accessible without login Plain text file 00_Intro.php Example Example script

  Files folder image Files (55)  /  source  
File Role Description
Files folder imageFluidXml (15 files)
  Plain text file FluidXml.php Class Class source

  Files folder image Files (55)  /  source  /  FluidXml  
File Role Description
  Plain text file CssTranslator.php Class Class source
  Plain text file fluid.php Class Class source
  Plain text file FluidAliasesTrait.php Class Class source
  Plain text file FluidContext.php Class Class source
  Plain text file FluidDocument.php Class Class source
  Plain text file FluidHelper.php Class Class source
  Plain text file FluidInsertionHandler.php Class Class source
  Plain text file FluidInterface.php Class Class source
  Plain text file FluidNamespace.php Class Class source
  Plain text file FluidRepeater.php Class Class source
  Plain text file FluidSaveTrait.php Class Class source
  Plain text file FluidXml.php Class Class source
  Plain text file NewableTrait.php Class Class source
  Plain text file ReservedCallStaticTrait.php Class Class source
  Plain text file ReservedCallTrait.php Class Class source

  Files folder image Files (55)  /  specs  
File Role Description
  Accessible without login Plain text file .common.php Test Unit test script
  Accessible without login Plain text file FluidXml.php Test Unit test script

  Files folder image Files (55)  /  support  
File Role Description
Files folder imagetools (10 files)
  Accessible without login Plain text file circle.yml Data Auxiliary data
  Accessible without login Plain text file codeclimate.yml Data Auxiliary data
  Accessible without login Plain text file Codevelox.php Test Unit test script
  Accessible without login Plain text file composer.json Data Auxiliary data
  Accessible without login Plain text file coveralls.php Aux. Auxiliary script
  Accessible without login Plain text file coveralls.yml Data Auxiliary data
  Accessible without login Plain text file editorconfig Data Auxiliary data
  Accessible without login Plain text file peridot.php Conf. Configuration script
  Accessible without login Plain text file scrutinizer.yml Data Auxiliary data
  Accessible without login Plain text file speedtest.php Test Unit test script
  Accessible without login Plain text file travis.yml Data Auxiliary data
  Accessible without login Plain text file vimrc Data Auxiliary data

  Files folder image Files (55)  /  support  /  tools  
File Role Description
  Accessible without login Plain text file .common.sh Data Auxiliary data
  Accessible without login Plain text file coverage Data Auxiliary data
  Accessible without login Plain text file coveralls Data Auxiliary data
  Accessible without login Plain text file gendoc Data Auxiliary data
  Accessible without login Plain text file init Data Auxiliary data
  Accessible without login Plain text file speedtest Data Auxiliary data
  Accessible without login Plain text file test Data Auxiliary data
  Accessible without login Plain text file testd Data Auxiliary data
  Accessible without login Plain text file testdbg Data Auxiliary data
  Accessible without login Plain text file testv Data Auxiliary data

The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page.
Install with Composer Install with Composer
 Version Control Unique User Downloads Download Rankings  
 100%
Total:260
This week:0
All time:7,813
This week:54Up
 User Ratings  
 
 All time
Utility:83%StarStarStarStarStar
Consistency:83%StarStarStarStarStar
Documentation:83%StarStarStarStarStar
Examples:83%StarStarStarStarStar
Tests:83%StarStarStarStarStar
Videos:-
Overall:74%StarStarStarStar
Rank:83