Application loader
Bedrock does give you a project structure, but for your own code, it is still just regular old plugins, mu plugins and themes. We like to place our project core code as an mu plugin, and we put inside a [appname]-application folder. If we come up with reusable functionality, we separate those as plugins and mu plugins.
We start our application up in a php file in mu-plugins directory. That file is called [appname]-loader.php and looks something like this:
namespace MyApplication;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
// Initiate Composer Autoloading.
require( ABSPATH . '../../vendor/autoload.php' );
// Bootstrap other mu plugins.
require( 'posts-to-posts/posts-to-posts.php' );
require( 'cmb/Custom-Meta-Boxes/custom-meta-boxes.php' );
// Load application configuration.
$container = new ContainerBuilder();
$loader = new YamlFileLoader( $container,
new FileLocator( __DIR__ . '/../../../config' ) );
$loader->load( 'services.yml' );
// Initiate the application.
$container->get('application');
What is happening there? To my taste, there is too much boilerplate code in there that would benefit of being encapsulated somewhere else. But, basically we just initiate the Symfony DependencyInjection container with a configuration file and then get an instance of our application class from it. Because of what we had defined in the configuration file, the application will get every object it will need from the container.
Application confuguration
Let’s look at the configuration file, services.yml. It has two parts. First, the parameters of each constructor is defined:
parameters:
posttypes:
- @post
- @page
- @person
- @casestudy
- @service
connections:
- @case_personnel
- @services_provided
taxonomies:
- @casetype
- @expertise
queryfilters:
- @frontpage
- @cases
- @persons
services:
- @person_api
- @auto_meta_property
Names starting with @ are references to classes, defined in the later part of the file. The parameters are arrays of classes.
Then, the actual services, which in practise means classes:
services:
wordpress:
class: WPlinth\WordPressFactory
post_type_manager:
class: WPlinth\PostTypeManager
arguments: ["%posttypes%"]
queryfiltermanager:
class: WPlinth\QueryFilterManager
arguments: ["%queryfilters%"]
application:
class: ProjectName\Application
arguments:
- "@post_type_manager"
- "%connections%"
- "%taxonomies%"
- "@queryfiltermanager"
- "%services%"
logging:
class: H1\Logging\Logging
post:
class: ProjectName\PostType\Post
page:
class: ProjectName\PostType\Page
person:
class: ProjectName\PostType\Person
arguments: ["@logging"]
calls: [[set_wp, ["@wordpress"]]]
casestudy:
class: ProjectName\PostType\CaseStudy
calls: [[set_wp, ["@wordpress"]]]
service:
class: ProjectName\PostType\Service
calls: [[set_wp, ["@wordpress"]]]
case_personnel:
class: ProjectName\Connection\CasePersonnel
services_provided:
class: ProjectName\Connection\ServicesProvided
casetype:
class: ProjectName\Taxonomy\CaseType
person_api:
class: ProjectName\Service\PersonAPI
auto_meta_property:
class: WPlinth\AutoMetaProperty
arguments: ["@post_type_manager"]
frontpage:
class: ProjectName\QueryFilter\FrontPage
cases:
class: ProjectName\QueryFilter\Cases
persons:
class: ProjectName\QueryFilter\Persons
This example file is from a fictitious project. Let me explain it a bit. We have a site that displays reference cases and services that a company has. Personnel and services are connected to reference cases with Posts to Posts. Personnel information is integrated with the company CRM, using PersonAPI class, and we are logging each change to a person post because of that.
Application class
An instance of most classes is passed on to the Application object as a parameter. That class itself can be very simple:
namespace ProjectName;
class Application {
public function __construct( $posttypemanager, $connections,
$taxonomies, $querymanager, $services ) {
}
}
We could store the constructor parameters as instance variables, if we would like to extend the Application class to do stuff with those. But in normally we don’t have to.
Application folder structure
Our [appname]-application has a specific structure. Here is a typical directory structure:
/Connection
/PostType
/QueryFilter
/Service
/Taxonomy
/Test
Application.php
Each of the folder contains the classes that inherit from a base class in WPlinth. For example PostType folder contains all the post types and they are classes that inherit from WPlinth PostType base class. Service is just a generic folder name for miscellaneous services. You can obviously have different and/or other folders (namespaces) in your application.
In the next post, we’ll look at code inside those classes.