Skip to content

adamtomat/lumberjack

 
 

Repository files navigation

Lumberjack

A framework for making WordPress theme development more sane & easier to maintain.

Written & maintained by the team at Rareloop.

Features

  • Dependency Injection Container (PSR11)
  • Configuration
  • Post Types
  • Actions & Filters
  • Router
    • HTTP Request/Response Messages (PSR7)
    • Middleware (PSR15)
  • Controllers
  • Logging (PSR3)
  • Service Providers
  • Facades
  • Exceptions

The framework has been designed to be as un-intrusive as possible and you're free to use as little or as much of it as you'd like.

Requirements

  • PHP >=7.0
  • Installation via Composer (e.g. Bedrock)

Installing

Download this theme to your Composer powered WordPress setup and then install the core framework dependency:

composer require rareloop/lumberjack-core

Dependency Injection Container

Lumberjack features a PSR11 compatible container, powered by the popular open source PHPDI. If this is a new term for you checkout this great intro and don't worry, you don't have to make use of it if you don't want to.

Accessing the container

In the default Lumberjack functions.php you'll find the following code:

$app = new Application(__DIR__);

This creates the Application and the $app variable becomes your reference to the container.

Setting entries in the container

To add something to the container you simply call bind(), e.g.:

$app->bind('foo', 'bar');

Retrieving entries from the container

To retrieve an entry from the container you can use get(), e.g.:

$foo = $app->get('foo');

Use the container to create an object

You can use the container to create an object from any class that your application can autoload using make(), e.g.:

$comment = $app->make('\MyNamespace\Comment');

When creating an object using make, all the dependencies required by it's __construct() function will be automatically resolved from the container using type hinting. If your object requires additional parameters that can not resolved by type hinting you can pass them as a second param, e.g.:

namespace MyNamespace;

class Comment
{
  public function __construct(ClassInContainer $resolvable, $param1, $param2) {}
}

...

$comment = $app->make('\MyNamespace\Comment', [
  'param1' => 123,
  'param2' => 'abc',
]);

Set concrete implementations for interfaces

You can also tell the container what concrete class to use when resolving a certain type hinted interface. This allows you to write your app code against contracts and then use the container to switch in the correct implementation at runtime.

namespace MyNamespace;

interface PaymentGateway {}

class StripePaymentGateway implements PaymentGateway{}

$app->set('\MyNamespace\PaymentGateway', '\MyNamespace\StripePaymentGateway');

$gateway = $app->make('\MyNamespace\PaymentGateway');
// $gateway is instance of '\MyNamespace\StripePaymentGateway'

Configuration

TODO

Post Types

TODO

Actions & Filters

TODO

Router

The Lumberjack Router is based on the standalone Rareloop Router but utilised a Facade to make setup and access simpler.

Note: Route closures and controller functions are automatically dependency injected from the container.

HTTP Request/Response Messages

Creating Routes

Map

Creating a route is done using the map function:

use Rareloop\Lumberjack\Facades\Router;

// Creates a route that matches the uri `/posts/list` both GET
// and POST requests.
Router::map(['GET', 'POST'], 'posts/list', function () {
    return 'Hello World';
});

map() takes 3 parameters:

  • methods (array): list of matching request methods, valid values:
    • GET
    • POST
    • PUT
    • PATCH
    • DELETE
    • OPTIONS
  • uri (string): The URI to match against
  • action (function|string): Either a closure or a Controller string

Route Parameters

Parameters can be defined on routes using the {keyName} syntax. When a route matches that contains parameters, an instance of the RouteParams object is passed to the action.

Router::map(['GET'], 'posts/{id}', function(RouteParams $params) {
    return $params->id;
});

Named Routes

Routes can be named so that their URL can be generated programatically:

Router::map(['GET'], 'posts/all', function () {})->name('posts.index');

$url = Router::url('posts.index');

If the route requires parameters you can be pass an associative array as a second parameter:

Router::map(['GET'], 'posts/{id}', function () {})->name('posts.show');

$url = Router::url('posts.show', ['id' => 123]);

HTTP Verb Shortcuts

Typically you only need to allow one HTTP verb for a route, for these cases the following shortcuts can be used:

Router::get('test/route', function () {});
Router::post('test/route', function () {});
Router::put('test/route', function () {});
Router::patch('test/route', function () {});
Router::delete('test/route', function () {});
Router::options('test/route', function () {});

Creating Groups

It is common to group similar routes behind a common prefix. This can be achieved using Route Groups:

Router::group('prefix', function ($group) {
    $group->map(['GET'], 'route1', function () {}); // `/prefix/route1`
    $group->map(['GET'], 'route2', function () {}); // `/prefix/route2§`
});

Middleware

TODO

Route based middleware

Global middleware

Controllers

WordPress Controllers

TODO

Route Controllers

If you'd rather use a class to group related route actions together you can pass a Controller String to map() instead of a closure. The string takes the format {name of class}@{name of method}. It is important that you use the complete namespace with the class name.

Example:

// TestController.php
namespace \MyNamespace;

class TestController
{
    public function testMethod()
    {
        return 'Hello World';
    }
}

// routes.php
Router::map(['GET'], 'route/uri', '\MyNamespace\TestController@testMethod');

Logging (PSR3)

TODO

Service Providers

TODO

Facades

Lumberjack uses the Blast Facades library.

Creating a Facade

Facades provide a simple static API to an object that has been registered into the container. For example to setup a facade you would first use a Service Provider to register an instance of your class into the container:

namespace Rareloop\Lumberjack\Providers;

use Monolog\Logger;
use Rareloop\Lumberjack\Application;

class LogServiceProvider extends ServiceProvider
{
    public function register()
    {
        // Create object instance and bind into container
        $this->app->bind('logger', new Logger('app'));
    }
}

Then create a Facade subclass and tell it which key to use to retrieve your class instance:

<?php

namespace Rareloop\Lumberjack\Facades;

use Blast\Facades\AbstractFacade;

class Log extends AbstractFacade
{
    protected static function accessor()
    {
        return 'logger';
    }
}

Exceptions

TODO

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • PHP 83.6%
  • HTML 15.2%
  • CSS 1.2%