Initial commit

This commit is contained in:
pcm-libraries
2024-08-07 15:04:23 +00:00
commit a4f4e1990c
17 changed files with 450 additions and 0 deletions

14
.editorconfig Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1,6 @@
FROM php:8.3-alpine
WORKDIR /code
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
COPY ./ /code

1
LICENSE Normal file
View File

@@ -0,0 +1 @@
License

16
Makefile Normal file
View 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
View 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
View File

@@ -0,0 +1,7 @@
services:
php:
build:
context: .
dockerfile: Containerfile
volumes:
- ./:/code

40
composer.json Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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');
}
}

View 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
View 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');
}
}