Initial commit
This commit is contained in:
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# This is the top-most .editorconfig file; do not search in parent directories.
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# All files.
|
||||||
|
[*]
|
||||||
|
end_of_line = LF
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.DS_Store
|
||||||
|
.vscode
|
||||||
|
/vendor
|
||||||
|
composer.lock
|
||||||
|
.phpunit.result.cache
|
||||||
|
/var
|
||||||
|
.php-cs-fixer.cache
|
||||||
32
.php-cs-fixer.dist.php
Normal file
32
.php-cs-fixer.dist.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
return (new PhpCsFixer\Config())
|
||||||
|
->setRules([
|
||||||
|
'@Symfony' => true,
|
||||||
|
|
||||||
|
'binary_operator_spaces' => [
|
||||||
|
'operators' => [
|
||||||
|
'=' => 'align_single_space',
|
||||||
|
'=>' => 'align_single_space',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'single_blank_line_at_eof' => true,
|
||||||
|
'phpdoc_align' => false,
|
||||||
|
'phpdoc_to_comment' => false,
|
||||||
|
'strict_comparison' => true,
|
||||||
|
'declare_strict_types' => true,
|
||||||
|
'single_trait_insert_per_statement' => false,
|
||||||
|
'nullable_type_declaration_for_default_null_value' => true,
|
||||||
|
'increment_style' => [
|
||||||
|
'style' => 'post',
|
||||||
|
],
|
||||||
|
])
|
||||||
|
->setFinder(
|
||||||
|
(new PhpCsFixer\Finder())
|
||||||
|
->in(__DIR__)
|
||||||
|
->exclude('var')
|
||||||
|
)
|
||||||
|
;
|
||||||
6
Containerfile
Normal file
6
Containerfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM php:8.3-alpine
|
||||||
|
|
||||||
|
WORKDIR /code
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||||
|
COPY ./ /code
|
||||||
|
|
||||||
16
Makefile
Normal file
16
Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
PHP = docker compose run php
|
||||||
|
|
||||||
|
.PHONY: composer_install composer_update static_analysis tests
|
||||||
|
|
||||||
|
composer_install:
|
||||||
|
@$(PHP) composer install
|
||||||
|
|
||||||
|
composer_update:
|
||||||
|
@$(PHP) composer update
|
||||||
|
|
||||||
|
static_analysis:
|
||||||
|
@$(PHP) vendor/bin/psalm
|
||||||
|
|
||||||
|
tests:
|
||||||
|
@$(PHP) rm -rf var/cache
|
||||||
|
@$(PHP) vendor/bin/phpunit
|
||||||
119
README.md
Normal file
119
README.md
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# Symfony Bundle Skeleton
|
||||||
|
|
||||||
|
A **WORK IN PROGRESS** skeleton for creating Symfony Bundles.
|
||||||
|
|
||||||
|
This skeleton is a very basic bundle with comments explaining what various bits are doing.
|
||||||
|
|
||||||
|
The bundle is called `PcmExampleBundle` and contains a `Greeting` class with a `greet(): string` method.
|
||||||
|
|
||||||
|
The `greet()` method returns a string welcoming someone who's name you can specify in the bundle configuration file.
|
||||||
|
|
||||||
|
|
||||||
|
# Installing dependencies
|
||||||
|
|
||||||
|
You need to run `docker compose run php` before any composer commands. EG:
|
||||||
|
```sh
|
||||||
|
docker compose run php composer require symfony/twig-bundle
|
||||||
|
```
|
||||||
|
The Makefile has some common shorthands as usual.
|
||||||
|
|
||||||
|
|
||||||
|
# Modifying this bundle
|
||||||
|
|
||||||
|
To change this bundle from `pcm/example-bundle` to something new there are few files you need to change.
|
||||||
|
|
||||||
|
1. **Bundle PHP file and namespace**
|
||||||
|
|
||||||
|
The file at `src/PcmExampleBundle.php` should have it's class name and filename changed.
|
||||||
|
|
||||||
|
If you are creating a bundle called `pcm/epic-login-bundle` the namespace should be `Pcm\EpicLogin`
|
||||||
|
while the class name should be `PcmEpicLoginBundle`.
|
||||||
|
|
||||||
|
Subsequently, all namespaces should be changed to start with `pcm\epiclogin`.
|
||||||
|
|
||||||
|
2. **composer metadata**
|
||||||
|
|
||||||
|
Update the `name` and `description` fields of the `composer.json` file with appropriate names.
|
||||||
|
The name should
|
||||||
|
|
||||||
|
You will also need to update the PSR autoload classes with your bundle's class name.
|
||||||
|
|
||||||
|
Optionally edit the authors if required.
|
||||||
|
|
||||||
|
3. **Config files**
|
||||||
|
|
||||||
|
- Chamge 'bundles.php` to use your new bundle class
|
||||||
|
- Modify `services.yaml` when required
|
||||||
|
- Update `definition.yaml` to specify your config structure (or remove if no config is required)
|
||||||
|
|
||||||
|
4. **Test files**
|
||||||
|
|
||||||
|
The `TestKernel` needs to return an array containing your bundle class.
|
||||||
|
|
||||||
|
Again, namespaces need changing to whatever is appropriate.
|
||||||
|
|
||||||
|
# PHPUnit testing
|
||||||
|
|
||||||
|
The bundle and it's configuration can be tested with PHPUnit.
|
||||||
|
|
||||||
|
This was a worthwhile section to add.
|
||||||
|
|
||||||
|
|
||||||
|
# Installing a development version of the bundle
|
||||||
|
|
||||||
|
If you need to install the bundle to test stuff (EG to see how certain Twig templates look, etc) you can do so
|
||||||
|
by using a development version of the bundle.
|
||||||
|
|
||||||
|
### Preparing the composer.json file
|
||||||
|
|
||||||
|
First, make sure your Symfony project has the following in it's `composer.json` file:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Next, you need to add the repository to the `composer.json` file, just as you would any other PCM bundle:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "ssh://example/bundle.git"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installing the development bundle
|
||||||
|
|
||||||
|
You can now install the bundle with composer. Because the bundle does not yet have a tagged version we
|
||||||
|
have to specify that it's a dev bundle alongside a branch to use. For example:
|
||||||
|
```sh
|
||||||
|
composer require pcm/example-bundle:dev-develop
|
||||||
|
```
|
||||||
|
|
||||||
|
The `dev-develop` part is specifying both that it's a **dev** package and that we want to use the **develop** branch. If you wanted to use the `master` branch you would specify as so: `dev-master`.
|
||||||
|
|
||||||
|
If a flex recipe is present it will prompt you to install it.
|
||||||
|
|
||||||
|
**NOTE** that the "symfony.lock" file will generate an incorrect version number "develop.9999999". This causes issues when uninstalling, so manually change this value to be `dev-develop` or whichever version you installed.
|
||||||
|
|
||||||
|
### Updating the development bundle
|
||||||
|
|
||||||
|
You can make changes to the bundle whilst it's installed. Once you've pushed your changes with git you can run a composer update to retrieve the most recent changes:
|
||||||
|
```sh
|
||||||
|
composer update pcm/example-bundle
|
||||||
|
```
|
||||||
|
|
||||||
|
### Uninstalling your development bundle
|
||||||
|
|
||||||
|
Make sure that the bundle version is correct in the `symfony.lock` file (see above) before running the usual uninstall command:
|
||||||
|
```sh
|
||||||
|
composer remove pcm/example-bundle
|
||||||
|
```
|
||||||
|
|
||||||
|
# Creating a flex recipe
|
||||||
|
|
||||||
|
See the flex recipe repo for info on how to do this.
|
||||||
7
compose.yml
Normal file
7
compose.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
services:
|
||||||
|
php:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Containerfile
|
||||||
|
volumes:
|
||||||
|
- ./:/code
|
||||||
40
composer.json
Normal file
40
composer.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "pcm/example-bundle",
|
||||||
|
"description": "PCM Example Bundle",
|
||||||
|
"type": "symfony-bundle",
|
||||||
|
"license": "MIT",
|
||||||
|
"version": "dev-develop",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Bradley Goode",
|
||||||
|
"email": "bg@pcmsystems.co.uk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Matt Feeney",
|
||||||
|
"email": "mf@pcmsystems.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Pcm\\ExampleBundle\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Pcm\\ExampleBundle\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"require": {
|
||||||
|
"symfony/dependency-injection": "^7.1",
|
||||||
|
"symfony/framework-bundle": "^7.1",
|
||||||
|
"symfony/yaml": "^7.1"
|
||||||
|
},
|
||||||
|
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/test-pack": "^1.1",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.61"
|
||||||
|
}
|
||||||
|
}
|
||||||
12
config/bundles.php
Normal file
12
config/bundles.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
// Here we define the environments the bundle is allowed to be in.
|
||||||
|
//
|
||||||
|
// Most of the time we probably want to have access to our bundle
|
||||||
|
// in all environments (prod, dev, test etc).
|
||||||
|
return [
|
||||||
|
Pcm\ExampleBundle\PcmExampleBundle::class => ['all' => true],
|
||||||
|
];
|
||||||
|
|
||||||
16
config/definition.php
Normal file
16
config/definition.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
|
||||||
|
|
||||||
|
// This file is imported and used by the main bundle class to
|
||||||
|
// define how the configuration should look.
|
||||||
|
return static function (DefinitionConfigurator $definition): void {
|
||||||
|
$definition->rootNode()
|
||||||
|
->children()
|
||||||
|
->scalarNode('name')->defaultValue('Mr. NoName')->cannotBeEmpty()->end()
|
||||||
|
->end()
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
28
config/services.yaml
Normal file
28
config/services.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
|
# Hide the fully qualified Greeting class name from public view
|
||||||
|
# but give the class an alias. This alias will be made public instead.
|
||||||
|
#
|
||||||
|
# Read the documentation to see why we do this:
|
||||||
|
# https://symfony.com/doc/current/service_container/autowiring.html#service-autowiring-alias
|
||||||
|
#
|
||||||
|
Pcm\ExampleBundle\Greeting:
|
||||||
|
public: false
|
||||||
|
alias: pcm_example.greeting
|
||||||
|
|
||||||
|
|
||||||
|
# Mark the alias we created as public.
|
||||||
|
pcm_example.greeting:
|
||||||
|
public: true
|
||||||
|
class: Pcm\ExampleBundle\Greeting
|
||||||
|
|
||||||
|
|
||||||
|
# If we were defining a twig extension, we'd want to add the twig.runtime tag
|
||||||
|
# so it loads correctly.
|
||||||
|
#
|
||||||
|
# Pcm\ExampleBundle\SomeTwigRuntime
|
||||||
|
# tags:
|
||||||
|
# - { name: twig.runtime }
|
||||||
19
phpunit.xml.dist
Normal file
19
phpunit.xml.dist
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="./vendor/autoload.php">
|
||||||
|
<coverage>
|
||||||
|
<include>
|
||||||
|
<directory>./src</directory>
|
||||||
|
</include>
|
||||||
|
</coverage>
|
||||||
|
<php>
|
||||||
|
<ini name="error_reporting" value="-1"/>
|
||||||
|
<ini name="intl.default_locale" value="en"/>
|
||||||
|
<ini name="intl.error_level" value="0"/>
|
||||||
|
<ini name="memory_limit" value="-1"/>
|
||||||
|
</php>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Test suite">
|
||||||
|
<directory suffix="Test.php">./tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
</phpunit>
|
||||||
18
src/Greeting.php
Normal file
18
src/Greeting.php
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pcm\ExampleBundle;
|
||||||
|
|
||||||
|
final class Greeting
|
||||||
|
{
|
||||||
|
public function __construct(private string $name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function greetPerson(): string
|
||||||
|
{
|
||||||
|
return sprintf("Hello there %s! Hope you're well.", $this->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
44
src/PcmExampleBundle.php
Normal file
44
src/PcmExampleBundle.php
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pcm\ExampleBundle;
|
||||||
|
|
||||||
|
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
|
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
|
||||||
|
|
||||||
|
final class PcmExampleBundle extends AbstractBundle
|
||||||
|
{
|
||||||
|
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Load the services defined in services.yaml into the container.
|
||||||
|
*/
|
||||||
|
$container->import('../config/services.yaml');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "$config" variable contains an array representing the
|
||||||
|
* configuration and it's values.
|
||||||
|
*
|
||||||
|
* We can use it to configure the service container, for example
|
||||||
|
* by passing in arguments to any services we have defined.
|
||||||
|
*
|
||||||
|
* (see services.yaml)
|
||||||
|
*/
|
||||||
|
$container->services()
|
||||||
|
->get('pcm_example.greeting')
|
||||||
|
->arg('$name', $config['name'])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configure(DefinitionConfigurator $definition): void
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Import the config definition (see definition.php)
|
||||||
|
*/
|
||||||
|
$definition->import('../config/definition.php');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
45
tests/Config/ConfigurationTest.php
Normal file
45
tests/Config/ConfigurationTest.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pcm\ExampleBundle\Tests\Config;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Configuration;
|
||||||
|
use Symfony\Component\Config\Definition\Processor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to make sure the config validation is working as expected.
|
||||||
|
*/
|
||||||
|
class ConfigurationTest extends TestCase
|
||||||
|
{
|
||||||
|
private Configuration $configuration;
|
||||||
|
private Processor $processor;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->configuration = new Configuration(true);
|
||||||
|
$this->processor = new Processor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testThrowsIfNameIsEmpty()
|
||||||
|
{
|
||||||
|
$config = $this->getValidConfig();
|
||||||
|
$config['name'] = '';
|
||||||
|
$this->expectException(\Exception::class);
|
||||||
|
$this->validateConfig($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validateConfig(array $config): array
|
||||||
|
{
|
||||||
|
return $this->processor->processConfiguration($this->configuration, [$config]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getValidConfig(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => 'Boris',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
26
tests/TestKernel.php
Normal file
26
tests/TestKernel.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pcm\ExampleBundle\Tests;
|
||||||
|
|
||||||
|
use Pcm\ExampleBundle\PcmExampleBundle;
|
||||||
|
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||||
|
use Symfony\Component\HttpKernel\Kernel;
|
||||||
|
|
||||||
|
final class TestKernel extends Kernel
|
||||||
|
{
|
||||||
|
public function registerBundles(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new PcmExampleBundle()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerContainerConfiguration(LoaderInterface $loader): void
|
||||||
|
{
|
||||||
|
// Ignore this
|
||||||
|
// $loader->load(__DIR__.'/../config/packages/pcm_example.yaml');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user