Scaffold Documentation - Read the Docs · The *.scaffold.phpfile is the configuration file (a...

28
Scaffold Documentation Release 1.1 Alin Eugen Deac Oct 29, 2017

Transcript of Scaffold Documentation - Read the Docs · The *.scaffold.phpfile is the configuration file (a...

Scaffold DocumentationRelease 1.1

Alin Eugen Deac

Oct 29, 2017

Contents

1 Contents 31.1 How to Install . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Install Scaffolds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.3 Create Scaffolds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.4 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191.5 Indices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

i

ii

Scaffold Documentation, Release 1.1

How many times have you been doing the same task, over and over again? Maybe it’s time for you to create somekind of helper that can perform that task for you. Perhaps this tool might be able to help you along the way.

Scaffold is a php-based command line tool for creating and installing various files and directories into your project,based on a configuration file (scaffold).

Key features

• Create desired directory structure

• Copy static files into desired location

• Ask user for input

• Generate files based on templates, compiled with data from the user

In other words, you can perceive this tool as a console wizzard for installing “something” inside your project.

Source is available on GitHub.

Contents 1

Scaffold Documentation, Release 1.1

2 Contents

CHAPTER 1

Contents

The basics

How to Install

Requirements

• php version > 5.6.4

• composer

This package uses composer. If you do not know what that is or how it works, I recommend that you read a littleabout, before attempting to use this package.

Other than this, you scaffold application requires read / write access to the directories where you use it. Normally thisisn’t a problem. However if you run into these kinds of issues, please review your PHP’s access privileges.

Local Installation

The Scaffold application is intended as a development tool, which is why it should be required via composer as adevelopment dependency.

composer require aedart/scaffold --dev

Global Installation

A global installation allows you to use the scaffold application everywhere.

composer global require aedart/scaffold

3

Scaffold Documentation, Release 1.1

Warning: If you have other packages installed globally, their dependencies might conflict.

You can perhaps resolves this by making use of Consolidation/Cgr, which safely installs each command line toolapplication in it’s own directory.

How to use scaffolds

Install Scaffolds

Require Scaffold

Regardless if you are within a new project or existing, you must first require your desired scaffold(s). This is done viacomposer’s require command or by specifying it in your composer.json.

composer require acme/scaffolds

{"name": "acme/my-project","description": "My Proejct","license": "BSD-3-Clause","type": "library","require": {

"acme/scaffolds": "~1.0"},

}

Global Scaffolds

If you have chosen to require your scaffold(s) globally, then they should already be available and there is no need foryou to perform this.

Install Scaffold

Install Command

The easiest way to install a your desired scaffold, is by invoking the install command

vendor/bin/scaffold install

This command will automatically create an index of all the found scaffolds and start displaying a list of vendors,packages and scaffolds you can chose to install. It should output something similar to this;

Building index==============

! [NOTE] Building new index (.scaffold/index.json)

Searching in /home/Code/my-project/vendor

! [NOTE] Indexing /home/Code/my-project/vendor/acme/scaffolds/my-scaffold.scaffold.→˓php

4 Chapter 1. Contents

Scaffold Documentation, Release 1.1

Searching in /home/.composer/vendor

! [NOTE] No scaffolds found in /home/.composer/vendor

[OK] Indexing completed

Install...==========

Please select a vendor:[0] acme>

Tip: The install command supports several options. See command help for additional information.

vendor/bin/scaffold install -h

Build Command

If you wish to skip the install procedure (listing of vendors, packages ... etc), then you can use the build commandto specify your desired scaffold directly.

vendor/bin/scaffold build other/location/my-scaffold.scaffold.php

Build From File Command

Sometimes it can be useful to automate the building process. For instance, if you want to build several scaffolds atonce, then you can use the build:file command.

vendor/bin/scaffold build:file location/scaffoldsToBuild.php

The command accepts a single argument, file, which is a location to a php file that contains a list of scaffolds to bebuilt.

In other words, this command allows you to build multiple scaffolds in one and the same process.

File Format

The following illustrates the format that the build:file command accepts.

<?php

return [[

// Location to scaffold'location' => __DIR__ . '/MyModel.scaffold.php',

// Input (answers to questions) for that scaffold'input' => [

1.2. Install Scaffolds 5

Scaffold Documentation, Release 1.1

'AEDART/a']

],[

'location' => __DIR__ . '/MyController.scaffold.php','input' => [

'Acme/b']

],[

'location' => __DIR__ . '/MyView.scaffold.php','input' => [

'Punk/c']

],];

Output Location

By default, bot the install and the build commands will output the resulting files and directories into the currentworking directory, form where you invoked the command. This behaviour can be modified by providing the commandswith an optional output directory

vendor/bin/scaffold install -o path/where/to/install/

vendor/bin/scaffold build -o path/where/to/install/ other/location/my-scaffold.→˓scaffold.php

Create your own

Create Scaffolds

Location

The first thing you need to consider is, where to place your scaffold files.

Regardless of your choice, I recommend that you use a version control system !

Note: Make sure that the scaffold application is available a development dependency.

See How to Install

New Project

The “safest” options is to create a new repository in which you only have to deal with the scaffold and it’s resources.Doing so allows you to focus mainly on the structure of the scaffold and there is little risk for you to interfere withexisting files.

6 Chapter 1. Contents

Scaffold Documentation, Release 1.1

Tip: If you are new to using this application, then I recommend that you start off by creating scaffolds in a separateproject.

Existing Project

Alternatively, you can also create scaffolds directly into existing projects. This does have the benefit of having a tightcoupling between your project and associated scaffolds. However, be sure of what you are doing, as it is the nature ofthis application to write files!

Location of (*).scaffold.php

The *.scaffold.php file is covered in the upcoming chapters. For now, you just need to ensure that it is locatedin the project’s root directory, at the same level as your composer.json.

The reason why the scaffold configuration file (*.scaffold.php) needs to be located here, is due to the indexingperformed by the application. By default, it will search for scaffolds inside the local vendor directory, searching eachpackage’s root directory only!

Blank Scaffold

To create a blank scaffold, execute the following command;

vendor/bin/scaffold install -a

Select the Blank Scaffold (aedart/scaffold) scaffold to be installed and follow the onscreen guide.

Once completed, you should have a new empty *.scaffold.php file and a resources directory.

(*).scaffold.php

The *.scaffold.php file is the configuration file (a php array) that the scaffold application will read and executeupon installation. In short, it determines what will happen when an end-user installs it.

<?phpreturn [

'name' => 'My Scaffold',

'description' => 'Creates cool stuff',

'basePath' => __DIR__ . '/resources/',

'tasks' => [],

'folders' => [],

'files' => [],

'templateData' => [],

'templates' => [],

1.3. Create Scaffolds 7

Scaffold Documentation, Release 1.1

'scripts' => [],

'handlers' => [],];

In the following sections, each of the above properties is covered in detail.

Name

required yes

Name of the Scaffold.

The name is displayed in the list of available templates, when the install command is invoked.

<?phpreturn [

'name' => 'My Scaffold',

];

Description

required yes

Description of the scaffold.

The description is displayed in the list of available templates, when the install command is invoked.

<?phpreturn [

'description' => 'Creates a few things...',

];

BasePath

required yes

Location of scaffold’s resources, e.g. static files and templates.

This path tells the scaffold where it can find it’s resource, from which it can build and install one or several folders,files and or templates.

<?phpreturn [

'basePath' => __DIR__ . '/resources/',

];

8 Chapter 1. Contents

Scaffold Documentation, Release 1.1

Tasks

required yes

An ordered list of all the tasks that must be executed. These tasks are responsible for building your project or resource.

By default, several tasks are included in a blank scaffold. You can change these are you see fit, but keep in mind thatthe order does matter.

<?phpreturn [

'tasks' => [\Aedart\Scaffold\Tasks\AskForTemplateData::class,\Aedart\Scaffold\Tasks\AskForTemplateDestination::class,\Aedart\Scaffold\Tasks\CreateDirectories::class,\Aedart\Scaffold\Tasks\CopyFiles::class,\Aedart\Scaffold\Tasks\GenerateFilesFromTemplates::class,

],

];

Note: You can remove all of the default tasks and replace them with your own.

When creating custom tasks, just ensure that you implement the \Aedart\Scaffold\Contracts\Tasks\ConsoleTaskinterface.

You can also just extend the \Aedart\Scaffold\Tasks\BaseTask abstract task, which does some of theground work for you.

Please review the documentation inside the source code for further information.

Folders

required only if \Aedart\Scaffold\Tasks\CreateDirectories::class is used

List of directories (or folders) that will be created.

<?phpreturn [

'folders' => ['app','config','src' => [

'Contracts','Controllers','Events','Models',

],'tmp'

],

];

1.3. Create Scaffolds 9

Scaffold Documentation, Release 1.1

Files

required only if \Aedart\Scaffold\Tasks\CopyFiles::class is used

Copies files from basePath and into the output directory.

See BasePath

<?phpreturn [

'files' => [// Source files (inside 'basePath') => Destination'.gitkeep' => '.gitkeep','logs/default.log' => 'tmp/log.log','docs/LICENSE.txt' => 'LICENSE',

],

];

Warning: You should avoid large files. If your template requires such, then you should perhaps consider a customtask that can download them from an external source!

Alternatively, you can use scripts to perform large file downloads. Just remember to specify a timeout.

See Scripts

TemplateData

required only if the following tasks are useda \Aedart\Scaffold\Tasks\AskForTemplateData::class,b \Aedart\Scaffold\Tasks\AskForTemplateDestination::class,c \Aedart\Scaffold\Tasks\GenerateFilesFromTemplates::class

Data to be used inside Twig templates. Depending upon the template-data’s type, the end-user might be asked in theconsole for an answer.

You can specify as many template data entries as you wish.

<?phpreturn [

'templateData' => [

'myProperty' => ['value' => 'My property value'

],],

];

10 Chapter 1. Contents

Scaffold Documentation, Release 1.1

Syntax

<?phpreturn [

'templateData' => ['name-of-property' => [

'type' =>→˓\Aedart\Scaffold\Contracts\Templates\Data\Type::QUESTION

'question' => 'The question to ask the user''value' => (default value, in case user just hits enter),'validation' => function($answer){return $answer;},'postProcess' => function($answer, array $previousAnswers){return

→˓$answer;},],

]];

The postProcess callback method is automatically provided with eventual previous values. This gives you thepossibility creating computed values that combine previous given answers from the end-user. The postProcess isavailable for all supported types.

In the following sections, an example is shown on each supported type.

Question

<?phpreturn [

'templateData' => [

'myQuestion' => [

'type' =>→˓\Aedart\Scaffold\Contracts\Templates\Data\Type::QUESTION,

'question' => 'What is your vendor name? (used as namespace prefix)',

'value' => 'Acme',

'validation' => function($answer){if(strlen($answer) >= 3){

return $answer;}

throw new \RuntimeException('Vendor name should be at least 3 chars→˓long');

},

'postProcess' => function($answer, array $previousAnswers){return ucfirst($answer);

}],

],];

1.3. Create Scaffolds 11

Scaffold Documentation, Release 1.1

Choice

<?phpreturn [

'templateData' => [

'myChoice' => [

'type' => \Aedart\Scaffold\Contracts\Templates\Data\Type::CHOICE,

'question' => 'In what sub-namespace should your class be located?',

'choices' => ['Controllers','Events','Models'

],

'value' => 'Controllers',],

],];

Confirm

<?phpreturn [

'templateData' => [

'myConfirm' => [

'type' =>→˓\Aedart\Scaffold\Contracts\Templates\Data\Type::CONFIRM,

'question' => 'Add class PHPDoc?',

'value' => true,],

],];

Hidden

<?phpreturn [

'templateData' => [

'myPassword' => [

'type' => \Aedart\Scaffold\Contracts\Templates\Data\Type::HIDDEN,

'question' => 'What password should be stored inside the .env?',

12 Chapter 1. Contents

Scaffold Documentation, Release 1.1

'validation' => function($answer){if(strlen($answer) >= 6){

return $answer;}

throw new \RuntimeException('The password should be at least 6→˓characters long');

},],

],];

Value

When using a simple value, the end-user is not prompted with any questions. Also, the type does not have to bedeclared explicitly.

<?phpreturn [

'templateData' => [

'myValue' => ['value' => 'My Value'

],],

];

It is also possible to perform post-processing of simple values. It can be used to create a computed value which consistsof the given value and perhaps a previously given value.

<?phpreturn [

'templateData' => [

'myValue' => ['value' => 'My Value','postProcess' => function($answer, array $previousAnswers){

return $answer . $previousAnswers['myOtherValue'];}

],],

];

Templates

required only if the following tasks are useda \Aedart\Scaffold\Tasks\AskForTemplateData::class,b \Aedart\Scaffold\Tasks\AskForTemplateDestination::class,c \Aedart\Scaffold\Tasks\GenerateFilesFromTemplates::class

The snippets (or templates) from which one or several files must be generated from.

Each defined template assumes that it’s source Twig template is located inside the basePath.

See BasePath

1.3. Create Scaffolds 13

Scaffold Documentation, Release 1.1

<?phpreturn [

'templates' => ['myTemplate' => [

'source' => 'snippets/env.twig',

'destination' => [

'value' => '.env',],

],],

];

Ask for template destination

The destination property works in the same way as with the templateData, in that you can use it to ask theend user for a file destination. All types are supported.

See TemplateData.

<?phpreturn [

'templates' => ['myTemplate' => [

'source' => 'snippets/markdown.twig',

// Destination of a file - uses a "question" property'destination' => [

'type' =>→˓\Aedart\Scaffold\Contracts\Templates\Data\Type::QUESTION,

'question' => 'Name / location of file? (.md automatically added)→˓',

'value' => 'WIKI',

// Use post processing to add file extension'postProcess' => function($answer, array $previousAnswers){

return $answer . '.md';}

],],

],];

Scripts

required only if \Aedart\Scaffold\Tasks\ExecuteScripts::class is used

CLI scripts (or commands) to be executed

Scripts can be used to perform advanced operations. This could for instance be downloading large files, disk cleanup,running composer commands... etc.

14 Chapter 1. Contents

Scaffold Documentation, Release 1.1

Multiple scripts are allowed and they can be stated in several ways.

Simple Script

<?phpreturn [

'scripts' => ['composer update',

]];

Script with Timeout

If yor expect your script(s) to require more that 60 seconds, then consider specifying a custom timeout.

<?phpreturn [

'scripts' => [[

'timeout' => 75, // Default is 60 seconds'script' => 'composer install && composer update'

],]

];

Advanced Script

If you need to perform very advanced scripts that depends on the scaffold configuration, then you can achieve this viaan anonymous function.

A copy of the scaffold configuration is given as argument.

The function MUST return an instance of \Aedart\Scaffold\Contracts\Scripts\CliScript.

<?phpreturn [

'scripts' => [function(array $config){

$script = 'cd ' . $config['outputPath'] . ' && ls';

return new \Aedart\Scaffold\Scripts\CliScript(['timeout' => 10,'script' => $script

]);},

]];

Error when triggering composer commands

If you trigger some kind of composer script, then you might see that composer’s output is logger to the console asan error. This is due to that composer chooses to write diagnostic output to STDERR instead of STDOUT.

1.3. Create Scaffolds 15

Scaffold Documentation, Release 1.1

You can read more about this in #1905 and #3795 .

Handlers

required no

These handlers are used by some of the default tasks. They provide an additional level of flexibility, in which you canuse the default tasks, yet change the way that each of them handles certain operations.

If you do not plan to change the default tasks’ behaviour, then you can leave out this part of the configuration.

<?phpreturn [

'handlers' => ['directory' => \Aedart\Scaffold\Handlers\DirectoriesHandler::class,'file' => \Aedart\Scaffold\Handlers\FilesHandler::class,'property' => \Aedart\Scaffold\Handlers\PropertyHandler::class,'template' => \Aedart\Scaffold\Handlers\TwigTemplateHandler::class,'script' => \Aedart\Scaffold\Handlers\ScriptsHandler::class,

]];

Note: You can create your own handlers, if the default handlers are insufficient to cover your needs.

Handlers need to implement the \Aedart\Scaffold\Contracts\Handlers\Handler interface.

Alternatively, you can extend the \Aedart\Scaffold\Handlers\BaseHandler abstract handler. It shouldprovide you with a few common methods implementation.

Tip: Currently, only Twig templates are supported. If you do not like working with that engine,then you can implement a different one, by means of creating a new template handler (Please review\Aedart\Scaffold\Handlers\TwigTemplateHandler for inspiration).

If this is the case, please consider if making that handler publicly available for others :)

Testing

Depending on your scaffold complexity, the fastest way of testing it is manually, by building it locally.

vendor/bin/scaffold install -a -o temp/

The above command will first index your scaffold and thereafter install it. All of it’s output will go into the tempdirectory.

Automatic Testing

If your scaffold(s) have become very complex, require lots of user input or perhaps depend on many resources, thenperhaps it is better to write some kind of automatic test for, e.g. via PHPUnit .

The current version of the scaffold application does not offer any testing utilities. However, you can review thetests\integration\InstallCommandTest as inspiration on how to write automatic tests for your scaffold.

Behind the scenes, Symfony’s Command Tester is being used.

16 Chapter 1. Contents

Scaffold Documentation, Release 1.1

In future versions, this package might include better testing utilities.

Helpers

Since version 1.1.0 a helpers.php file is included, which offers a few utility methods that can be used throughoutyour scaffold.

The file is located in {{scaffold application location}}\helpers\helpers.php.

Cache

Available since version 1.1.0

Confronting an end-user with too many questions can quickly become a hassle for them. Therefore, if you find yourselfin a situation where you need a lot of user input, consider caching some of the input.

Caching is made available in a scaffold, by making use of the scaffold_cache_* methods, which are definedinside the helpers.php file.

Behind the Scene

The caching system that is offered by the Scaffold Application, is basically just a wrapper around Laravel’s Cache. It is configured to use the \Illuminate\Cache\FileStore, storing values withing the user provided cachedirectory.

The cache directory is set via a --cache option on each available command that makes use of caching. It defaults.scaffold/cache/ if the option is not provided.

Example

In this example, once a user has answered the question first time, the scaffold will use a cached answer as the defaultvalue. Next time the scaffold is built, the default value will become the cached value.

<?phpreturn [

'templateData' => [

'name' => [

'type' =>→˓\Aedart\Scaffold\Contracts\Templates\Data\Type::QUESTION,

'question' => 'What is your name?',

'value' => scaffold_cache_get('name', 'John Doe'),

'postProcess' => function($answer, array $previousAnswers){// Update the cached value, in case user provides a "new" answerscaffold_cache_put('name', $answer, 60);

return $answer;}

],

1.3. Create Scaffolds 17

Scaffold Documentation, Release 1.1

],];

Available Methods

Please consider Laravel’s documentation for further information and examples of using the cache.

scaffold_cache()

Returns an instance of \Illuminate\Contracts\Cache\Repository.

scaffold_cache_put($key, $value, $minutes = 5)

Store an item in the cache.

scaffold_cache_remember($key, $minutes, Closure $callback)

Get an item from the cache, or store the default value.

scaffold_cache_forever($key, $value)

Store an item in the cache indefinitely.

scaffold_cache_has($key)

Determine if an item exists in the cache.

scaffold_cache_get($key, $default = null)

Retrieve an item from the cache by key.

scaffold_cache_pull($key, $default = null)

Retrieve an item from the cache and delete it.

scaffold_cache_forget($key)

Remove an item from the cache.

scaffold_cache_flush()

Flushes the registered cache directory.

Misc

18 Chapter 1. Contents

Scaffold Documentation, Release 1.1

Release Notes

Within this chapter, you will find a list of the most significant changes.

Version 2.0.x

v2.0.1 (29-10-2017)

Fixed

• Incorrect populate of directories collection inside TwigTemplateHandler

v2.0.0 (15-10-2017)

Added

• Added “build:file” command

Changed

• Changed minimum required PHP version to 7.1.x

• Adapted application to use Laravel 5.5.x. Several interfaces and service providers have changed.

• Adapted application to use Symfony 3.3.x components.

• Deprecated AedartScaffoldTestingConsoleStyleExtendedStyle, replaced by AedartScaffoldConsoleStyleExtend-edStyle.

• Changed build command, now supports setting answers to questions via the input option.

Version 1.2.x

v1.2.0 (08-01-2017)

Changed

• License updated

Version 1.1.x

v1.1.5 (01-10-2016)

Fixed

• Re-fixed indexing order. First fix was correct, yet due to incorrect manual test, the “issue” didn’t seemed fixed.

1.4. Release Notes 19

Scaffold Documentation, Release 1.1

v1.1.4 (01-10-2016)

Fixed

• Re-fixed order of default indexing directories. First fix caused undesired indexing results.

v1.1.3 (01-10-2016)

Fixed

• Fixed order of default index directories.

v1.1.2 (22-09-2016)

Fixed

• Fixed #4 Parse error: syntax error, unexpected ‘->’ (T_OBJECT_OPERATOR) (issue in PHP 5.6.x only)

v1.1.1 (18-09-2016)

Fixed

• Fixed Fatal error: Can’t use function return value in write context (issue in PHP 5.6.x only)

v1.1.0 (18-09-2016)

Added

• Added Cache utility (#3).

• Added release notes documentation

• Added multiple smaller and more maintainable service providers

• Added documentation about why output from composer commands (in scripts) are logged to STDERR

Changed

• Changed ScaffoldServiceProvider, has now become an AggregateServiceProvider instead.It registers a series of smaller service providers.

Version 1.0.x

v1.0.4 (17-09-2016)

Fixed

• Fixed ScriptHandler logging of empty buffer

20 Chapter 1. Contents

Scaffold Documentation, Release 1.1

v1.0.3 (17-09-2016)

Fixed

• Fixed ScriptHandler dual logging of buffered output

v1.0.2 (17-09-2016)

Fixed

• Fixed console logging attempted converting array into string

v1.0.1 (17-09-2016)

Changed

• Changed required dependencies

Fixed

• Fixed property value being cast to string, which caused issue for other types of values, e.g. arrays

• Fixed unstable tests, due to poor generated sample data

v1.0.0 (11-09-2016)

• Release of first stable version

Indices

genindex

1.5. Indices 21

Scaffold Documentation, Release 1.1

22 Chapter 1. Contents

Index

BBasePath

scaffold.php, 8Blank

Empty Scaffold, 7Build

Command, Install, 4Build-File

File Command, 4

CCache, 17CLI, 14Command

Build-File File, 4Install Build, 4

Command TesterSymfony, 16

ComposerSTDERR, 14STDOUT, 14

DDescription

scaffold.php, 8

EEmpty

Scaffold, Blank, 7Scaffold, Location, 6

FFile

Command, Build-File, 4Files

scaffold.php, 9Folders

scaffold.php, 9

GGlobal

Installation, 3

HHandlers

scaffold.php, 16helpers, 17

IInstall

Build Command, 4Installation

Global, 3Local, 3

LLocal

Installation, 3Location

Empty Scaffold, 6Output, 4Scaffold, 6

NName

scaffold.php, 8New

Scaffold, 7

OOutput

Location, 4

PPHPUnit

UnitTest, 16

RRelease Notes, 18

23

Scaffold Documentation, Release 1.1

RequireScaffold, 4

Requirements, 3

SScaffold

Blank Empty, 7Location, 6Location Empty, 6New, 7Require, 4

scaffold.php, 6, 7BasePath, 8Description, 8Files, 9Folders, 9Handlers, 16Name, 8Scripts, 14Tasks, 8TemplateData, 10Templates, 13

Scriptsscaffold.php, 14

Single: Build, 4Single: Build-File, 4Single: Install, 4STDERR

Composer, 14STDOUT

Composer, 14Symfony

Command Tester, 16

TTasks

scaffold.php, 8TemplateData

scaffold.php, 10Templates

scaffold.php, 13Testing, 16

UUnitTest

PHPUnit, 16

24 Index