Skip to content

Commit c310794

Browse files
committed
Initial. Based off of phpexperts/mini-api-base.
0 parents  commit c310794

23 files changed

+8055
-0
lines changed

.codeclimate.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"version": "2",
3+
"checks": {
4+
"method-complexity": {
5+
"config": {
6+
"threshold": 10
7+
}
8+
},
9+
"method-count": {
10+
"config": {
11+
"threshold": 30
12+
}
13+
},
14+
"return-statements": {
15+
"config": {
16+
"threshold": 10
17+
}
18+
}
19+
}
20+
}

.env.dist

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
APP_KEY=""
2+
3+
DB_CONNECTION="pgsql"
4+
DB_HOST=localhost
5+
DB_USERNAME=root
6+
DB_PASSWORD=root
7+
DB_DATABASE=test
8+

.framework/ApiKeyManager.php

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace PHPExperts\MiniApiBase;
4+
5+
use http\Exception\RuntimeException;
6+
use Illuminate\Support\Facades\DB;
7+
8+
class ApiKeyManager
9+
{
10+
public static function generateUuidV4(): string
11+
{
12+
$data = random_bytes(16);
13+
14+
// Set the version to 0100
15+
$data[6] = chr((ord($data[6]) & 0x0f) | 0x40);
16+
17+
// Set the variant to 10xx
18+
$data[8] = chr((ord($data[8]) & 0x3f) | 0x80);
19+
20+
// Convert to hexadecimal and format as UUID
21+
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
22+
}
23+
24+
public function createApiKey(string $client): string
25+
{
26+
$apiKey = self::generateUuidV4();
27+
$wasSuccessful = DB::table('api_keys')
28+
->insert([
29+
'apikey' => $apiKey,
30+
'client' => $client
31+
]);
32+
if ($wasSuccessful === false) {
33+
throw new RuntimeException('Could not create an API key.');
34+
}
35+
36+
return $apiKey;
37+
}
38+
39+
public function activateKey(string $apikey)
40+
{
41+
DB::table('api_keys')
42+
->where('apikey', $apikey)
43+
->update(['is_active' => true]);
44+
}
45+
46+
public function deactivateKey(string $apikey)
47+
{
48+
DB::table('api_keys')
49+
->where('apikey', $apikey)
50+
->update(['is_active' => false]);
51+
}
52+
}

.framework/boot.php

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
use Dotenv\Dotenv;
4+
use Illuminate\Container\Container;
5+
use Illuminate\Database\Capsule\Manager;
6+
use Illuminate\Database\Migrations\DatabaseMigrationRepository;
7+
use Illuminate\Database\Migrations\Migrator;
8+
use Illuminate\Events\Dispatcher;
9+
use Illuminate\Filesystem\Filesystem;
10+
use Illuminate\Support\Facades\Facade;
11+
use Minicli\App;
12+
use Minicli\Command\CommandCall;
13+
use PHPExperts\ConsolePainter\ConsolePainter;
14+
use PHPExperts\MiniApiBase\ApiKeyManager;
15+
16+
/** @var Manager $capsule */
17+
require __DIR__ . '/../database/config.php';
18+
19+
$container = new Container;
20+
21+
// Set up the event dispatcher
22+
$container->singleton('events', function() {
23+
return new Dispatcher($this);
24+
});
25+
26+
27+
$container->instance('db', $capsule->getDatabaseManager());
28+
//$container->instance('db.schema', $capsule->getDatabaseManager()->getSchemaGrammar());
29+
30+
// Bind 'db.schema' so Schema facade can resolve the schema builder
31+
$container->singleton('db.schema', function ($app) {
32+
return $app->make('db')->connection()->getSchemaBuilder();
33+
});
34+
35+
// Set the container instance to Facade
36+
Facade::setFacadeApplication($container);
37+
38+
39+
$app = new App([
40+
'app_path' => [
41+
__DIR__ . '/src/Command',
42+
],
43+
'theme' => '\Dracula',
44+
'debug' => false,
45+
]);
46+
47+
$p = new ConsolePainter();
48+
49+
// Load environment variables from the .env file
50+
$ensureDotEnv = function () {
51+
if (!file_exists(__DIR__ . '/../.env')) {
52+
if (file_exists('.env.dist')) {
53+
system('cp .env.dist .env');
54+
}
55+
56+
file_put_contents('.env', '');
57+
}
58+
};
59+
60+
$makeAppKey = function () {
61+
$appKey = env('APP_KEY');
62+
if (empty($appKey)) {
63+
$appKey = hash('sha256', bin2hex(random_bytes(8)));
64+
file_put_contents('.env', "\nAPP_KEY=$appKey\n", FILE_APPEND);
65+
putenv("APP_KEY=$appKey");
66+
$_ENV['APP_KEY'] = $appKey;
67+
}
68+
};
69+
70+
$ensureDotEnv();
71+
72+
$dotenv = Dotenv::createImmutable(__DIR__ . '/../');
73+
$dotenv->load();
74+
75+
$makeAppKey();
76+
77+
// Validate the environment variables
78+
$validateEnv = function () use ($p) {
79+
$missing = false;
80+
foreach (['APP_KEY'] as $e) {
81+
if (empty($_ENV[$e])) {
82+
echo $p->bold()->red("ERROR: ")->lightCyan($e)->text(" is not set in ")->lightPurple('.env')->text(" or environment variable\n");
83+
$missing = true;
84+
}
85+
}
86+
87+
if ($missing === true) {
88+
exit(1);
89+
}
90+
};
91+
92+
$validateEnv();
93+
94+
95+
96+
$app->registerCommand('migrate', function () {
97+
global $capsule;
98+
99+
$repository = new DatabaseMigrationRepository($capsule->getDatabaseManager(), 'migrations');
100+
if (!$repository->repositoryExists()) {
101+
$repository->createRepository();
102+
}
103+
104+
$migrator = new Migrator($repository, $capsule->getDatabaseManager(), new Filesystem());
105+
$migrationKeys = $migrator->run(__DIR__ . '/../database/migrations');
106+
107+
foreach ($migrationKeys as $filepath) {
108+
$migrationKey = basename($filepath, '.php');
109+
dump("Successfully ran the migration $migrationKey.");
110+
}
111+
112+
}, '<option>', 'Runs database migrations.');
113+
114+
$app->registerCommand('migrate:rollback', function () {
115+
global $capsule;
116+
117+
$repository = new DatabaseMigrationRepository($capsule->getDatabaseManager(), 'migrations');
118+
if (!$repository->repositoryExists()) {
119+
$repository->createRepository();
120+
}
121+
122+
$migrator = new Migrator($repository, $capsule->getDatabaseManager(), new Filesystem());
123+
$migrationKeys = $migrator->rollback(__DIR__ . '/../database/migrations');
124+
125+
foreach ($migrationKeys as $filepath) {
126+
$migrationKey = basename($filepath, '.php');
127+
dump("Successfully rolled back the migration $migrationKey.");
128+
}
129+
130+
}, '', 'Rolls back one migration at a time.');
131+
132+
133+
$app->registerCommand('api_key:issue', function (CommandCall $cli) use ($p) {
134+
$argv = $cli->getRawArgs();
135+
if (count($argv) < 3) {
136+
echo $p->bold()->red("ERROR: ")->text('Missing the "client" CLI argument.') . "\n";
137+
exit(1);
138+
}
139+
140+
$client = $argv[2];
141+
142+
$keyMaster = new ApiKeyManager();
143+
$apiKey = $keyMaster->createApiKey($client);
144+
145+
echo $p->bold(" Here is your API Key:") . "\n";
146+
echo "\n";
147+
echo $p->bold()->yellow(" $apiKey\n");
148+
echo "\n";
149+
echo $p->bold()->red(" Store it now, because it will never be reshown.") . "\n";
150+
151+
}, '[client]', 'Issues a new API key for a client.');

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vendor/

.php-cs-fixer.php

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
$header = <<<HEADER
4+
This file is part of MiniApiBase, a PHP Experts, Inc., Project.
5+
6+
Copyright © 2024-2025 PHP Experts, Inc.
7+
Author: Theodore R. Smith <[email protected]>
8+
GPG Fingerprint: 4BF8 2613 1C34 87AC D28F 2AD8 EB24 A91D D612 5690
9+
https://www.phpexperts.pro/
10+
https://github.com/PHPExpertsInc/MiniApiBase
11+
12+
This file is licensed under the MIT License.
13+
HEADER;
14+
15+
return (new PhpCsFixer\Config())
16+
->setRules([
17+
'@Symfony' => true,
18+
'elseif' => false,
19+
'yoda_style' => false,
20+
'list_syntax' => ['syntax' => 'short'],
21+
'concat_space' => ['spacing' => 'one'],
22+
'binary_operator_spaces' => [
23+
'operators' => [
24+
'=' => 'align',
25+
'=>' => 'align',
26+
],
27+
],
28+
'phpdoc_no_alias_tag' => false,
29+
'declare_strict_types' => true,
30+
'no_superfluous_elseif' => true,
31+
'blank_line_after_opening_tag' => false,
32+
'header_comment' => [
33+
'header' => $header,
34+
'location' => 'after_declare_strict',
35+
'comment_type' => 'PHPDoc',
36+
]
37+
])
38+
->setFinder(
39+
PhpCsFixer\Finder::create()
40+
->exclude('vendor')
41+
->in(__DIR__)
42+
);

0 commit comments

Comments
 (0)