baileyherbert / horizon Goto Github PK
View Code? Open in Web Editor NEWFramework for building distributed web applications that work on all servers.
Home Page: https://docs.bailey.sh/horizon/
License: MIT License
Framework for building distributed web applications that work on all servers.
Home Page: https://docs.bailey.sh/horizon/
License: MIT License
Uncaught exception "UnexpectedValueException" with message "RecursiveDirectoryIterator::__construct(app\translations,app\translations): The system cannot find the file specified. (code: 2)" in horizon\lib\Provider\Services\TranslationProvider.php on line 36
Warning: Invalid argument supplied for foreach() in horizon\lib\Extend\ExtensionKernel.php on line 42
Route pipes are similar to middleware, except they apply to all requests under a prefix rather than specific routes. They also execute before the request is matched to a route, allowing them to:
In addition, two official pipes will be added to the framework.
Horizon\Http\Pipes\ErrorHandlerPipe
-- Used to change the error handler for all matching requests.Horizon\Http\Pipes\HeaderPipe
-- Used to set headers for all matching requests.Example pipe invocations to demonstrate prefixes and attributes:
Route::pipe('/api/', Horizon\Http\Pipes\ErrorHandlerPipe::class)
->set('handler', Horizon\Exception\JsonErrorHandler::class);
Route::pipe('/api/', Horizon\Http\Pipes\HeaderPipe::class)
->push('headers', 'Access-Control-Allow-Credentials: true')
->push('headers', 'Access-Control-Allow-Origin: http://localhost:3000');
With the above example, the pipes are applied for all requests within /api/
before the kernel even checks if the request has a matching route:
/api
-- Not matched/api/
-- Matched/api/file
-- Matched/api/dir/file
-- MatchedAs a result, even 404
errors generated by the framework will receive the custom headers and use the JSON error handler.
Currently a component can be rendered within a template like this:
@component('name', args)
This proposal will add tagged components that look like regular HTML tags and accept attributes and slots.
A tagged component must be in the format <@name>
which will resolve to a component template named tags/name
.
<@name><div>Inner content</div></@name>
<@name />
The corresponding tags/name
component template file will need to express the @tagged
attribute at the top of the file. This directs the transpiler to treat the component as a tag. It can then use the special @slot
directive.
@tagged
@slot
Attributes supplied after the declaration of a tagged component are parsed as strings and made available to the component template. Attributes defined without a value will be set to "true"
.
<@name value="The bool attribute is set!" bool />
The corresponding tags/name
component template file can retrieve these values using its class, which receives an associative array of all attributes and their values at construction time. For the default component class, this means all attributes can be retrieved using the standard $this->varname
:
@tagged
@if ($this->bool)
{{ $this->value }}
@end
Attributes can accept variables from the environment like usual, and can be optionally enclosed in quotes:
<@name value="{{ $variableName }}" />
Attributes can accept inner HTML using slots. Each component has a default slot and can also define named slots. Behind the scenes, tagged components treat slots as twig blocks which can be easily extended from above.
The default slot can be used by simply providing inner HTML:
<@name>Inner HTML</@name>
However, named slots must be defined as their own tags in the format <@slot:name>
, where name
is the name of the slot as defined within the corresponding component template. As an example, take this tagged component template:
@tagged
<h1><@slot:header /></h1>
<p><@slot /></p>
The usage to implement both slots would look like the following:
<@name>
<@slot:header>Hello world!</@slot>
<@slot>This is some paragraph text.</@slot>
</@name>
Note that when specifying slots with the special @slot
tag, it is illegal to supply additional inner HTML outside of slot tags. In other words, this must error:
<@name>
<@slot:header>Hello world!</@slot>
<@slot>This is some paragraph text.</@slot>
This content isn't allowed outside of a slot.
</@name>
The cool thing about normal components is that they have their own environment for state which is managed by the class defined with the @using()
directive. Tagged components are no exception, they too must be attached to a class and can specify the @using()
directive.
Normally, this state is isolated and cannot be accessed by the templates that invoke the component. However, tagged components can have their state exported from their attributes.
For example, if the component has a variable stored at $this->varname
, the caller can export it like below, after which the variable varname
will immediately become available in the scope of the calling template:
<@name export:varname />
{{ $varname }}
If the name of the tagged component is unknown until runtime, it can be invoked dynamically with the built-in <@dynamic>
tag. This accepts a name
argument containing a string.
<@dynamic name={{ $componentName }} />
When a controller exits and the response output buffer is empty, encode the controller's return value as JSON and pipe it into the output.
Twig filters that have an equivalent PHP function should be added to the custom template syntax to behave like native PHP functions.
For example, the lower
twig filter is normally invoked like this:
{{ 'UPPER'|lower }}
Horizon should accept the following and convert it to the above syntax:
{{ strtolower('UPPER') }} -> {{ 'UPPER'|lower }}
For filters with arguments, they will be shifted accordingly:
{{ sprintf("%s", "foo") }} -> {{ '%s'|format('foo') }}
Add a new session driver that uses session_set_save_handler
to save data in the database.
Add Schema::sessions()
and Schema::dropSessions()
to create the database table. The default name should be @sessions
.
The afterExecute
method on middleware only executes for successful requests.
Add a protected flag that will enable invocation of the afterExecute
method on failed requests. There should also be a separate option to enable it for fatal errors (null
for this option will use the same value as the former flag).
protected $afterErrors = false;
protected $afterFatalErrors = null;
There needs to be some sort of managed task scheduling.
Tasks can be anonymous closures, callables, and commands as strings. They can be registered on a regular schedule using the global Schedule
class alias, similar to routes.
First the file(s) containing the tasks must be set in the app
configuration.
'tasks' => [
'app/tasks/schedule.php'
]
Then define tasks within the app/tasks/schedule.php
file as follows:
// Run commands
Schedule::command('command:name --args')->daily();
Schedule::command(SendEmailsCommand::class, ['--args'])->daily();
// Run functions and methods
Schedule::run(function() {})->daily();
Schedule::run(new DeleteRecentUsers())->daily();
Schedule::run('App\Tasks\DeleteRecentUsers::methodName')->daily();
// Run shell commands
Schedule::exec('node /path/to/script')->daily();
First define a task via the schedule configuration file above using Schedule::define()
. The first argument requires a unique name for this task, and the second is a callable just like with Schedule::run()
.
Schedule::define('name', function() {});
Schedule::define('name', 'App\Tasks\DeleteRecentUsers::methodName');
When the application is running, schedule one of the defined tasks for later with the Schedule::later()
function.
Schedule::later('name')->immediately();
Schedule::later('name')->inMinutes(5);
Because multiple instances of the same task could be scheduled simultaneously this way, it is important to allow custom "stacking" behavior for each "later" task.
// Append the new scheduled task to the list of existing ones and run them all (default)
Schedule::define('name', function() {})->withStacking(Schedule::STACK_APPEND);
// Replace any existing scheduled tasks with the new one
Schedule::define('name', function() {})->withStacking(Schedule::STACK_REPLACE);
// Ignore the new scheduled task if there is an existing one
Schedule::define('name', function() {})->withStacking(Schedule::STACK_DISABLED);
You can also call Schedule::later()->withStacking()
to override the behavior per invocation.
Horizon\Foundation\Kernel::scheduler()->run()
schedule:run
ace command* * * * * cd /path-to-your-project && ace schedule:run >> /dev/null 2>&1
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.