My name is Auke van Slooten
Been using PHP since 1997 (PHP 2.0)
Build a few small libraries
...and one humongous platform
Ariadne ( http://www.ariadne-cms.org/ )
ARC

Ariadne Components: a set of simple components for the most common web application related tasks
ARC Components
- arc/base
 path, tree, prototype, context
 
- arc/cache
 cache store and cache proxy
- arc/xml
 xml writer and parser
- arc/web
 url and http client
- arc/config
 
- arc/events
 
- arc/grants
 user and group rights management
ARC uses very loosely coupled components
- no reliance on other components
 
- small code size 
 ...which means less bugs
 
- dependency injection and composition 
 ...instead of inheritance
 
- no type checking but duck-typing
 ...for flexibility
 
ARC is small
biggest files are
- path - 12 methods - 300 lines
- tree - 9 methods - 230 lines
classes
- 18 static factory classes
- 40 component classes
 
ARC is not a framework
doesn't try to be
- no routing
- no mvc
- no orm
just the bricks, none of the knitting
data types first
common abstractions across arc
functional approach where possible
- arc\path
- arc\tree
arc\path
any string seperated by '/' charactersdata type not defined by class, but by its functions
$path = \arc\path::collapse( '..\\foo/./bar', '/baz/' );
// -> '/foo/bar/'
$parent = \arc\path::parent( $path );
// -> '/foo/'
$head = \arc\path::head( '/foo/bar/baz/' );
// -> 'foo'
$tail = \arc\path::tail( '/foo/bar/baz/' );
// -> /bar/baz/
$diff = \arc\path::diff( '/foo/bar/baz/', '/foo/baz/bar/' );
// -> ../baz/bar/
$path = \arc\path::map( $path, function($part) { return strrev($part); } );
// -> /oof/rab/
$path = \arc\path::reduce( $path, function( $prev, $part ) { return $prev++; } );
// -> 2
arc\tree
class with array notation for interop
$tree = [
    '/foo/'     => 'Foo',
    '/foo/bar/' => 'Foo Bar',
    '/foo/baz/' => 'Foo Baz',
    '/bar/baz/' => 'Bar Baz'
];
$root = \arc\tree::expand( $tree );
/*
    $root->nodeValue = null;
         ->childNodes = [
             'foo' => node->nodeValue = 'Foo', 
                          ->childNodes = [
                              'bar' => node->nodeValue = 'Foo Bar'
                          ]
                          ->parentNode = $root
             'bar' => node ... etc      
*/
$treeCopy = \arc\tree::collapse($root);
// -> [ '/foo/' => 'Foo', '/foo/bar/' => 'Foo Bar', ... ]
arc/tree
still (mostly) defined by functions not methods
$bar = $root->cd('/foo/bar/');
$result = \arc\tree::dive( 
    $bar, 
    function( $node ) { // going 'down'
        return ( $node->nodeName == 'foo' ) ? $node->nodeValue : null;
    },
    function( $node, $previous ) { // going back 'up'
        return $previous . ' ' . $node->nodeValue;
    }
);
// -> 'Foo Foo Bar'

arc/tree
other functions
$parents = \arc\tree::parents( $bar, function( $node ) { return $node->nodeValue; }); // -> [ '/' => null, '/foo/' => 'Foo', '/foo/bar/' => 'Foo Bar' ] $list = \arc\tree::ls( $root, function( $node ) { return $node->nodeValue; }); // -> [ '/foo/bar/' => 'Foo Bar', '/foo/baz/' => 'Foo Baz' $searchResults = \arc\tree::search( $roo, function( $node ) { if ( strpos( $node->nodeValue, 'Bar' ) !== false ) { return $node->getPath() } ); // -> '/foo/bar/' $tree2 = \arc\tree::map( $root, function($node) { return (isset($node->nodeValue) ? strtolower($node->nodeValue) : null);}); // [ '/foo/' => 'foo', '/foo/bar/' => 'foo bar', ... ]
arc/tree
other functions continued
$filtered = \arc\tree::filter( $root, function($node) {
    return ( strpos( $node->nodeValue, 'Foo' )!== false );
});
// -> [ '/foo/' => 'Foo', '/foo/bar' => 'Foo Bar', '/foo/baz/' => 'Foo Baz' ]
$reduced = \arc\tree::reduce( 
    $root, 
    function( $node, $reduced ) {
        return (isset($node->nodeValue) ? $node->nodeValue . ' ' : '');
    }, 
    ''
);
// -> 'Foo Foo Bar Foo Baz Bar Baz '
$sorted = \arc\tree::sort( $root, function( $a, $b ) {
    return ( $a->nodeValue < $b->nodeValue )
});
// -> [ '/bar/baz/' => 'Bar Baz', '/foo/' => 'Foo', '/foo/bar/' => 'Foo Bar', ... ]
Why these abstractions?
let's take a look at arc/grants
This component allows you to keep track of user rights ( grants ) 
in a tree based data structure - say a filesystem
so user 'public' has the right to see 
all contents in /foo/, but not in /bar/
$grants = \arc\grants::cd('foo')->switchUser('public')->setUserGrants('read');
$hasRead = $grants->cd('/foo/bar/')->check('read');
// -> true
$hasRead = $grants->cd('/bar/baz/')->check('read');
// -> false
The Code
    public function switchUser( $user, $groups = array() )
    {
        return new GrantsTree( $this->tree, $user, $groups );
    }
    public function setUserGrants($grants = null)
    {
        if ( isset( $grants ) ) {
            $this->tree->nodeValue['user.'.$this->user ] = ' ' . trim( $grants ) . ' ';
        } else {
            unset( $this->tree->nodeValue['user.'.$this->user ] );
        }
    }
    public function check($grant)
    {
        $grants = $this->fetchGrants();
        return ( strpos( $grants, ' '.$grant.' ')!==false );
    }
fetchGrants
private function fetchGrants()
{
    return (string) \arc\tree::dive(
        $this->tree,
        function ($node) {
            if ( isset( $node->nodeValue['user.'.$this->user] ) ) {
                return $node->nodeValue['user.'.$this->user];
            }
        }
    );
}
Ok, I lied
in reality there is a bit more code
the grants component allows you to specify grants like this:
- '=read' : only allow read access on this node, not the children
- '>read' : only allow read access on child nodes
In addition, it supports groups.
Still:
- /arc/grants.php 
 53 lines, 4 methods
- /arc/grants/GrantsTree.php
 121 lines, 8 methods
More Important:
- Almost no control structures:
 if, while, for, foreach
 
- Very low cyclomatic complexity
 
- Very easy to unit-test
 
EXAMPLES
xml writer
    function menu( $list ) {
        return \arc\xml::ul( 
            [ 'class' => 'menu' ], 
            array_map( function( $child ) {
                return \arc\xml::li( 
                    \arc\xml::a( 
                        [ 'href' => $child['url'] ] 
                        , $child['name'] 
                    )
                )
            }, $list )
        );
    }
Lambda objects
$view = \arc\lambda::prototype( [
'class' => 'menu', 'menu' => function( $children ) { return \arc\html::ul( ['class' => $this->class], array_map( $this->menuitem, (array) $children ) ); }, 'menuitem' => function( $input ) { return \arc\html::li(
\arc\html::a(
[ 'href' => $input['url'] ],
$input['name']
), ( isset( $input['children'] ) ? $this->menu( $input['children'] ) : null ) ); }, ] ); echo $view->menu( $menulist );
events
$listener = \arc\events::cd( '/test/' )
    ->listen( 'testEvent', function($event) {
        $event->data['seen'] = true;
    } );
$result = \arc\events::cd( '/test/child/' )
    ->fire( 'testEvent', array( 'seen' => false ) );
if ( $result ) {
    // event not cancelled
} 
cache proxy
    $proxy = \arc\cache::proxy( new ComplexObject(), 3600 );
    
    //first call 
    $result = $proxy->takesTooLong();
    
    //second call is cached
    $result2 = $proxy->takesTooLong();
Because of ducktyping arc accepts proxies 
wherever any other object is expected.
Caching HTTP Client
$client = \arc\http::client();
$proxy = \arc\cache::proxy( 
    \arc\http::client(),
    function($params) {
        $headers = $params['target']->responseHeaders;
        $cacheTime = getCacheTime( $headers ); // left as an exercise for the reader
        return $cacheTime;
    }
);
STATE of arc
still somewhat experimental
1.* focuses on small and clean code
not optimized for speed for now
ease of use also important
state of arc
- arc/base 90%
- 
arc/cache 90%
 
- arc/xml 60%
 parser needs ArrayAccess and DomElement methods
- arc/web 50% needs html writer and parser and http utility functions
- arc/events 90%
- arc/grants 80%
 misses owner grants and must be more extendable
- arc/config 80%
 
- 
documentation... 10%?
 
state of ARC
http://ariadne-cms.github.io/arc/
https://packagist.org/packages/arc/arc
http://github.com/ariadne-cms/arc-*/
http://slides.com/poefke/arc/
ARC - modern php components
By Auke van Slooten
ARC - modern php components
ARC is a set of modern php components geared for web applications with hierarchical (tree-based) data. ARC uses DI, composition over inheritance, duck-typing and favours small and simple code size over features.
- 2,004
 
   
   
  