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.

img

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.

hook

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.

mvc ww-mvc

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.

widget

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:

A simple benchmark when we developing Router:

Matcher Benchmark

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);