
Ariadne Components: a set of simple components for the most common web application related tasks
ARC is small
biggest files are
classes
ARC is not a framework
doesn't try to be
- no routing
- no mvc
- no orm
just the bricks, none of the knitting
common abstractions across arc
functional approach where possible
$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
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', ... ]
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'

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', ... ]
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', ... ]
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
    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 );
    }
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];
            }
        }
    );
}
in reality there is a bit more code
the grants component allows you to specify grants like this:
In addition, it supports groups.
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 )
        );
    }
$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 );
$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
} 
    $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.
$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;
    }
);
still somewhat experimental
1.* focuses on small and clean code
not optimized for speed for now
ease of use also important
http://ariadne-cms.github.io/arc/
https://packagist.org/packages/arc/arc
http://github.com/ariadne-cms/arc-*/
http://slides.com/poefke/arc/