Easy and Understandable
Windwalker is very simple on classes interface, we called it DX (Developer Experience), most classes in Windwalker has single entry point and easy understandable naming.
Package System
Package is the main component of Windwalker's structure. Here is a image that describe the package system:
From this image, we will know there can be multiple packages and its' own MVC system in Windwalker. That makes our application more flexible. For example, we can create a FrontendPackage and an AdminPackage to maintain your front-end and back-end in separated different packages. And maybe an ApiPackage to provide RESTful API for mobile APP.
See: Package Syetem
RAD Package
We also provides a RAD package called Phoenix, with this package, every web development team are able to establish an usable system prototype with powerful admin UI quickly and continue complete it after multiple iteration.
Single Responsibility Principle
Most Windwalker objects follows Single Responsibility Principle, the benefit is that the responsibility of every object are very clear, we don't need to include a big object for using only one method.
The main usage is Single Action Controller, every controller has only one action (execute()
).
Controllers in Windwalker will be more lighter then other frameworks. You can add more logic to one controller
but won't be confused by many actions in one class.
class GetController extends Controller
{
protected function doExecute()
{
// Do some stuff...
}
}
See: Use Controller
Hook System
Since many objects has single entry point, there is a hook system in Windwalker everywhere.
You can add many logic before or after doExecute()
if you override the parent classes.
ViewModel Pattern
Windwalker uses a pattern which is similar to Supervising Controller, MVVM or MVP , View can not communicate to Model, but Controller can binding Model to View, then View is able to get data from Model.
See: ViewModel
Repository and State Control
Windwalker Repository is stateful design, use state pattern will help us create flexible data provider. For example, we can change this state to get different data.
$repo = new MyRepository;
// Let's change repository state
$repo->set('where.published', 1);
$repo->set('list.ordering', 'birth');
$repo->set('list.direction', 'DESC');
$users = $repo->getUsers();
See: Model State
Multiple Template Engines
Extendible PHP Engine
Windwalker PHP Engine is able to extends parent template which similar to Blade or Twig:
<?php
$this->extend('_global.main');
?>
<?php $this->block('title');?>Article<?php $this->endblock(); ?>
<?php $this->block('body');?>
<article>
<h2>Article</h2>
<p>FOO</p>
</article>
<?php $this->endblock(); ?>
See: PHP Engine
Blade/Edge and Twig Engine
Windwalker also support powerful Blade and Twig engine, and our own Edge engine which is compatible with Blade.
See: Blade Engine / Twig Engine
Widget System
Widget object is a convenience tool to help us render HTML blocks, you can consider it as a backend web component.
We also contains powerful level-based template override rules.
See: Widget and Renderer
Asset Management
Windwalker has an asset manager to help us include css/js files and handle the script dependencies.
// Include CSS and JS
$asset->addJS('js/my-script.min.js');
$asset->addCSS('css/my-style.min.css');
// Use script manager to handle dependencies
\Flower\Script\MyScript::formHandler('#admin-form');
See Asset Manager
Fast Routing
Restful
Windwalker use Restful design, one route will able to handle four controller actions. This can reduce a quarter of times to match routes.
Matchers
Router provides some matchers to use different way to search routes:
- Sequential Matcher - Use the Sequential Search Method to find route
- Binary Matcher - Use the Binary Search Algorithm to find route.
- Trie Matcher - Use the Trie tree to search route.
A simple benchmark when we developing Router:
See: Routing
Database
Powerful Schema Builder
$table->create(function (Schema $schema)
{
$schema->primary('id')->signed(false)->allowNull(false)->comment('Primary Key');
$schema->integer('category_id')->signed(false)->allowNull(false)->comment('Cat Key');
$schema->varchar('title')->allowNull(false)->comment('Title');
$schema->varchar('slug')->length(123)->allowNull(false)->comment('Slug');
$schema->text('content')->allowNull(false)->comment('Content');
$schema->addIndex('category_id');
$schema->addIndex(['category_id', 'title']);
$schema->addUniqueKey('slug(150)');
}, true);
See: Table and Schema
DataType Mapping
Windwalker will auto map datatype between different databases.
For example, use datetime
in Mysql, will be datetime
type, but in PostgreSql, the column type will be timestamp
. You don't worry about
the difference of data type between databases, Windwalker will auto handle it.
See: Table and Schema
Easy Error Handling
See: Error Handling
Spl Iterable Filesystem
$items = Filesystem::items($path);
foreach ($files as $file) {
if ($file->isDir()) {
continue;
}
}
Check permission bigger than 755.
$closure = function($current, $key, $iterator) {
return Path::getPermissions($current->getPath()) >= 755;
};
$files = Filesystem::find($path, $closure, true);
Form Builder
$form = new Form;
$form->addField(new TextField('name', 'Label'))
->set('id', 'my-name')
->set('class', 'col-md-8 form-input')
->set('onclick', 'return false;');
$form->addField(new TextField('email', 'Label'))
->required();
$form->addField(new TextField('username', 'Username'));
$form->addField(new PasswordField('password', 'Password'));
$form->addField(new TextareaField('description', 'Description'));
echo $form->renderFields();
See: Form Builder and Form Definition
HTML Builder
Simple HtmlElement to build a tag.
use Windwalker\Dom\HtmlElement;
$attrs = array(
'class' => 'btn btn-mini',
'onclick' => 'return fasle;'
);
$html = (string) new HtmlElement('button', 'Click', $attrs);
// The result
// <button class="btn btn-mini" onclick="return false;">Click</button>
And select list builder.
use Windwalker\Html\Select\SelectList;
use Windwalker\Html\Option;
$select = new SelectList(
'form[timezone]',
array(
new Option('Asia - Tokyo', 'Asia/Tokyo', array('class' => 'opt')),
new Option('Asia - Taipei', 'Asia/Taipei'),
new Option('Europe - Paris', 'Asia/Paris'),
new Option('UTC', 'UTC'),
),
array('class' => 'input-select'),
'UTC',
false
);
echo $select;
See: HTML Builder
Easy Benchmarking
Benchmark in Windwalker is very easy:
use Windwalker\Profiler\Banchmark;
$benchmark = new Benchmark;
$benchmark->addTask('task1', function() {
md5(uniqid());
});
$benchmark->->addTask('task2', function() {
sha1(uniqid());
});
$benchmark->execute(10000);
echo $benchmark->render();
/* Result
task1 => 187.489986 ms
task2 => 207.049847 ms
*/
See: Profiler
Utilities
String Handler
Utf8 string handler
use Windwalker\String\Utf8String;
echo str('這是中文字', 0, 3)->truncate(3, '...')->__toString();
String Inflector
use Windwalker\String\StringInflector;
$inflector = new StringInflector;
echo $inflector->toSingular('categories'); // category
Easy Dump Data
// print_r 3 objects and limit 7 levels
show($data1, $data2, $data3, 7);