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', ... ]
defines only the tree structure, not the datastill (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/