Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelgfeller committed Mar 30, 2024
0 parents commit c22da9c
Show file tree
Hide file tree
Showing 59 changed files with 2,530 additions and 0 deletions.
58 changes: 58 additions & 0 deletions .cs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

use PhpCsFixer\Config;

return (new Config())
->setUsingCache(false)
->setRiskyAllowed(true)
->setRules(
[
'@PSR1' => true,
'@PSR2' => true,
'@Symfony' => true,
'@PSR12' => true,
'strict_param' => true,
'psr_autoloading' => true,
// custom rules
'align_multiline_comment' => ['comment_type' => 'phpdocs_only'], // psr-5
'phpdoc_to_comment' => false,
'no_superfluous_phpdoc_tags' => false,
'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'cast_spaces' => ['space' => 'none'],
'concat_space' => ['spacing' => 'one'],
'compact_nullable_type_declaration' => true,
'nullable_type_declaration' => true,
'nullable_type_declaration_for_default_null_value' => true,
'declare_equal_normalize' => ['space' => 'single'],
'declare_strict_types' => false,
'increment_style' => ['style' => 'post'],
'list_syntax' => ['syntax' => 'short'],
'echo_tag_syntax' => ['format' => 'long'],
'phpdoc_add_missing_param_annotation' => ['only_untyped' => false],
'phpdoc_align' => false,
'phpdoc_no_empty_return' => false,
'phpdoc_order' => true, // psr-5
'phpdoc_no_useless_inheritdoc' => false,
'protected_to_private' => false,
'yoda_style' => false,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'ordered_imports' => [
'sort_algorithm' => 'alpha',
'imports_order' => ['class', 'const', 'function']
],
'single_line_throw' => false,
'fully_qualified_strict_types' => true,
'global_namespace_import' => false,
]
)
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__ . '/src')
->in(__DIR__ . '/tests')
->in(__DIR__ . '/config')
->in(__DIR__ . '/public')
->name('*.php')
->ignoreDotFiles(true)
->ignoreVCS(true)
);
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.eot binary
*.ttf binary
*.woff binary
*.woff2 binary
*.otf binary
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ko_fi: samuelgfeller
82 changes: 82 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: 🧪 Build test
on:
push:
branches:
- master
- develop
pull_request:
types: [ opened, synchronize, reopened ]

env:
APP_ENV: github

jobs:
run:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ ubuntu-latest ]
php-versions: [ '8.2' ]
test-database: [ 'slim_api_starter_test' ]
name: PHP ${{ matrix.php-versions }} Test

services:
mysql:
image: mysql:8.0.23
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: test
ports:
- 33306:3306

steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
extensions: mbstring, pdo, pdo_mysql, intl, zip
coverage: xdebug

- name: Check PHP version
run: php -v

- name: Check Composer version
run: composer -V

- name: Check PHP extensions
run: php -m

- name: Check MySQL version
run: mysql -V

- name: Start MySQL
run: sudo systemctl start mysql

- name: Check MySQL variables
run: mysql -uroot -proot -e "SHOW VARIABLES LIKE 'version%';"

- name: Set MySQL timezone to swiss time
run: mysql -uroot -proot -e "SET GLOBAL time_zone = '+01:00';"

- name: Create database
run: mysql -uroot -proot -e 'CREATE DATABASE IF NOT EXISTS ${{ matrix.test-database }} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'

- name: Validate composer.json and composer.lock
run: composer validate

- name: Install dependencies
run: composer update --no-ansi --no-interaction --no-progress

- name: Execute database migrations
run: composer migrate-prod

- name: Show test db tables
run: mysql -uroot -proot -D ${{ matrix.test-database }} -e "SHOW TABLES;"

- name: Run test suite
run: composer test:coverage
env:
PHP_CS_FIXER_IGNORE_ENV: 1
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/vendor/
/.idea/
/config/env/env.php
/logs/*.log
/var/cache/*
/composer.lock
/.gtm/
6 changes: 6 additions & 0 deletions .htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Turn on the rewrite engine
RewriteEngine on
# If the URL path is empty, rewrite to the 'public/' directory
RewriteRule ^$ public/ [L]
# For any requested URL path, rewrite to the 'public/' directory followed by the requested path
RewriteRule (.*) public/$1 [L]
15 changes: 15 additions & 0 deletions LICENCE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Copyright (c) 2024 Samuel Gfeller

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
97 changes: 97 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<div align="center">

<h1>Slim <img src="https://i.imgur.com/YzDYQ0V.png" width="60px" alt="API"> starter</h1>

[![Latest Version on Packagist](https://img.shields.io/github/release/samuelgfeller/slim-api-starter.svg)](https://packagist.org/packages/slim-api-starter)

[Slim 4](https://www.slimframework.com/) API starter template with a few examples and some essential [features](#features) to
build a secure and scalable API following 2024 best practices and
[SOLID](https://en.wikipedia.org/wiki/SOLID) principles.

An extensive [documentation](https://github.com/samuelgfeller/slim-example-project/wiki) explains
the project structure, components, design choices and features.

</div>

## Features

* [Dependency Injection](https://github.com/samuelgfeller/slim-example-project/wiki/Dependency-Injection)
* [Database migrations](https://github.com/samuelgfeller/slim-example-project/wiki/Database-Migrations)
* [Validation](https://github.com/samuelgfeller/slim-example-project/wiki/Validation)
* [Error handling](https://github.com/samuelgfeller/slim-example-project/wiki/Error-Handling)
* [Logging](https://github.com/samuelgfeller/slim-example-project/wiki/Logging)
* [Integration testing](https://github.com/samuelgfeller/slim-example-project/wiki/Writing-Tests)
* [Query Builder](https://github.com/samuelgfeller/slim-example-project/wiki/Repository-and-Query-Builder)
* [GitHub Actions](https://github.com/samuelgfeller/slim-example-project/wiki/GitHub-Actions)
* [Coding standards fixer](https://github.com/samuelgfeller/slim-example-project/wiki/Coding-Standards-Fixer)
* [PHPStan static code analysis](https://github.com/samuelgfeller/slim-example-project/wiki/PHPStan-Static-Code-Analysis)


## Requirements
* PHP 8.2+
* [Composer](https://github.com/samuelgfeller/slim-example-project/wiki/Composer)
* MariaDB or MySQL database

## Installation
#### 1. Create project
Navigate to the directory you want to create the project in and run the following
command, replacing [project-name] with the desired name for your project.
```bash
composer create-project samuelgfeller/slim-api-starter [project-name]
```
This will create a new directory with the specified name and install all
necessary dependencies.

#### 2. Set up the database
Open the project and rename the file `config/env/env.example.php` to `env.php`
and add the local database credentials.

Then, create the database on the server and update the `config/env/env.dev.php`
file with the name of the database, like this:
```php
$settings['db']['database'] = 'my_dev_database_name';
```
After that, create a separate database for testing and update the `config/env/env.test.php`
file with its name. The name must contain the word "test". There is a safety measure to
prevent accidentally truncating the development database while testing:
```php
$settings['db']['database'] = 'my_dev_database_name_test';
```

#### 3. Run migrations
Open the terminal in the project's root directory and run the following command to create the
demo table `user`:
```bash
composer migrate
```

### 4. Insert demo data
You can install four demo users into the database to test the API response by
running the following command:

```bash
composer seed
```

#### 5. Update GitHub workflows

To run the project's tests automatically when pushing, update the
`.github/workflows/develop.yml` file.
Replace the matrix value "test-database" `slim_api_starter_test` with the name of
your test database as you specified in `config/env/env.test.php`.
If you are not using Scrutinizer, remove the "Scrutinizer Scan" step from the workflow.

### Done!
That's it! Your project should now be fully set up and ready to use.
If you are using XAMPP and installed the project in the `htdocs` folder, you can access it via
http://localhost/project-name.
Or you can serve it locally by running `php -S localhost:8080 -t public/` in the project's root
directory.

## Support
If you value this project and want to support it,
visit the [Support❤️](https://github.com/samuelgfeller/slim-example-project/wiki/Support❤️) page. (thank you!)

## License
This project is licensed under the MIT Licence — see the
[LICENCE](https://github.com/samuelgfeller/slim-example-project/blob/master/LICENCE.txt) file for details.
29 changes: 29 additions & 0 deletions bin/console.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
/**
* Execute a class function instantiated by the container with the command line.
* The first argument is the container key and the second the function name that should be called.
* Example: php bin/console.php SqlSchemaGenerator generateSqlSchema
*/

// Boot the application
$app = require __DIR__ . '/../config/bootstrap.php';

/** Get the container instance @var Psr\Container\ContainerInterface $container */
$container = $app->getContainer();

// The $argv variable is an array that contains the command-line arguments passed to the script.
// The first element of the $argv array is always the name of the script itself ('bin/console.php').
// array_shift($argv) removes this first element that is not relevant here.
array_shift($argv);

// The now first parameter after the script name that was removed is the class name.
// The second element in the $argv array is the function name.
[$containerKey, $functionName] = $argv;

// Retrieve the instance corresponding to the $containerKey form the container.
$objectInstance = $container->get($containerKey);

// The call_user_func_array function is used to call the specified function on the retrieved instance.
// In this case, it's calling the function specified by $functionName on the object instance.
// The second parameter is an empty array, which means no parameters are passed to the function.
call_user_func_array([$objectInstance, $functionName], []);
64 changes: 64 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"name": "samuelgfeller/slim-api-starter",
"description": "Example project with the slim micro-framework",
"type": "project",
"license": "MIT",
"require": {
"slim/slim": "^4",
"monolog/monolog": "^3",
"php-di/php-di": "^7.0",
"cakephp/database": "^5",
"selective/basepath": "^2.0",
"nyholm/psr7": "^1.5",
"nyholm/psr7-server": "^1.1",
"cakephp/validation": "^5",
"fig/http-message-util": "^1.1",
"php": "^8.2",
"ext-pdo": "*",
"ext-json": "*"
},
"require-dev": {
"roave/security-advisories": "dev-latest",
"phpunit/phpunit": "^11",
"phpstan/phpstan": "^1",
"jetbrains/phpstorm-attributes": "^1.0",
"friendsofphp/php-cs-fixer": "^3",
"odan/phinx-migrations-generator": "^6",
"samuelgfeller/test-traits": "^5"
},
"autoload": {
"psr-4": {
"App\\": "src/"
},
"files": [
"config/functions.php"
]
},
"autoload-dev": {
"psr-4": {
"App\\Test\\": "tests/"
}
},
"scripts": {
"stan": "phpstan analyse -c phpstan.neon --no-progress --ansi",
"test": "php ./vendor/bin/phpunit --configuration phpunit.xml --do-not-cache-result --colors=always",
"test:coverage": "vendor/bin/phpunit --coverage-clover=coverage.xml",
"cs:check": "php-cs-fixer fix --dry-run --format=txt --verbose --diff --config=.cs.php --ansi",
"cs:fix": "php-cs-fixer fix --config=.cs.php --ansi --verbose",
"migration:generate": [
"phinx-migrations generate --overwrite -c config/env/env.phinx.php --ansi",
"@schema:generate"
],
"migrate-prod": "vendor/bin/phinx migrate -c config/env/env.phinx.php --ansi -vvv",
"migrate": [
"@migrate-prod",
"@schema:generate"
],
"schema:generate": [
"php bin/console.php SqlSchemaGenerator generateSqlSchema",
"@add-migrations-to-git"
],
"add-migrations-to-git": "git add resources/migrations/* && git add resources/schema/*",
"seed": "php vendor/bin/phinx seed:run -c config/env/env.phinx.php"
}
}
14 changes: 14 additions & 0 deletions config/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

use DI\ContainerBuilder;
use Slim\App;

require __DIR__ . '/../vendor/autoload.php';

// Instantiate DI ContainerBuilder
$containerBuilder = new ContainerBuilder();
// Add container definitions and build DI container
$container = $containerBuilder->addDefinitions(__DIR__ . '/container.php')->build();

// Create app instance
return $container->get(App::class);
Loading

0 comments on commit c22da9c

Please sign in to comment.