PHP code example of lark / framework

1. Go to this page and download the library: Download lark/framework library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

lark / framework example snippets


// bootstrap
// ...

// define routes
router()
    // get([route], [action])
    ->get('/', function() {});

// run app
app()->run();

// routes for HTTP specific methods:
router()->delete('/route', function(){});
router()->get('/route', function(){});
router()->head('/route', function(){});
router()->options('/route', function(){});
router()->patch('/route', function(){});
router()->post('/route', function(){});
router()->put('/route', function(){});

// route for all HTTP methods
router()->all('/route', function(){});

// route for multiple HTTP methods
router()->route(['GET', 'POST'], '/route', function(){});

// a wildcard route "*" can be used to match any route
router()->get('*', function(){}); // all HTTP GET methods
router()->all('*', function(){}); // all HTTP methods (all requests)
router()->route(['GET', 'POST'], '*', function(){}); // all HTTP GET and POST methods

// match all routes that begin with "/api"
router()->get('/api.*?', function(){});

router()
    ->group('/api/users') // group([base-route])
    ->get('/', function(){}) // "/api/users"
    ->get('/active', function(){}); // "/api/users/active"

// bootstrap routes directory
// ...

router()->load([
    // [base-route] => [file]
    '/api/users' => 'users'
]);

// in routes directory file "users.php" defines routes
// the group('/api/users') method does not need to be called (handled by load() method)
router()
    ->get('/', function(){}) // "/api/users"
    ->get('/active', function(){}); // "/api/users/active"

// incorrect:
router()->bind(function(){});
router()->get('/', function(){});
// correct:
router()
    ->bind(function(){})
    ->get('/', function(){});

class MyController implements Lark\Router\RouteControllerInterface
{
    public function bind(Router $router): void
    {
        $router->get('/users', function(){}); // "/api/users"
    }
}

// in routes file
router()
    ->group('/api')
    ->controller(new MyController);

// function will be called on route match
router()->get('/example-html', function(): string {
    return 'hello'; // return string to output as html
});

router()->get('/example-json', function(): array {
    return ['message' => 'hello']; // return array|stdClass to output as JSON
    // will auto add header "Content-Type: application/json"
    // and response body will be:
    // {"message": "hello"}
});

// class method "App\Controller\ExampleController::hello()" will be called on route match
router()->get('/example2', [App\Controller\ExampleController::class, 'hello']);

router()->notFound(function(string $requestMethod, string $requestPath){});

router()->get('/users/{id}', function($id){});

router()->get('/users/{id}/{groupId?}', function($id, $groupId = null){});

// match digits
router()->get('/users/(\d+)', function(int $id){});
// or match alphanumeric with length of 8
router()->get('/users/([a-z0-9]{8})', function(string $id) {});

// executed always
router()->bind(function(Lark\Request $req, Lark\Response $res){});
// executed if any route is matched
router()->matched(function(Lark\Request $req, Lark\Response $res){});

// define routes
// ...

// single action
router()->bind(function(){});
// multiple actions
router()->bind(function(){}, [MyClass::class, 'myMethod']);
// array of actions
router()->bind([
    function(){},
    function(){}
]);

// method([methods], [route], [...actions])
router()->map(['GET'], '/api.*?', function(){});

router()->get('/api/users', function(){});

router()
    // group([base-route], [...actions])
    ->group('/api/users', function(){})
    ->get('/', function(){}) // "/api/users"
    ->get('/{id}', function($id){}) // "/api/users/{id}"

router()->after(function(){}, [MyClass::class, 'myMethod']);

logger('channel')->critical('message', [context]);
logger('channel')->debug('message', [context]);
logger('channel')->error('message', [context]);
logger('channel')->info('message', [context]);
logger('channel')->warning('message', [context]);

// bootstrap log handler
app()->logHandler = new App\LogHandler;
Lark\Logger::handler(app()->logHandler);

// ...

// log info level record
logger('user')->info('User has been authorized', ['userId' => $user->id]);

// ...

// output log example
print_r( app()->logHandler->close() );

Lark\Logger::globalContext(['sessionId' => $session->id]);
// ...
logger('user')->info('User has signed out', ['userId' => $user->id]);
// context is: ['sessionId' => x, 'userId' => y]

// bootstrap
// ...

// define routes
// ...

try
{
    // run app
    app()->run();
}
catch (Throwable $th)
{
    new App\ExceptionHandler($th);
}

namespace App;
use Throwable;
class ExceptionHandler
{
    public function __construct(Throwable $th)
    {
        \Lark\Exception::handle($th, function (array $info) use ($th)
        {
            $code = $th->getCode();
            if (!$code)
            {
                $code = 500;
            }

            // log error
            // ...

            // respond with error
            res()
                ->code($code)
                ->json($info);

            // --or-- continue to throw exception
            throw $th;
        });
    }
}

use Lark\Debugger;

// append debugger info
Debugger::append(['some' => 'info'])
    ->name('Test info') // this will be displayed as title (optional)
    ->group('test'); // this will group info together (optional)

Debugger::append(['more' => 'info'])
    ->name('More test info')
    ->group('test');

Debugger::dump(); // dump all debugger info and exit
// or use:
// x(); // dump all debugger info and exit

app()->use('debug.dump', true);

app()->use('debug.log', true);

// setup default MongoDB database connection with connectionId "default"
// the first registered connection is always the default connection
// regardless of connectionId
app()->use('db.connection.default', [
    'hosts' => ['127.0.0.1'],
    'username' => 'test',
    'password' => 'secret',
    'replicaSet' => 'rsNameHere', // (optional)
    // options can override any global database options
    // (optional, see "Database Global Options" below)
    'options' => []
]);

// register second connection with connectionId "myconn"
app()->use('db.connection.myconn', [...]);

// ...

// use default connection (no connectionId 

use MongoDB\Driver\ReadConcern;
use MongoDB\Driver\WriteConcern;

app()->use('db.options', [
    'db.allow' => [], // allow access to only specific databases
    'db.deny' => ['admin', 'config', 'local'], // restrict access to databases
    'debug.dump' => false, // will write concern
]);

app()->use('db.session', new App\Model\Session);

app()->use('validator.rule.string.beginWithEndWith', App\Validator\BeginWithEndWith::class);

$path = env('PATH');

// or use default value "/my/path" if environment variable does not exist
$path2 = env('PATH2', '/my/path');

// for  variable key "PATH2"

// load from file (bootstrap)
Lark\Env::getInstance()->load(DIR_ROOT . '/.env');

$dbUser = env('DB_USER'); // myuser
$dbPassword = env('DB_PWD'); // secret

// example request:
// POST /example
// Content-Type: application/json
// {"name": "Test", "contact": {"email": "[email protected]"}}
$data = req()->json(); // get all as object/array (no auto sanitizing)

// request JSON must be an array or 400 response is sent
$data = req()->jsonArray();
// request JSON must be an object or 400 response is sent
$data = req()->jsonObject();

// get individual field
$name = req()->jsonField('name')->string();
if(req()->jsonField('contact.email')->has())
{
    $email = req()->jsonField('contact.email')->email();
}

if(req()->isMethod('POST'))
{
    $name = req()->input('name')->string();
    if(req()->input('email')->has())
    {
        $email = req()->input('email')->email();
    }
}

// request "/?id=5&name=Shay"
print_r([
    'id' => req()->query('id')->integer(),
    // use "default" as value if query "name" does not exist
    'name' => req()->query('name', 'default')->string()
]); // Array ( [id] => 5 [name] => Shay )

if(req()->cookie('myCookie')->has())
{
    var_dump( req()->cookie('myCookie')->string() );
}

app()->session->set('user.id', 5); // creates session data: [user => [id => 5]]
// ...
if(app()->session->has('user.id'))
{
    $userId = app()->session->get('user.id');
}

app()->session()->flash()->set('userError', 'Invalid session');
// redirect, then use message
echo app()->session()->flash()->get('userError');
// message is no longer available on next request

// set header, status code 200, content-type and send JSON response
res()
    ->header('X-Test', 'value')
    ->code(Lark\Response::HTTP_OK)
    ->contentType('application/json') // not 

// bootstrap
// setup default MongoDB database connection with connectionId "default"
app()->use('db.connection.default', [...]);

// register second connection with connectionId "myconn"
app()->use('db.connection.myconn', [...]);

// ...

// get Database object instance
$db = db('myDb$users');

// insert documents
$docIds = $db->insert([
    ['name' => 'Test', 'role' => 'admin'],
    ['name' => 'Test2', 'role' => 'admin']
]);
// Array ( [0] => 62ba4fd034faaf6fc132ef54 [1] => 62ba4fd034faaf6fc132ef55 )

// insert single document
$docId = $db->insertOne(['name' => 'Test3', 'role' => 'readonly']);

// find documents
$docs = $db->find(['role' => 'admin']);
// Array ( [0] => Array ( [id] => 62ba4fd034faaf6fc132ef54 [name] => Test [role] => admin )
// [1] => Array ( [id] => 62ba4fd034faaf6fc132ef55 [name] => Test2 [role] => admin ) )

// find documents with "name" staring with "Test"
$docs = $db->find(['name' => ['$regex' => '^Test']]);

// find documents by IDs
$docs = $db->findIds(['62ba4fd034faaf6fc132ef54', '62ba4fd034faaf6fc132ef55']);

// find single document
$doc = $db->findOne(['name' => 'Test2']);

// find single document by ID
$doc = $db->findId('62ba4fd034faaf6fc132ef54');

// update documents
$affected = $db->update(['role' => 'admin'], ['role' => 'admin2']);

// update bulk
$docIds = $db->updateBulk([
    ['id' => '62ba4fd034faaf6fc132ef55', 'role' => 'admin'],
    [...]
]);
// Array ( [0] => 62ba4fd034faaf6fc132ef55 [1] => ... )

// update single document by ID
$newDoc = $db->updateId('62ba4fd034faaf6fc132ef55', ['role' => 'admin2']);

// update single document
$newDoc = $db->updateOne(['name' => 'Test2'], ['role' => 'admin']);

// increment visits by 1
$newDoc = $db->updateOne(['name' => 'Test2'], ['visits' => 1], operator: '$inc');

// replace bulk
$docIds = $db->replaceBulk([
    ['id' => '62ba4fd034faaf6fc132ef55', 'name' => 'Test222'],
    [...]
]);
// Array ( [0] => 62ba4fd034faaf6fc132ef55 [1] => ... )

// replace single document by ID
$newDoc = $db->replaceId('62ba4fd034faaf6fc132ef55',
    ['name' => 'Test2222', 'role' => 'admin']);

// replace single document
$newDoc = $db->replaceOne(['name' => 'Test2222'], ['name' => 'Test2', 'role' => 'admin']);

// delete documents (note: filter cannot be empty)
$affected = $db->delete(['role' => 'admin']);

// delete documents by IDs
$affected = $db->deleteIds(['62ba4fd034faaf6fc132ef54', '62ba4fd034faaf6fc132ef55']);

// delete single document
$affected = $db->deleteOne(['name' => 'Test2']);

// delete all documents in collection
$affected = $db->deleteAll();

// create a new field
// set default value to empty array
$affected = $db->collectionField('tags')->create([]);

// delete a field
$affected = $db->collectionField('tags')->delete();

// check if a field exists on all documents
$exists = $db->collectionField('tags')->exists();

// check if a field exists on any document
$exists = $db->collectionField('tags')->exists(false);

// remove value "mytag" from field "tags" array
$affected = $db->collectionField('tags')->pull(
    ['id' => '62ba4fd034faaf6fc132ef54'],
    'mytag'
);

// append values "mytag1" and "mytag2" to field "tags" array
// these values will only be appended if they
// don't already exists in the array
// use $unique=false to always append
$affected = $db->collectionField('tags')->push(
    ['id' => '62ba4fd034faaf6fc132ef54'],
    ['mytag1', 'mytag2']
);

// rename a field
$affected = $db->collectionField('tags')->rename('tagsNew');

use Lark\Schema;
$schema = new Schema([
    // create an index when creating a database collection
    '$index' => [
        'name' => 1, 'age' => 1, '$name' => 'idxNameAge'
    ],
    // or create multiple indexes
    // '$indexes' => [
    //    ['username' => 1, '$name' => 'idxUsername', '$unique' => true],
    //    ['name' => 1, 'age' => 1, '$name' => 'idxNameAge']
    // ],

    // auto database projection (filter password by default)
    '$filter' => ['password' => 0],

    // schema fields
    'name' => ['string', 'notEmpty'],
    'username' => ['string', 'notEmpty'],
    'password' => ['string', 'notEmpty'],
    'age' => ['int', 'notEmpty'],
    'isAdmin' => ['bool', 'notNull', ['default' => false]]
]);

$schema->default('isAdmin', false);

$schema->apply('name', function($name): string {
    return strtoupper($name);
});


return [
    'object',
    [
        'fields' => [
            'age' => 'int',
            'tags' => 'array'
        ]
    ]
];

$schema = new Schema([
    '$import' => [
        // field => file (in schemas directory)
        'info' => 'partials/users.info'
    ],
    'name' => ['string', 'notEmpty'],
    // field for schema import (optional, does not need to be set here)
    'info' => null
]);

$schema = new Schema([
    '$import' => [
        // field => file (in schemas directory)
        'info.1.fields' => 'partials/users.info'
    ],
    'name' => ['string', 'notEmpty'],
    'info' => [
        'object',
        ['fields' => null]
    ]
]);


return [
    'age' => 'int',
    'tags' => 'array'
];

namespace App\Model;
use App\Model;
use Lark\Schema;

class User extends Model
{
    const DBS = 'default$app$users';
    public static function &schema(): Schema
    {
        return parent::schema([
            'name' => ['string', 'notEmpty'],
            'age' => ['int', 'notEmpty'],
            'isAdmin' => ['bool', 'notNull', ['default' => false]]
        ]);
    }
}

$user = (new App\Model\User)->make([
    'name' => 'Bob',
    'age' => 25
]);
var_dump($user);
// array(3) { ["name"]=> string(3) "Bob" ["age"]=> int(25) ["isAdmin"]=> bool(false) }

// or an array can be used
$user = (new App\Model\User)->makeArray([
    ['name' => 'Bob', 'age' => 25],
    ['name' => 'Jane', 'age' => 21]
]);

// schema: ['id' => ['string', 'id'], 'name' => ['string', 'notEmpty']]
$user = (new App\Model\User)->make([
    'name' => 'Bob'
], 'update+id');
// throws Lark\Validator\ValidatorException:
// Validation failed: "User.id" must be a string

$user = (new App\Model\User)->make([
    'name' => 'Bob'
], 'update');
var_dump($user); // array(1) { ["name"]=> string(3) "Bob" }

// ...
class Model extends Model
{
    const DBS = 'default$app$users';
    public function get(string $id): ?array
    {
        return $this->db()->findId($id);
    }
}

// get user document
$user = (new App\Model\User)->get('62ba4fd034faaf6fc132ef55');

// external calls: get documents
$docs = (new \App\Model\User)->db()->find(['role' => 'admin']);

class ExampleModel extends Model
{
    public static function &schema(): Schema
    {
        return parent::schema([
            'id' => ['string', 'id'],
            // ...
        ]);
    }
}

class ExampleModel extends Model
{
    const SCHEMA = 'users.php';
    public static function &schema(): Schema
    {
        return parent::schema(function(Schema &$schema)
        {
            $schema->apply('name', function($name)
            {
                return strtoupper($name);
            });
        });
    }
}

use Lark\Database\Query;
use App\Model\User;

$query = new Query(new User, [
    'name' => 'test'
]);

// Database::find()
$results = $query->find();

// Database::count()
$count = $query->count();

$query = [
    'name' => 'test'
];

$query = [
    'age' => ['$gte' => 18]
];

$query = [
    'name' => ['$in' => ['test', 'test2', 'test3']]
];

$query = [
    'age' => ['$gt' => 20, '$lt' => 100]
];

$query = [
    // age is greater than 20 OR less than 100
    'age' => ['$gt' => 20, '$lt' => 100],
    '$or' => true
];

$query = [
    // only  => 1, 'name' => 1],
    'name' => 'test',
    'age' => ['$gte' => 18]
];

// or fields can be excluded for each document
$query = [
    // exclude fields "age" and "info" for each document
    '$filter' => ['age' => 0, 'info' => 0]
];

// fetch first page
$query = [
    '$page' => 1
];

// fetch second page
$query = [
    '$page' => 2
];

$query = [
    '$limit' => 100
];

// sort by "name" ASC and "age" DESC
$query = [
    '$sort' => ['name' => 1, 'age' => -1]
];

$query = [
    '$skip' => 10
];

[
    '$created' => 'createdAt',
    '$updated' => 'updatedAt',
    'name' => ['string', 'notNull'],
    'createdAt' => ['timestamp', 'notNull'],
    'updatedAt' => ['timestamp', 'notNull']
]

[
    '$created' => [
        'createdAt' => 'dbdatetime'
    ],
    // ...
]

class UserLog extends Model
{
    const DBS = 'default$app$users.log';
    public static function &schema(): Schema
    {
        return parent::schema([
            '$refs' => [
                'fk' => [
                    // collection => [localField => foreignField, ...]
                    'users' => ['userId' => 'id']
                ]
            ],
            'id' => ['string', 'id'],
            'userId' => ['string', 'notEmpty'],
            'message' => ['string', 'notEmpty']
        ]);
    }
}

// class UserGroup (model)
$schema = new Schema([
    '$refs' => [
        'fk' => [
            // collection => [localField => foreignField, ...]
            'users' => ['users.$' => 'id']
        ]
    ],
    // ...
]);

// class UserAllowed (model)
$schema = new Schema([
    '$refs' => [
        'fk' => [
            // collection => [localField => foreignField, ...]
            'users' => ['users.$.id' => 'id']
        ]
    ],
    // ...
]);

$schema = new Schema([
    '$refs' => [
        'fk' => [
            // collection => [localField => foreignField, ...]
            'users' => [
                'userId' => 'id',
                'users.$' => 'id',
                'usersAllowed.$.id' => 'id'
            ]
        ]
    ],
    // ...
]);

// class User (model)
$schema = new Schema([
    '$refs' => [
        'fk' => [
            // allow managerId to be null (no manager)
            // verify FK users.id exists when users.managerId exists
            'users' => ['nullable$managerId' => 'id']
        ]
    ],
    'id' => ['string', 'id'],
    'managerId' => 'string'
]);

class User extends Model
{
    const DBS = 'default$app$users';
    public static function &schema(): Schema
    {
        return parent::schema([
            '$refs' => [
                'clear' => [
                    // collection => [foreign fields]
                    'users.log' => ['userId']
                ]
            ],
            'id' => ['string', 'id'],
            'name' => ['string', 'notEmpty']
        ]);
    }
}

class User extends Model
{
    const DBS = 'default$app$users';
    public static function &schema(): Schema
    {
        return parent::schema([
            '$refs' => [
                'delete' => [
                    // collection => [foreign fields]
                    'users.log' => ['userId']
                ]
            ],
            'id' => ['string', 'id'],
            'name' => ['string', 'notEmpty']
        ]);
    }
}

$schema = new Schema([
    '$refs' => [
        'delete' => [
            // collection => [foreign fields]
            'users.groups' => ['users.$']
        ]
    ],
    // ...
]);

$schema = new Schema([
    '$refs' => [
        'delete' => [
            // collection => [foreign fields]
            'users.allowed' => ['users.$.id']
        ]
    ],
    // ...
]);

$schema = new Schema([
    '$refs' => [
        'delete' => [
            // collection => [foreign fields]
            'users.log' => ['userId', 'userId2'],
            'users.groups' => ['users.$'],
            'users.allowed' => ['users.$.id']
        ]
    ],
    // ...
]);

use Lark\Validator;

$isValid = (new Validator([
    // data
    'name' => 'Bob',
    'age' => 25
], [
    // schema
    'name' => ['string', 'notEmpty'],
    'age' => ['int', 'notNull'],
    'phone' => null, // no type (any type allowed), optional
    'title' => 'string' // string, optional
]))->validate(); // true

(new Validator([
    'name' => null
], [
    'name' => ['string', 'notNull']
]))->assert();
// throws Lark\Validator\ValidatorException:
// Validation failed: "name" must be a string

// validation will pass because no field is 'name' => ['string'],
        'age' => ['int']
    ]))->make()
);
// array(2) { ["name"]=> NULL ["age"]=> NULL }

$isValid = (new Validator([
    // data
    'name' => 'Bob',
    'contact' => [
        'email' => '[email protected]',
        'phone' => [
            'cell' => '555-5555',
            'office' => '555-6666'
        ]
    ]
], [
    // schema
    'name' => ['string', 'notEmpty'],
    'contact' => [
        'array',
        [
            'fields' => [
                'email' => ['string', 'email'],
                'phone' => [
                    'array',
                    [
                        'fields' => [
                            'cell' => 'string',
                            'office' => 'string'
                        ]
                    ]
                ]
            ]
        ]
    ]
]))->validate(); // true

$isValid = (new Validator([
    'name' => 'test',
    'tags' => [
        // these must be arrays because "schema:array" is used
        // if "schema:object" is used these must be objects
        ['id' => '1', 'name' => 'test2'],
        ['id' => 2, 'name' => 'test3'],
    ]
], [
    'name' => ['string', 'notEmpty'],
    'tags' => [
        'array', 'notEmpty',
        [
            'schema:array' => [
                'id' => ['int', 'notNull'],
                'name' => 'string'
            ]
        ]
    ]
]))->assert();
// throws Lark\Validator\ValidatorException:
// Validation failed: "tags.0.id" must be an integer or null

(new Validator([
    'name' => null
], [
    'name' => ['string', 'notNull']
]))->assert(function(string $field, string $message, string $name = null){
    // handle error
    //...

    // return true to halt
    // return false to continue to throw validation exception
    return true;
});

// validator.rule.[type].[name]
app()->use('validator.rule.string.beginWithEndWith', App\Validator\BeginWithEndWith::class);

// App\Validator\MyRule class:
namespace App\Validator;
class BeginWithEndWith extends \Lark\Validator\Rule
{
    private string $beginWith;
    private string $endWith;

    protected string $message = 'must begin with value and end with value';

    public function __construct(string $beginWith, string $endWith)
    {
        $this->beginWith = $beginWith;
        $this->endWith = $endWith;
    }

    public function validate($value): bool
    {
        $beginsWith = substr($value, 0, strlen($this->beginWith));
        $endsWith = substr($value, -(strlen($this->endWith)));

        return $beginsWith === $this->beginWith && $endsWith === $this->endWith;
    }
}

// validation example
(new Validator([
    'alias' => '123testXYZ'
], [
    'alias' => ['string', ['beginWithEndWith' => ['123', 'XYZ']]]
]))->validate(); // true

// validator.rule.[type].[name]
// overwrite existing string rule "email"
app()->use('validator.rule.string.email', 'App\\Validator\\Email');

// App\Validator\Email class:
namespace App\Validator;
class Email extends \Lark\Validator\TypeString\Email
{
    public function validate($value): bool
    {
        // must be valid email and domain "example.com"
        return parent::validate($value)
            && preg_match('/@example\.com$/i', $value) === 1;
    }
}

// validation example
(new Validator([
    'email' => '[email protected]'
], [
    'email' => ['string', 'email']
]))->validate(); // true

$cleanStr = filter()->string($str);

$arr = ["one" => 1, "two" => 2, "three" => 3];

// exclude filter
print_r(
    filter()->keys($arr, ["two" => 0])
); // Array ( [one] => 1 [three] => 3 )

// 

use Lark\Http\Client;
$client = new Client;
try
{
    $res = $client->get('http://example.com');
    $headers = $client->headers();
    $statusCode = $client->statusCode();

    if($statusCode === 200)
    {
        // ok
    }
    else
    {
        // handle
    }
}
catch (Lark\Http\HttpException $ex)
{
    // handle request/curl error
}

// DELETE request
$client->delete('http://example.com', ['field1' => 'value']);
// GET request
$client->get('http://example.com', ['param' => 1]); // http://example.com?param=1
// HEAD request
$client->head('http://example.com');
// OPTIONS request
$client->options('http://example.com');
// PATCH request
$client->patch('http://example.com', ['field1' => 'value']);
// POST request
$client->post('http://example.com', ['field1' => 'value']);
// PUT request
$client->put('http://example.com', ['field1' => 'value']);

$client = new Client([
    'headers' => ['content-type' => 'application/json']
]);
// POST request with JSON string
$client->post('http://example.com', json_encode(['field1' => 'value']));

use Lark\Http\Client;
$client = new Client(['url' => 'http://example.com', 'timeout' => 8]);
$res = $client->get('/api/items'); // http://example.com/api/items
$res2 = $client->post('/api/items', ['name' => 'My Item']);

$res = $client->get('/api/items', ['timeout' => 5]);

use Lark\Http\Client;
$client = new Client([
    'curl' => [
        CURLOPT_RESOLVE => ['test.loc:127.0.0.1']
    ]
]);

> db.users.delete( { _id: { $in: [ids] } } )
> db.users.log.updateMany( { userId: { $in: [ids] } }, { $set: { userId: null } } )
> 

> db.users.delete( { _id: { $in: [ids] } } )
> db.users.groups.updateMany(
>     { users: { $in: [ids] } },
>     { $pullAll: { users: [ids] } },
>     { multi:true }
> )
> 

> db.users.delete( { _id: { $in: [ids] } } )
> db.users.allowed.updateMany(
>     { users.id: { $in: [ids] } },
>     { $pull: { users: { id: { $in: [ids] } } } },
>     { multi:true }
> )
> 
php
// bootstrap
// ...

$cli = Lark\Cli::getInstance();

// add command
$cli->command('files', 'Print files in directory')
    ->arg('dir', 'Read directory')
    ->action(function(string $dir) {
        // print files in directory $dir

        // optional, exit with any code by returning an int
        // return 1; // same as $cli->exit(1);
    });
    // or use class/method:
    // ->action([MyClass::class, 'methodName'])

// run app
$cli->run($_SERVER['argv']);
php
// set global option (separate from command options)
$cli->option('-d, --debug', 'Enable debug mode', function() {
    // enable here
});

$cli->command('files', 'Print files in directory')
    ->arg('dir', 'Read directory') //  // option test
    ->option('-t, --test', 'Run test', ['optional'])
    // add command action
    ->action(function(string $dir, ?array $subdirs, ?string $outputfile, ?bool $isTest) {
        var_dump($dir, $subdirs, $outputfile, $isTest);
    });

// $ php ./app/cli.php files mydir subdir1 subdir2 --outputfile=/my/file -t
// string(5) "mydir"
// array(2) { [0] => string(7) "subdir1" [1] => string(7) "subdir2" }
// string(8) "/my/file"
// bool(true)
php
$o = $cli->output();

// output green text
$o->colorGreen->echo('This is green text');
// use multiple styles
$o->colorBlue->styleUnderline->echo('More text');

// style methods for common styles
$o->error('Error'); // red background
$o->info('Info'); // blue text
$o->ok('Success'); // green text
$o->warn('Warning'); // yellow text
$o->dim('Muted'); // dim text

// custom style methods can be registered
$o::register('blink', function ($text, $end = PHP_EOL) use ($out) {
    $out->styleBlink;
    $out->echo($text, $end);
});
$o->bink('Blinking text'); // blinking text

// override existing style methods
$o::register('error', function ($text, $end = PHP_EOL) use ($out) {
    $out->colorRed; // text color red (instead of bg red)
    $out->stderr($text, $end); // send to stderr
});
$o->error('Oops'); // red text
php
$data = [
    [1, "one"],
    [2, "two"],
    [100, "one hundred"],
    [3, "three"],
];

$out->grid($data, ['indent' => 2]);
php
use Lark\File;

$file = new File('./my-file.txt');
if($file->write('contents'))
{
    // ...
}

$contents = $file->read();
php
use Lark\Exception as LarkException;
use Lark\Json\File as JsonFile;

$file = new JsonFile('./my-file.json');
$file->write(['name' => 'test']);

try
{
    $value = $file->read();
}
catch(LarkException $ex)
{
    // exception is throw on JSON decode error
    echo 'Failed to decode JSON file: ' . $ex->getMessage();
}
php
$timer = new Lark\Timer;

usleep(500000);
echo $timer->elapsed(); // 0.5001s

sleep(1);
echo $timer->elapsed(); // 1.5014s

sleep(2);
// get elapsed since last Timer::elapsed()
// or Timer::elapsedSinceLast() was invoked
echo $timer->elapsedSinceLast(); // 2.0003s

echo $timer->elapsed(); // 3.5018s
php
app()->use('[...]');
php
$dbDt = dbdatetime();
$dt = $dbDt->toDateTime(); // DateTime object

// with milliseconds
$dbDt = dbdatetime(strtotime('-1 day') * 1000);
php
$dbName = env('DB_NAME');
php
logger('channel')->info('message', ['context']);
php
var_dump(
    req()->path()
);
// string(1) "/"
php
res()->contentType('application/json');
php
router()->get('/', function() {
    return 'home';
});