├── .env
├── .gitignore
├── README.md
├── bin
└── console
├── bootstrap
└── bootstrap.php
├── composer.json
├── composer.lock
├── config
└── services.php
├── docker-compose.yaml
├── framework
├── .gitignore
├── composer.json
├── composer.lock
├── src
│ ├── Authentication
│ │ ├── AuthRepositoryInterface.php
│ │ ├── AuthUserInterface.php
│ │ ├── SessionAuthInterface.php
│ │ └── SessionAuthentication.php
│ ├── Console
│ │ ├── Application.php
│ │ ├── Command
│ │ │ ├── CommandInterface.php
│ │ │ └── MigrateDatabase.php
│ │ ├── ConsoleException.php
│ │ └── Kernel.php
│ ├── Container
│ │ ├── Container.php
│ │ └── ContainerException.php
│ ├── Controller
│ │ └── AbstractController.php
│ ├── Dbal
│ │ ├── ConnectionFactory.php
│ │ ├── DataMapper.php
│ │ ├── Entity.php
│ │ └── Event
│ │ │ └── PostPersist.php
│ ├── EventDispatcher
│ │ ├── Event.php
│ │ └── EventDispatcher.php
│ ├── Http
│ │ ├── Event
│ │ │ └── ResponseEvent.php
│ │ ├── HttpException.php
│ │ ├── HttpRequestMethodException.php
│ │ ├── Kernel.php
│ │ ├── Middleware
│ │ │ ├── Authenticate.php
│ │ │ ├── Dummy.php
│ │ │ ├── ExtractRouteInfo.php
│ │ │ ├── Guest.php
│ │ │ ├── MiddlewareInterface.php
│ │ │ ├── RequestHandler.php
│ │ │ ├── RequestHandlerInterface.php
│ │ │ ├── RouterDispatch.php
│ │ │ ├── StartSession.php
│ │ │ └── Success.php
│ │ ├── NotFoundException.php
│ │ ├── RedirectResponse.php
│ │ ├── Request.php
│ │ └── Response.php
│ ├── Routing
│ │ ├── Router.php
│ │ └── RouterInterface.php
│ ├── ServiceProvider
│ │ └── ServiceProviderInterface.php
│ ├── Session
│ │ ├── Session.php
│ │ └── SessionInterface.php
│ └── Template
│ │ └── TwigFactory.php
└── tests
│ ├── ContainerTest.php
│ ├── DependantClass.php
│ ├── DependencyClass.php
│ ├── SessionTest.php
│ └── SubDependencyClass.php
├── migrations
├── 20230304203000.php
├── 20230305153000.php
├── 20230306123000.php
└── 20230407133000.php
├── public
└── index.php
├── routes
└── web.php
├── src
├── Controller
│ ├── DashboardController.php
│ ├── HomeController.php
│ ├── LoginController.php
│ ├── PostsController.php
│ └── RegistrationController.php
├── Entity
│ ├── Post.php
│ └── User.php
├── EventListener
│ ├── ContentLengthListener.php
│ └── InternalErrorListener.php
├── Form
│ └── User
│ │ └── RegistrationForm.php
├── Provider
│ └── EventServiceProvider.php
├── Repository
│ ├── PostMapper.php
│ ├── PostRepository.php
│ ├── UserMapper.php
│ └── UserRepository.php
└── Widget.php
├── templates
├── base.html.twig
├── create-post.html.twig
├── dashboard.html.twig
├── home.html.twig
├── login.html.twig
├── post.html.twig
└── register.html.twig
└── var
└── .gitignore
/.env:
--------------------------------------------------------------------------------
1 | APP_ENV=dev
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | /vendor/
3 | notes.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | A comprehensive step-by-step video course created to help PHP developers grasp how frameworks function behind the scenes by actually building one.
8 |
9 |
10 | To get started, all you need to do is:
11 |
12 | Purchase the course here and get 20% discount using this coupon code: GCTREPO20
13 |
14 | All the code examples used in the lessons are stored in individual branches within this repository. Each lesson has its own branch, and within that branch, you can find all the relevant code samples used in that specific lesson.
15 |
16 | To set up your development environment, you will need to install Composer on your local machine.
17 |
18 | All these are for your information. The most exciting part is that every single step is covered in the course.
19 |
20 | Happy Coding.
21 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | get(\GaryClarke\Framework\Console\Kernel::class);
16 |
17 | // Call a handle method on the Kernel, return the console application status code
18 | $status = $kernel->handle();
19 |
20 | // exit with that status
21 | exit($status);
22 |
23 |
--------------------------------------------------------------------------------
/bootstrap/bootstrap.php:
--------------------------------------------------------------------------------
1 | get($providerClass);
9 | $provider->register();
10 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "autoload": {
3 | "psr-4": {
4 | "App\\": "src/"
5 | }
6 | },
7 | "minimum-stability": "dev",
8 | "repositories": [
9 | {
10 | "type": "path",
11 | "url": "framework"
12 | }
13 | ],
14 | "require-dev": {
15 | "symfony/var-dumper": "6.3.x-dev"
16 | },
17 | "require": {
18 | "garyclarketech/php-framework-pro": "dev-main"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "45db679556ef570bcba0da51c149f1b1",
8 | "packages": [
9 | {
10 | "name": "doctrine/cache",
11 | "version": "2.2.x-dev",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/doctrine/cache.git",
15 | "reference": "5d55089cbe7339f72405560a254153e21c24e9c5"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/doctrine/cache/zipball/5d55089cbe7339f72405560a254153e21c24e9c5",
20 | "reference": "5d55089cbe7339f72405560a254153e21c24e9c5",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": "~7.1 || ^8.0"
25 | },
26 | "conflict": {
27 | "doctrine/common": ">2.2,<2.4"
28 | },
29 | "require-dev": {
30 | "cache/integration-tests": "dev-master",
31 | "doctrine/coding-standard": "^9",
32 | "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
33 | "psr/cache": "^1.0 || ^2.0 || ^3.0",
34 | "symfony/cache": "^4.4 || ^5.4 || ^6",
35 | "symfony/var-exporter": "^4.4 || ^5.4 || ^6"
36 | },
37 | "default-branch": true,
38 | "type": "library",
39 | "autoload": {
40 | "psr-4": {
41 | "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
42 | }
43 | },
44 | "notification-url": "https://packagist.org/downloads/",
45 | "license": [
46 | "MIT"
47 | ],
48 | "authors": [
49 | {
50 | "name": "Guilherme Blanco",
51 | "email": "guilhermeblanco@gmail.com"
52 | },
53 | {
54 | "name": "Roman Borschel",
55 | "email": "roman@code-factory.org"
56 | },
57 | {
58 | "name": "Benjamin Eberlei",
59 | "email": "kontakt@beberlei.de"
60 | },
61 | {
62 | "name": "Jonathan Wage",
63 | "email": "jonwage@gmail.com"
64 | },
65 | {
66 | "name": "Johannes Schmitt",
67 | "email": "schmittjoh@gmail.com"
68 | }
69 | ],
70 | "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
71 | "homepage": "https://www.doctrine-project.org/projects/cache.html",
72 | "keywords": [
73 | "abstraction",
74 | "apcu",
75 | "cache",
76 | "caching",
77 | "couchdb",
78 | "memcached",
79 | "php",
80 | "redis",
81 | "xcache"
82 | ],
83 | "support": {
84 | "issues": "https://github.com/doctrine/cache/issues",
85 | "source": "https://github.com/doctrine/cache/tree/2.2.x"
86 | },
87 | "funding": [
88 | {
89 | "url": "https://www.doctrine-project.org/sponsorship.html",
90 | "type": "custom"
91 | },
92 | {
93 | "url": "https://www.patreon.com/phpdoctrine",
94 | "type": "patreon"
95 | },
96 | {
97 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
98 | "type": "tidelift"
99 | }
100 | ],
101 | "time": "2023-01-18T18:44:28+00:00"
102 | },
103 | {
104 | "name": "doctrine/dbal",
105 | "version": "3.7.x-dev",
106 | "source": {
107 | "type": "git",
108 | "url": "https://github.com/doctrine/dbal.git",
109 | "reference": "3db3f61496c07e98f29e4a73bef72b3eae1380d6"
110 | },
111 | "dist": {
112 | "type": "zip",
113 | "url": "https://api.github.com/repos/doctrine/dbal/zipball/3db3f61496c07e98f29e4a73bef72b3eae1380d6",
114 | "reference": "3db3f61496c07e98f29e4a73bef72b3eae1380d6",
115 | "shasum": ""
116 | },
117 | "require": {
118 | "composer-runtime-api": "^2",
119 | "doctrine/cache": "^1.11|^2.0",
120 | "doctrine/deprecations": "^0.5.3|^1",
121 | "doctrine/event-manager": "^1|^2",
122 | "php": "^7.4 || ^8.0",
123 | "psr/cache": "^1|^2|^3",
124 | "psr/log": "^1|^2|^3"
125 | },
126 | "require-dev": {
127 | "doctrine/coding-standard": "11.1.0",
128 | "fig/log-test": "^1",
129 | "jetbrains/phpstorm-stubs": "2022.3",
130 | "phpstan/phpstan": "1.10.9",
131 | "phpstan/phpstan-strict-rules": "^1.5",
132 | "phpunit/phpunit": "9.6.6",
133 | "psalm/plugin-phpunit": "0.18.4",
134 | "squizlabs/php_codesniffer": "3.7.2",
135 | "symfony/cache": "^5.4|^6.0",
136 | "symfony/console": "^4.4|^5.4|^6.0",
137 | "vimeo/psalm": "4.30.0"
138 | },
139 | "suggest": {
140 | "symfony/console": "For helpful console commands such as SQL execution and import of files."
141 | },
142 | "bin": [
143 | "bin/doctrine-dbal"
144 | ],
145 | "type": "library",
146 | "autoload": {
147 | "psr-4": {
148 | "Doctrine\\DBAL\\": "src"
149 | }
150 | },
151 | "notification-url": "https://packagist.org/downloads/",
152 | "license": [
153 | "MIT"
154 | ],
155 | "authors": [
156 | {
157 | "name": "Guilherme Blanco",
158 | "email": "guilhermeblanco@gmail.com"
159 | },
160 | {
161 | "name": "Roman Borschel",
162 | "email": "roman@code-factory.org"
163 | },
164 | {
165 | "name": "Benjamin Eberlei",
166 | "email": "kontakt@beberlei.de"
167 | },
168 | {
169 | "name": "Jonathan Wage",
170 | "email": "jonwage@gmail.com"
171 | }
172 | ],
173 | "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
174 | "homepage": "https://www.doctrine-project.org/projects/dbal.html",
175 | "keywords": [
176 | "abstraction",
177 | "database",
178 | "db2",
179 | "dbal",
180 | "mariadb",
181 | "mssql",
182 | "mysql",
183 | "oci8",
184 | "oracle",
185 | "pdo",
186 | "pgsql",
187 | "postgresql",
188 | "queryobject",
189 | "sasql",
190 | "sql",
191 | "sqlite",
192 | "sqlserver",
193 | "sqlsrv"
194 | ],
195 | "support": {
196 | "issues": "https://github.com/doctrine/dbal/issues",
197 | "source": "https://github.com/doctrine/dbal/tree/3.7.x"
198 | },
199 | "funding": [
200 | {
201 | "url": "https://www.doctrine-project.org/sponsorship.html",
202 | "type": "custom"
203 | },
204 | {
205 | "url": "https://www.patreon.com/phpdoctrine",
206 | "type": "patreon"
207 | },
208 | {
209 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
210 | "type": "tidelift"
211 | }
212 | ],
213 | "time": "2023-04-13T22:06:37+00:00"
214 | },
215 | {
216 | "name": "doctrine/deprecations",
217 | "version": "v1.0.0",
218 | "source": {
219 | "type": "git",
220 | "url": "https://github.com/doctrine/deprecations.git",
221 | "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
222 | },
223 | "dist": {
224 | "type": "zip",
225 | "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
226 | "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
227 | "shasum": ""
228 | },
229 | "require": {
230 | "php": "^7.1|^8.0"
231 | },
232 | "require-dev": {
233 | "doctrine/coding-standard": "^9",
234 | "phpunit/phpunit": "^7.5|^8.5|^9.5",
235 | "psr/log": "^1|^2|^3"
236 | },
237 | "suggest": {
238 | "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
239 | },
240 | "type": "library",
241 | "autoload": {
242 | "psr-4": {
243 | "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
244 | }
245 | },
246 | "notification-url": "https://packagist.org/downloads/",
247 | "license": [
248 | "MIT"
249 | ],
250 | "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
251 | "homepage": "https://www.doctrine-project.org/",
252 | "support": {
253 | "issues": "https://github.com/doctrine/deprecations/issues",
254 | "source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
255 | },
256 | "time": "2022-05-02T15:47:09+00:00"
257 | },
258 | {
259 | "name": "doctrine/event-manager",
260 | "version": "2.0.x-dev",
261 | "source": {
262 | "type": "git",
263 | "url": "https://github.com/doctrine/event-manager.git",
264 | "reference": "fe71bc032e5de972b8d18939abfa87d23f43ebd3"
265 | },
266 | "dist": {
267 | "type": "zip",
268 | "url": "https://api.github.com/repos/doctrine/event-manager/zipball/fe71bc032e5de972b8d18939abfa87d23f43ebd3",
269 | "reference": "fe71bc032e5de972b8d18939abfa87d23f43ebd3",
270 | "shasum": ""
271 | },
272 | "require": {
273 | "php": "^8.1"
274 | },
275 | "conflict": {
276 | "doctrine/common": "<2.9"
277 | },
278 | "require-dev": {
279 | "doctrine/coding-standard": "^10",
280 | "phpstan/phpstan": "^1.8.8",
281 | "phpunit/phpunit": "^9.5",
282 | "vimeo/psalm": "^4.28"
283 | },
284 | "default-branch": true,
285 | "type": "library",
286 | "autoload": {
287 | "psr-4": {
288 | "Doctrine\\Common\\": "src"
289 | }
290 | },
291 | "notification-url": "https://packagist.org/downloads/",
292 | "license": [
293 | "MIT"
294 | ],
295 | "authors": [
296 | {
297 | "name": "Guilherme Blanco",
298 | "email": "guilhermeblanco@gmail.com"
299 | },
300 | {
301 | "name": "Roman Borschel",
302 | "email": "roman@code-factory.org"
303 | },
304 | {
305 | "name": "Benjamin Eberlei",
306 | "email": "kontakt@beberlei.de"
307 | },
308 | {
309 | "name": "Jonathan Wage",
310 | "email": "jonwage@gmail.com"
311 | },
312 | {
313 | "name": "Johannes Schmitt",
314 | "email": "schmittjoh@gmail.com"
315 | },
316 | {
317 | "name": "Marco Pivetta",
318 | "email": "ocramius@gmail.com"
319 | }
320 | ],
321 | "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
322 | "homepage": "https://www.doctrine-project.org/projects/event-manager.html",
323 | "keywords": [
324 | "event",
325 | "event dispatcher",
326 | "event manager",
327 | "event system",
328 | "events"
329 | ],
330 | "support": {
331 | "issues": "https://github.com/doctrine/event-manager/issues",
332 | "source": "https://github.com/doctrine/event-manager/tree/2.0.x"
333 | },
334 | "funding": [
335 | {
336 | "url": "https://www.doctrine-project.org/sponsorship.html",
337 | "type": "custom"
338 | },
339 | {
340 | "url": "https://www.patreon.com/phpdoctrine",
341 | "type": "patreon"
342 | },
343 | {
344 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
345 | "type": "tidelift"
346 | }
347 | ],
348 | "time": "2022-10-13T11:16:49+00:00"
349 | },
350 | {
351 | "name": "garyclarketech/php-framework-pro",
352 | "version": "dev-main",
353 | "dist": {
354 | "type": "path",
355 | "url": "framework",
356 | "reference": "71f30e6b4ace462188a572bca5c4f5248c819aa6"
357 | },
358 | "require": {
359 | "doctrine/dbal": "^3.6",
360 | "league/container": "^4.0.0",
361 | "nikic/fast-route": "dev-master",
362 | "psr/container": "2.0.x-dev",
363 | "psr/event-dispatcher": "^1.0",
364 | "symfony/dotenv": "^6.0",
365 | "twig/twig": "^3.0"
366 | },
367 | "require-dev": {
368 | "phpunit/phpunit": "10.1.x-dev",
369 | "symfony/var-dumper": "6.3.x-dev"
370 | },
371 | "type": "library",
372 | "autoload": {
373 | "psr-4": {
374 | "GaryClarke\\Framework\\": "src/"
375 | }
376 | },
377 | "autoload-dev": {
378 | "psr-4": {
379 | "GaryClarke\\Framework\\Tests\\": "tests"
380 | }
381 | },
382 | "license": [
383 | "MIT"
384 | ],
385 | "authors": [
386 | {
387 | "name": "Gary Clarke",
388 | "email": "info@garyclarke.tech"
389 | }
390 | ],
391 | "description": "A PHP framework tutorial project",
392 | "transport-options": {
393 | "relative": true
394 | }
395 | },
396 | {
397 | "name": "league/container",
398 | "version": "4.x-dev",
399 | "source": {
400 | "type": "git",
401 | "url": "https://github.com/thephpleague/container.git",
402 | "reference": "388e992884ab75632d93dbaf4d29ec024d64b964"
403 | },
404 | "dist": {
405 | "type": "zip",
406 | "url": "https://api.github.com/repos/thephpleague/container/zipball/388e992884ab75632d93dbaf4d29ec024d64b964",
407 | "reference": "388e992884ab75632d93dbaf4d29ec024d64b964",
408 | "shasum": ""
409 | },
410 | "require": {
411 | "php": "^7.2 || ^8.0",
412 | "psr/container": "^1.1 || ^2.0"
413 | },
414 | "provide": {
415 | "psr/container-implementation": "^1.0"
416 | },
417 | "replace": {
418 | "orno/di": "~2.0"
419 | },
420 | "require-dev": {
421 | "nette/php-generator": "^3.4",
422 | "nikic/php-parser": "^4.10",
423 | "phpstan/phpstan": "^0.12.47",
424 | "phpunit/phpunit": "^8.5.17",
425 | "roave/security-advisories": "dev-latest",
426 | "scrutinizer/ocular": "^1.8",
427 | "squizlabs/php_codesniffer": "^3.6"
428 | },
429 | "default-branch": true,
430 | "type": "library",
431 | "extra": {
432 | "branch-alias": {
433 | "dev-master": "4.x-dev",
434 | "dev-4.x": "4.x-dev",
435 | "dev-3.x": "3.x-dev",
436 | "dev-2.x": "2.x-dev",
437 | "dev-1.x": "1.x-dev"
438 | }
439 | },
440 | "autoload": {
441 | "psr-4": {
442 | "League\\Container\\": "src"
443 | }
444 | },
445 | "notification-url": "https://packagist.org/downloads/",
446 | "license": [
447 | "MIT"
448 | ],
449 | "authors": [
450 | {
451 | "name": "Phil Bennett",
452 | "email": "mail@philbennett.co.uk",
453 | "role": "Developer"
454 | }
455 | ],
456 | "description": "A fast and intuitive dependency injection container.",
457 | "homepage": "https://github.com/thephpleague/container",
458 | "keywords": [
459 | "container",
460 | "dependency",
461 | "di",
462 | "injection",
463 | "league",
464 | "provider",
465 | "service"
466 | ],
467 | "support": {
468 | "issues": "https://github.com/thephpleague/container/issues",
469 | "source": "https://github.com/thephpleague/container/tree/4.x"
470 | },
471 | "funding": [
472 | {
473 | "url": "https://github.com/philipobenito",
474 | "type": "github"
475 | }
476 | ],
477 | "time": "2022-02-02T09:18:15+00:00"
478 | },
479 | {
480 | "name": "nikic/fast-route",
481 | "version": "dev-master",
482 | "source": {
483 | "type": "git",
484 | "url": "https://github.com/nikic/FastRoute.git",
485 | "reference": "34128a32009e1b41c4615bcd7d4c39968931e9ea"
486 | },
487 | "dist": {
488 | "type": "zip",
489 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/34128a32009e1b41c4615bcd7d4c39968931e9ea",
490 | "reference": "34128a32009e1b41c4615bcd7d4c39968931e9ea",
491 | "shasum": ""
492 | },
493 | "require": {
494 | "php": ">=7.4.0"
495 | },
496 | "require-dev": {
497 | "doctrine/coding-standard": "^9.0",
498 | "phpbench/phpbench": "^1.0",
499 | "phpstan/extension-installer": "^1.0",
500 | "phpstan/phpstan": "^0.12",
501 | "phpstan/phpstan-deprecation-rules": "^0.12",
502 | "phpstan/phpstan-phpunit": "^0.12",
503 | "phpstan/phpstan-strict-rules": "^0.12",
504 | "phpunit/phpunit": "^9.5"
505 | },
506 | "suggest": {
507 | "ext-apcu": "To be able to use APCu cache driver"
508 | },
509 | "default-branch": true,
510 | "type": "library",
511 | "extra": {
512 | "branch-alias": {
513 | "dev-master": "2.0-dev"
514 | }
515 | },
516 | "autoload": {
517 | "files": [
518 | "src/functions.php"
519 | ],
520 | "psr-4": {
521 | "FastRoute\\": "src/"
522 | }
523 | },
524 | "notification-url": "https://packagist.org/downloads/",
525 | "license": [
526 | "BSD-3-Clause"
527 | ],
528 | "authors": [
529 | {
530 | "name": "Nikita Popov",
531 | "email": "nikic@php.net"
532 | }
533 | ],
534 | "description": "Fast request router for PHP",
535 | "keywords": [
536 | "router",
537 | "routing"
538 | ],
539 | "support": {
540 | "issues": "https://github.com/nikic/FastRoute/issues",
541 | "source": "https://github.com/nikic/FastRoute/tree/master"
542 | },
543 | "time": "2023-03-16T08:06:25+00:00"
544 | },
545 | {
546 | "name": "psr/cache",
547 | "version": "dev-master",
548 | "source": {
549 | "type": "git",
550 | "url": "https://github.com/php-fig/cache.git",
551 | "reference": "0a7c67d0d1c8167b342eb74339d6f961663826ce"
552 | },
553 | "dist": {
554 | "type": "zip",
555 | "url": "https://api.github.com/repos/php-fig/cache/zipball/0a7c67d0d1c8167b342eb74339d6f961663826ce",
556 | "reference": "0a7c67d0d1c8167b342eb74339d6f961663826ce",
557 | "shasum": ""
558 | },
559 | "require": {
560 | "php": ">=8.0.0"
561 | },
562 | "suggest": {
563 | "fig/cache-util": "Provides some useful PSR-6 utilities"
564 | },
565 | "default-branch": true,
566 | "type": "library",
567 | "extra": {
568 | "branch-alias": {
569 | "dev-master": "3.0.x-dev"
570 | }
571 | },
572 | "autoload": {
573 | "psr-4": {
574 | "Psr\\Cache\\": "src/"
575 | }
576 | },
577 | "notification-url": "https://packagist.org/downloads/",
578 | "license": [
579 | "MIT"
580 | ],
581 | "authors": [
582 | {
583 | "name": "PHP-FIG",
584 | "homepage": "https://www.php-fig.org/"
585 | }
586 | ],
587 | "description": "Common interface for caching libraries",
588 | "keywords": [
589 | "cache",
590 | "psr",
591 | "psr-6"
592 | ],
593 | "support": {
594 | "source": "https://github.com/php-fig/cache/tree/master"
595 | },
596 | "time": "2021-02-24T03:25:37+00:00"
597 | },
598 | {
599 | "name": "psr/container",
600 | "version": "dev-master",
601 | "source": {
602 | "type": "git",
603 | "url": "https://github.com/php-fig/container.git",
604 | "reference": "90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5"
605 | },
606 | "dist": {
607 | "type": "zip",
608 | "url": "https://api.github.com/repos/php-fig/container/zipball/90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5",
609 | "reference": "90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5",
610 | "shasum": ""
611 | },
612 | "require": {
613 | "php": ">=7.4.0"
614 | },
615 | "default-branch": true,
616 | "type": "library",
617 | "extra": {
618 | "branch-alias": {
619 | "dev-master": "2.0.x-dev"
620 | }
621 | },
622 | "autoload": {
623 | "psr-4": {
624 | "Psr\\Container\\": "src/"
625 | }
626 | },
627 | "notification-url": "https://packagist.org/downloads/",
628 | "license": [
629 | "MIT"
630 | ],
631 | "authors": [
632 | {
633 | "name": "PHP-FIG",
634 | "homepage": "https://www.php-fig.org/"
635 | }
636 | ],
637 | "description": "Common Container Interface (PHP FIG PSR-11)",
638 | "homepage": "https://github.com/php-fig/container",
639 | "keywords": [
640 | "PSR-11",
641 | "container",
642 | "container-interface",
643 | "container-interop",
644 | "psr"
645 | ],
646 | "support": {
647 | "issues": "https://github.com/php-fig/container/issues",
648 | "source": "https://github.com/php-fig/container/tree/master"
649 | },
650 | "time": "2022-07-19T17:36:59+00:00"
651 | },
652 | {
653 | "name": "psr/event-dispatcher",
654 | "version": "dev-master",
655 | "source": {
656 | "type": "git",
657 | "url": "https://github.com/php-fig/event-dispatcher.git",
658 | "reference": "e275e2d67d53964a3f13e056886ecd769edee021"
659 | },
660 | "dist": {
661 | "type": "zip",
662 | "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/e275e2d67d53964a3f13e056886ecd769edee021",
663 | "reference": "e275e2d67d53964a3f13e056886ecd769edee021",
664 | "shasum": ""
665 | },
666 | "require": {
667 | "php": ">=7.2.0"
668 | },
669 | "suggest": {
670 | "fig/event-dispatcher-util": "Provides some useful PSR-14 utilities"
671 | },
672 | "default-branch": true,
673 | "type": "library",
674 | "extra": {
675 | "branch-alias": {
676 | "dev-master": "1.0.x-dev"
677 | }
678 | },
679 | "autoload": {
680 | "psr-4": {
681 | "Psr\\EventDispatcher\\": "src/"
682 | }
683 | },
684 | "notification-url": "https://packagist.org/downloads/",
685 | "license": [
686 | "MIT"
687 | ],
688 | "authors": [
689 | {
690 | "name": "PHP-FIG",
691 | "homepage": "https://www.php-fig.org/"
692 | }
693 | ],
694 | "description": "Standard interfaces for event handling.",
695 | "keywords": [
696 | "events",
697 | "psr",
698 | "psr-14"
699 | ],
700 | "support": {
701 | "source": "https://github.com/php-fig/event-dispatcher/tree/master"
702 | },
703 | "time": "2022-06-29T17:22:39+00:00"
704 | },
705 | {
706 | "name": "psr/log",
707 | "version": "dev-master",
708 | "source": {
709 | "type": "git",
710 | "url": "https://github.com/php-fig/log.git",
711 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
712 | },
713 | "dist": {
714 | "type": "zip",
715 | "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
716 | "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
717 | "shasum": ""
718 | },
719 | "require": {
720 | "php": ">=8.0.0"
721 | },
722 | "default-branch": true,
723 | "type": "library",
724 | "extra": {
725 | "branch-alias": {
726 | "dev-master": "3.x-dev"
727 | }
728 | },
729 | "autoload": {
730 | "psr-4": {
731 | "Psr\\Log\\": "src"
732 | }
733 | },
734 | "notification-url": "https://packagist.org/downloads/",
735 | "license": [
736 | "MIT"
737 | ],
738 | "authors": [
739 | {
740 | "name": "PHP-FIG",
741 | "homepage": "https://www.php-fig.org/"
742 | }
743 | ],
744 | "description": "Common interface for logging libraries",
745 | "homepage": "https://github.com/php-fig/log",
746 | "keywords": [
747 | "log",
748 | "psr",
749 | "psr-3"
750 | ],
751 | "support": {
752 | "source": "https://github.com/php-fig/log/tree/3.0.0"
753 | },
754 | "time": "2021-07-14T16:46:02+00:00"
755 | },
756 | {
757 | "name": "symfony/dotenv",
758 | "version": "6.3.x-dev",
759 | "source": {
760 | "type": "git",
761 | "url": "https://github.com/symfony/dotenv.git",
762 | "reference": "070cdb03ac12b8f3b2db7e6b89145ccebfd54543"
763 | },
764 | "dist": {
765 | "type": "zip",
766 | "url": "https://api.github.com/repos/symfony/dotenv/zipball/070cdb03ac12b8f3b2db7e6b89145ccebfd54543",
767 | "reference": "070cdb03ac12b8f3b2db7e6b89145ccebfd54543",
768 | "shasum": ""
769 | },
770 | "require": {
771 | "php": ">=8.1"
772 | },
773 | "conflict": {
774 | "symfony/console": "<5.4",
775 | "symfony/process": "<5.4"
776 | },
777 | "require-dev": {
778 | "symfony/console": "^5.4|^6.0",
779 | "symfony/process": "^5.4|^6.0"
780 | },
781 | "type": "library",
782 | "autoload": {
783 | "psr-4": {
784 | "Symfony\\Component\\Dotenv\\": ""
785 | },
786 | "exclude-from-classmap": [
787 | "/Tests/"
788 | ]
789 | },
790 | "notification-url": "https://packagist.org/downloads/",
791 | "license": [
792 | "MIT"
793 | ],
794 | "authors": [
795 | {
796 | "name": "Fabien Potencier",
797 | "email": "fabien@symfony.com"
798 | },
799 | {
800 | "name": "Symfony Community",
801 | "homepage": "https://symfony.com/contributors"
802 | }
803 | ],
804 | "description": "Registers environment variables from a .env file",
805 | "homepage": "https://symfony.com",
806 | "keywords": [
807 | "dotenv",
808 | "env",
809 | "environment"
810 | ],
811 | "support": {
812 | "source": "https://github.com/symfony/dotenv/tree/6.3"
813 | },
814 | "funding": [
815 | {
816 | "url": "https://symfony.com/sponsor",
817 | "type": "custom"
818 | },
819 | {
820 | "url": "https://github.com/fabpot",
821 | "type": "github"
822 | },
823 | {
824 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
825 | "type": "tidelift"
826 | }
827 | ],
828 | "time": "2023-03-10T10:08:00+00:00"
829 | },
830 | {
831 | "name": "symfony/polyfill-ctype",
832 | "version": "dev-main",
833 | "source": {
834 | "type": "git",
835 | "url": "https://github.com/symfony/polyfill-ctype.git",
836 | "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
837 | },
838 | "dist": {
839 | "type": "zip",
840 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
841 | "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
842 | "shasum": ""
843 | },
844 | "require": {
845 | "php": ">=7.1"
846 | },
847 | "provide": {
848 | "ext-ctype": "*"
849 | },
850 | "suggest": {
851 | "ext-ctype": "For best performance"
852 | },
853 | "default-branch": true,
854 | "type": "library",
855 | "extra": {
856 | "branch-alias": {
857 | "dev-main": "1.28-dev"
858 | },
859 | "thanks": {
860 | "name": "symfony/polyfill",
861 | "url": "https://github.com/symfony/polyfill"
862 | }
863 | },
864 | "autoload": {
865 | "files": [
866 | "bootstrap.php"
867 | ],
868 | "psr-4": {
869 | "Symfony\\Polyfill\\Ctype\\": ""
870 | }
871 | },
872 | "notification-url": "https://packagist.org/downloads/",
873 | "license": [
874 | "MIT"
875 | ],
876 | "authors": [
877 | {
878 | "name": "Gert de Pagter",
879 | "email": "BackEndTea@gmail.com"
880 | },
881 | {
882 | "name": "Symfony Community",
883 | "homepage": "https://symfony.com/contributors"
884 | }
885 | ],
886 | "description": "Symfony polyfill for ctype functions",
887 | "homepage": "https://symfony.com",
888 | "keywords": [
889 | "compatibility",
890 | "ctype",
891 | "polyfill",
892 | "portable"
893 | ],
894 | "support": {
895 | "source": "https://github.com/symfony/polyfill-ctype/tree/main"
896 | },
897 | "funding": [
898 | {
899 | "url": "https://symfony.com/sponsor",
900 | "type": "custom"
901 | },
902 | {
903 | "url": "https://github.com/fabpot",
904 | "type": "github"
905 | },
906 | {
907 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
908 | "type": "tidelift"
909 | }
910 | ],
911 | "time": "2023-01-26T09:26:14+00:00"
912 | },
913 | {
914 | "name": "symfony/polyfill-mbstring",
915 | "version": "dev-main",
916 | "source": {
917 | "type": "git",
918 | "url": "https://github.com/symfony/polyfill-mbstring.git",
919 | "reference": "f9c7affe77a00ae32ca127ca6833d034e6d33f25"
920 | },
921 | "dist": {
922 | "type": "zip",
923 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f9c7affe77a00ae32ca127ca6833d034e6d33f25",
924 | "reference": "f9c7affe77a00ae32ca127ca6833d034e6d33f25",
925 | "shasum": ""
926 | },
927 | "require": {
928 | "php": ">=7.1"
929 | },
930 | "provide": {
931 | "ext-mbstring": "*"
932 | },
933 | "suggest": {
934 | "ext-mbstring": "For best performance"
935 | },
936 | "default-branch": true,
937 | "type": "library",
938 | "extra": {
939 | "branch-alias": {
940 | "dev-main": "1.28-dev"
941 | },
942 | "thanks": {
943 | "name": "symfony/polyfill",
944 | "url": "https://github.com/symfony/polyfill"
945 | }
946 | },
947 | "autoload": {
948 | "files": [
949 | "bootstrap.php"
950 | ],
951 | "psr-4": {
952 | "Symfony\\Polyfill\\Mbstring\\": ""
953 | }
954 | },
955 | "notification-url": "https://packagist.org/downloads/",
956 | "license": [
957 | "MIT"
958 | ],
959 | "authors": [
960 | {
961 | "name": "Nicolas Grekas",
962 | "email": "p@tchwork.com"
963 | },
964 | {
965 | "name": "Symfony Community",
966 | "homepage": "https://symfony.com/contributors"
967 | }
968 | ],
969 | "description": "Symfony polyfill for the Mbstring extension",
970 | "homepage": "https://symfony.com",
971 | "keywords": [
972 | "compatibility",
973 | "mbstring",
974 | "polyfill",
975 | "portable",
976 | "shim"
977 | ],
978 | "support": {
979 | "source": "https://github.com/symfony/polyfill-mbstring/tree/main"
980 | },
981 | "funding": [
982 | {
983 | "url": "https://symfony.com/sponsor",
984 | "type": "custom"
985 | },
986 | {
987 | "url": "https://github.com/fabpot",
988 | "type": "github"
989 | },
990 | {
991 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
992 | "type": "tidelift"
993 | }
994 | ],
995 | "time": "2023-01-30T17:25:47+00:00"
996 | },
997 | {
998 | "name": "twig/twig",
999 | "version": "3.x-dev",
1000 | "source": {
1001 | "type": "git",
1002 | "url": "https://github.com/twigphp/Twig.git",
1003 | "reference": "1812ca1ade2006c9238e7fa0562d438f401246a6"
1004 | },
1005 | "dist": {
1006 | "type": "zip",
1007 | "url": "https://api.github.com/repos/twigphp/Twig/zipball/1812ca1ade2006c9238e7fa0562d438f401246a6",
1008 | "reference": "1812ca1ade2006c9238e7fa0562d438f401246a6",
1009 | "shasum": ""
1010 | },
1011 | "require": {
1012 | "php": ">=7.2.5",
1013 | "symfony/polyfill-ctype": "^1.8",
1014 | "symfony/polyfill-mbstring": "^1.3"
1015 | },
1016 | "require-dev": {
1017 | "psr/container": "^1.0|^2.0",
1018 | "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
1019 | },
1020 | "default-branch": true,
1021 | "type": "library",
1022 | "autoload": {
1023 | "psr-4": {
1024 | "Twig\\": "src/"
1025 | }
1026 | },
1027 | "notification-url": "https://packagist.org/downloads/",
1028 | "license": [
1029 | "BSD-3-Clause"
1030 | ],
1031 | "authors": [
1032 | {
1033 | "name": "Fabien Potencier",
1034 | "email": "fabien@symfony.com",
1035 | "homepage": "http://fabien.potencier.org",
1036 | "role": "Lead Developer"
1037 | },
1038 | {
1039 | "name": "Twig Team",
1040 | "role": "Contributors"
1041 | },
1042 | {
1043 | "name": "Armin Ronacher",
1044 | "email": "armin.ronacher@active-4.com",
1045 | "role": "Project Founder"
1046 | }
1047 | ],
1048 | "description": "Twig, the flexible, fast, and secure template language for PHP",
1049 | "homepage": "https://twig.symfony.com",
1050 | "keywords": [
1051 | "templating"
1052 | ],
1053 | "support": {
1054 | "issues": "https://github.com/twigphp/Twig/issues",
1055 | "source": "https://github.com/twigphp/Twig/tree/3.x"
1056 | },
1057 | "funding": [
1058 | {
1059 | "url": "https://github.com/fabpot",
1060 | "type": "github"
1061 | },
1062 | {
1063 | "url": "https://tidelift.com/funding/github/packagist/twig/twig",
1064 | "type": "tidelift"
1065 | }
1066 | ],
1067 | "time": "2023-04-14T11:18:53+00:00"
1068 | }
1069 | ],
1070 | "packages-dev": [
1071 | {
1072 | "name": "symfony/var-dumper",
1073 | "version": "6.3.x-dev",
1074 | "source": {
1075 | "type": "git",
1076 | "url": "https://github.com/symfony/var-dumper.git",
1077 | "reference": "3f026afbd79aa419a889126333c25767ef354e09"
1078 | },
1079 | "dist": {
1080 | "type": "zip",
1081 | "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3f026afbd79aa419a889126333c25767ef354e09",
1082 | "reference": "3f026afbd79aa419a889126333c25767ef354e09",
1083 | "shasum": ""
1084 | },
1085 | "require": {
1086 | "php": ">=8.1",
1087 | "symfony/polyfill-mbstring": "~1.0"
1088 | },
1089 | "conflict": {
1090 | "phpunit/phpunit": "<5.4.3",
1091 | "symfony/console": "<5.4"
1092 | },
1093 | "require-dev": {
1094 | "ext-iconv": "*",
1095 | "symfony/console": "^5.4|^6.0",
1096 | "symfony/process": "^5.4|^6.0",
1097 | "symfony/uid": "^5.4|^6.0",
1098 | "twig/twig": "^2.13|^3.0.4"
1099 | },
1100 | "suggest": {
1101 | "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
1102 | "ext-intl": "To show region name in time zone dump",
1103 | "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
1104 | },
1105 | "bin": [
1106 | "Resources/bin/var-dump-server"
1107 | ],
1108 | "type": "library",
1109 | "autoload": {
1110 | "files": [
1111 | "Resources/functions/dump.php"
1112 | ],
1113 | "psr-4": {
1114 | "Symfony\\Component\\VarDumper\\": ""
1115 | },
1116 | "exclude-from-classmap": [
1117 | "/Tests/"
1118 | ]
1119 | },
1120 | "notification-url": "https://packagist.org/downloads/",
1121 | "license": [
1122 | "MIT"
1123 | ],
1124 | "authors": [
1125 | {
1126 | "name": "Nicolas Grekas",
1127 | "email": "p@tchwork.com"
1128 | },
1129 | {
1130 | "name": "Symfony Community",
1131 | "homepage": "https://symfony.com/contributors"
1132 | }
1133 | ],
1134 | "description": "Provides mechanisms for walking through any arbitrary PHP variable",
1135 | "homepage": "https://symfony.com",
1136 | "keywords": [
1137 | "debug",
1138 | "dump"
1139 | ],
1140 | "support": {
1141 | "source": "https://github.com/symfony/var-dumper/tree/6.3"
1142 | },
1143 | "funding": [
1144 | {
1145 | "url": "https://symfony.com/sponsor",
1146 | "type": "custom"
1147 | },
1148 | {
1149 | "url": "https://github.com/fabpot",
1150 | "type": "github"
1151 | },
1152 | {
1153 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1154 | "type": "tidelift"
1155 | }
1156 | ],
1157 | "time": "2023-04-14T12:13:08+00:00"
1158 | }
1159 | ],
1160 | "aliases": [],
1161 | "minimum-stability": "dev",
1162 | "stability-flags": {
1163 | "garyclarketech/php-framework-pro": 20,
1164 | "symfony/var-dumper": 20
1165 | },
1166 | "prefer-stable": false,
1167 | "prefer-lowest": false,
1168 | "platform": [],
1169 | "platform-dev": [],
1170 | "plugin-api-version": "2.3.0"
1171 | }
1172 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | load(dirname(__DIR__) . '/.env');
5 |
6 | $container = new \League\Container\Container();
7 |
8 | $container->delegate(new \League\Container\ReflectionContainer(true));
9 |
10 | # parameters for application config
11 | $basePath = dirname(__DIR__);
12 | $container->add('basePath', new \League\Container\Argument\Literal\StringArgument($basePath));
13 | $routes = include $basePath . '/routes/web.php';
14 | $appEnv = $_SERVER['APP_ENV'];
15 | $templatesPath = $basePath . '/templates';
16 |
17 | $container->add('APP_ENV', new \League\Container\Argument\Literal\StringArgument($appEnv));
18 | $databaseUrl = 'sqlite:///' . $basePath . '/var/db.sqlite';
19 |
20 | $container->add(
21 | 'base-commands-namespace',
22 | new \League\Container\Argument\Literal\StringArgument('GaryClarke\\Framework\\Console\\Command\\')
23 | );
24 |
25 | # services
26 |
27 | $container->add(
28 | GaryClarke\Framework\Routing\RouterInterface::class,
29 | GaryClarke\Framework\Routing\Router::class
30 | );
31 |
32 | $container->extend(GaryClarke\Framework\Routing\RouterInterface::class)
33 | ->addMethodCall(
34 | 'setRoutes',
35 | [new \League\Container\Argument\Literal\ArrayArgument($routes)]
36 | );
37 |
38 | $container->add(
39 | \GaryClarke\Framework\Http\Middleware\RequestHandlerInterface::class,
40 | \GaryClarke\Framework\Http\Middleware\RequestHandler::class
41 | )->addArgument($container);
42 |
43 | $container->addShared(\GaryClarke\Framework\EventDispatcher\EventDispatcher::class);
44 |
45 | $container->add(GaryClarke\Framework\Http\Kernel::class)
46 | ->addArguments([
47 | $container,
48 | \GaryClarke\Framework\Http\Middleware\RequestHandlerInterface::class,
49 | \GaryClarke\Framework\EventDispatcher\EventDispatcher::class
50 | ]);
51 |
52 | $container->add(\GaryClarke\Framework\Console\Application::class)
53 | ->addArgument($container);
54 |
55 | $container->add(\GaryClarke\Framework\Console\Kernel::class)
56 | ->addArguments([$container, \GaryClarke\Framework\Console\Application::class]);
57 |
58 | $container->addShared(
59 | \GaryClarke\Framework\Session\SessionInterface::class,
60 | \GaryClarke\Framework\Session\Session::class
61 | );
62 |
63 | $container->add('template-renderer-factory', \GaryClarke\Framework\Template\TwigFactory::class)
64 | ->addArguments([
65 | \GaryClarke\Framework\Session\SessionInterface::class,
66 | new \League\Container\Argument\Literal\StringArgument($templatesPath)
67 | ]);
68 |
69 | $container->addShared('twig', function () use ($container) {
70 | return $container->get('template-renderer-factory')->create();
71 | });
72 |
73 | $container->add(\GaryClarke\Framework\Controller\AbstractController::class);
74 |
75 | $container->inflector(\GaryClarke\Framework\Controller\AbstractController::class)
76 | ->invokeMethod('setContainer', [$container]);
77 |
78 | $container->add(\GaryClarke\Framework\Dbal\ConnectionFactory::class)
79 | ->addArguments([
80 | new \League\Container\Argument\Literal\StringArgument($databaseUrl)
81 | ]);
82 |
83 | $container->addShared(\Doctrine\DBAL\Connection::class, function () use ($container): \Doctrine\DBAL\Connection {
84 | return $container->get(\GaryClarke\Framework\Dbal\ConnectionFactory::class)->create();
85 | });
86 |
87 | $container->add(
88 | 'database:migrations:migrate',
89 | \GaryClarke\Framework\Console\Command\MigrateDatabase::class
90 | )->addArguments([
91 | \Doctrine\DBAL\Connection::class,
92 | new \League\Container\Argument\Literal\StringArgument($basePath . '/migrations')
93 | ]);
94 |
95 | $container->add(\GaryClarke\Framework\Http\Middleware\RouterDispatch::class)
96 | ->addArguments([
97 | \GaryClarke\Framework\Routing\RouterInterface::class,
98 | $container
99 | ]);
100 |
101 | $container->add(\GaryClarke\Framework\Authentication\SessionAuthentication::class)
102 | ->addArguments([
103 | \App\Repository\UserRepository::class,
104 | \GaryClarke\Framework\Session\SessionInterface::class
105 | ]);
106 |
107 | $container->add(\GaryClarke\Framework\Http\Middleware\ExtractRouteInfo::class)
108 | ->addArgument(new \League\Container\Argument\Literal\ArrayArgument($routes));
109 |
110 | return $container;
111 |
112 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | # server
3 | web:
4 | image: garyclarke/php-framework-web
5 | volumes:
6 | - ./public:/var/www/html/public
7 | ports:
8 | - "80:80"
9 | # application
10 | app:
11 | image: garyclarke/php-framework-app
12 | volumes:
13 | - .:/var/www/html
14 | extra_hosts:
15 | - host.docker.internal:host-gateway
16 |
--------------------------------------------------------------------------------
/framework/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
--------------------------------------------------------------------------------
/framework/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "garyclarketech/php-framework-pro",
3 | "description": "A PHP framework tutorial project",
4 | "minimum-stability": "dev",
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Gary Clarke",
9 | "email": "info@garyclarke.tech"
10 | }
11 | ],
12 | "autoload": {
13 | "psr-4": {
14 | "GaryClarke\\Framework\\": "src/"
15 | }
16 | },
17 | "autoload-dev": {
18 | "psr-4": {
19 | "GaryClarke\\Framework\\Tests\\": "tests"
20 | }
21 | },
22 | "require-dev": {
23 | "symfony/var-dumper": "6.3.x-dev",
24 | "phpunit/phpunit": "10.1.x-dev"
25 | },
26 | "require": {
27 | "nikic/fast-route": "dev-master",
28 | "psr/container": "2.0.x-dev",
29 | "league/container": "^4.0.0",
30 | "symfony/dotenv": "^6.0",
31 | "twig/twig": "^3.0",
32 | "doctrine/dbal": "^3.6",
33 | "psr/event-dispatcher": "^1.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/framework/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "62ca7c15188f039d13e48db41cb02d50",
8 | "packages": [
9 | {
10 | "name": "nikic/fast-route",
11 | "version": "dev-master",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/nikic/FastRoute.git",
15 | "reference": "ea5d3abe8b9fc7d63bb42b0384cb1db60972ff68"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/ea5d3abe8b9fc7d63bb42b0384cb1db60972ff68",
20 | "reference": "ea5d3abe8b9fc7d63bb42b0384cb1db60972ff68",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": ">=7.4.0"
25 | },
26 | "require-dev": {
27 | "doctrine/coding-standard": "^9.0",
28 | "phpbench/phpbench": "^1.0",
29 | "phpstan/extension-installer": "^1.0",
30 | "phpstan/phpstan": "^0.12",
31 | "phpstan/phpstan-deprecation-rules": "^0.12",
32 | "phpstan/phpstan-phpunit": "^0.12",
33 | "phpstan/phpstan-strict-rules": "^0.12",
34 | "phpunit/phpunit": "^9.5"
35 | },
36 | "suggest": {
37 | "ext-apcu": "To be able to use APCu cache driver"
38 | },
39 | "default-branch": true,
40 | "type": "library",
41 | "extra": {
42 | "branch-alias": {
43 | "dev-master": "2.0-dev"
44 | }
45 | },
46 | "autoload": {
47 | "files": [
48 | "src/functions.php"
49 | ],
50 | "psr-4": {
51 | "FastRoute\\": "src/"
52 | }
53 | },
54 | "notification-url": "https://packagist.org/downloads/",
55 | "license": [
56 | "BSD-3-Clause"
57 | ],
58 | "authors": [
59 | {
60 | "name": "Nikita Popov",
61 | "email": "nikic@php.net"
62 | }
63 | ],
64 | "description": "Fast request router for PHP",
65 | "keywords": [
66 | "router",
67 | "routing"
68 | ],
69 | "support": {
70 | "issues": "https://github.com/nikic/FastRoute/issues",
71 | "source": "https://github.com/nikic/FastRoute/tree/master"
72 | },
73 | "time": "2021-06-21T15:01:25+00:00"
74 | },
75 | {
76 | "name": "psr/container",
77 | "version": "dev-master",
78 | "source": {
79 | "type": "git",
80 | "url": "https://github.com/php-fig/container.git",
81 | "reference": "90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5"
82 | },
83 | "dist": {
84 | "type": "zip",
85 | "url": "https://api.github.com/repos/php-fig/container/zipball/90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5",
86 | "reference": "90db7b9ac2a2c5b849fcb69dde58f3ae182c68f5",
87 | "shasum": ""
88 | },
89 | "require": {
90 | "php": ">=7.4.0"
91 | },
92 | "default-branch": true,
93 | "type": "library",
94 | "extra": {
95 | "branch-alias": {
96 | "dev-master": "2.0.x-dev"
97 | }
98 | },
99 | "autoload": {
100 | "psr-4": {
101 | "Psr\\Container\\": "src/"
102 | }
103 | },
104 | "notification-url": "https://packagist.org/downloads/",
105 | "license": [
106 | "MIT"
107 | ],
108 | "authors": [
109 | {
110 | "name": "PHP-FIG",
111 | "homepage": "https://www.php-fig.org/"
112 | }
113 | ],
114 | "description": "Common Container Interface (PHP FIG PSR-11)",
115 | "homepage": "https://github.com/php-fig/container",
116 | "keywords": [
117 | "PSR-11",
118 | "container",
119 | "container-interface",
120 | "container-interop",
121 | "psr"
122 | ],
123 | "support": {
124 | "issues": "https://github.com/php-fig/container/issues",
125 | "source": "https://github.com/php-fig/container/tree/master"
126 | },
127 | "time": "2022-07-19T17:36:59+00:00"
128 | }
129 | ],
130 | "packages-dev": [
131 | {
132 | "name": "myclabs/deep-copy",
133 | "version": "1.x-dev",
134 | "source": {
135 | "type": "git",
136 | "url": "https://github.com/myclabs/DeepCopy.git",
137 | "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
138 | },
139 | "dist": {
140 | "type": "zip",
141 | "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
142 | "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
143 | "shasum": ""
144 | },
145 | "require": {
146 | "php": "^7.1 || ^8.0"
147 | },
148 | "conflict": {
149 | "doctrine/collections": "<1.6.8",
150 | "doctrine/common": "<2.13.3 || >=3,<3.2.2"
151 | },
152 | "require-dev": {
153 | "doctrine/collections": "^1.6.8",
154 | "doctrine/common": "^2.13.3 || ^3.2.2",
155 | "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
156 | },
157 | "default-branch": true,
158 | "type": "library",
159 | "autoload": {
160 | "files": [
161 | "src/DeepCopy/deep_copy.php"
162 | ],
163 | "psr-4": {
164 | "DeepCopy\\": "src/DeepCopy/"
165 | }
166 | },
167 | "notification-url": "https://packagist.org/downloads/",
168 | "license": [
169 | "MIT"
170 | ],
171 | "description": "Create deep copies (clones) of your objects",
172 | "keywords": [
173 | "clone",
174 | "copy",
175 | "duplicate",
176 | "object",
177 | "object graph"
178 | ],
179 | "support": {
180 | "issues": "https://github.com/myclabs/DeepCopy/issues",
181 | "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
182 | },
183 | "funding": [
184 | {
185 | "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
186 | "type": "tidelift"
187 | }
188 | ],
189 | "time": "2022-03-03T13:19:32+00:00"
190 | },
191 | {
192 | "name": "nikic/php-parser",
193 | "version": "4.x-dev",
194 | "source": {
195 | "type": "git",
196 | "url": "https://github.com/nikic/PHP-Parser.git",
197 | "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039"
198 | },
199 | "dist": {
200 | "type": "zip",
201 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039",
202 | "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039",
203 | "shasum": ""
204 | },
205 | "require": {
206 | "ext-tokenizer": "*",
207 | "php": ">=7.0"
208 | },
209 | "require-dev": {
210 | "ircmaxell/php-yacc": "^0.0.7",
211 | "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
212 | },
213 | "default-branch": true,
214 | "bin": [
215 | "bin/php-parse"
216 | ],
217 | "type": "library",
218 | "extra": {
219 | "branch-alias": {
220 | "dev-master": "4.9-dev"
221 | }
222 | },
223 | "autoload": {
224 | "psr-4": {
225 | "PhpParser\\": "lib/PhpParser"
226 | }
227 | },
228 | "notification-url": "https://packagist.org/downloads/",
229 | "license": [
230 | "BSD-3-Clause"
231 | ],
232 | "authors": [
233 | {
234 | "name": "Nikita Popov"
235 | }
236 | ],
237 | "description": "A PHP parser written in PHP",
238 | "keywords": [
239 | "parser",
240 | "php"
241 | ],
242 | "support": {
243 | "issues": "https://github.com/nikic/PHP-Parser/issues",
244 | "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3"
245 | },
246 | "time": "2023-01-16T22:05:37+00:00"
247 | },
248 | {
249 | "name": "phar-io/manifest",
250 | "version": "dev-master",
251 | "source": {
252 | "type": "git",
253 | "url": "https://github.com/phar-io/manifest.git",
254 | "reference": "36d8a21e851a9512db2b086dc5ac2c61308f0138"
255 | },
256 | "dist": {
257 | "type": "zip",
258 | "url": "https://api.github.com/repos/phar-io/manifest/zipball/36d8a21e851a9512db2b086dc5ac2c61308f0138",
259 | "reference": "36d8a21e851a9512db2b086dc5ac2c61308f0138",
260 | "shasum": ""
261 | },
262 | "require": {
263 | "ext-dom": "*",
264 | "ext-libxml": "*",
265 | "ext-phar": "*",
266 | "ext-xmlwriter": "*",
267 | "phar-io/version": "^3.0.1",
268 | "php": "^7.2 || ^8.0"
269 | },
270 | "default-branch": true,
271 | "type": "library",
272 | "extra": {
273 | "branch-alias": {
274 | "dev-master": "2.0.x-dev"
275 | }
276 | },
277 | "autoload": {
278 | "classmap": [
279 | "src/"
280 | ]
281 | },
282 | "notification-url": "https://packagist.org/downloads/",
283 | "license": [
284 | "BSD-3-Clause"
285 | ],
286 | "authors": [
287 | {
288 | "name": "Arne Blankerts",
289 | "email": "arne@blankerts.de",
290 | "role": "Developer"
291 | },
292 | {
293 | "name": "Sebastian Heuer",
294 | "email": "sebastian@phpeople.de",
295 | "role": "Developer"
296 | },
297 | {
298 | "name": "Sebastian Bergmann",
299 | "email": "sebastian@phpunit.de",
300 | "role": "Developer"
301 | }
302 | ],
303 | "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
304 | "support": {
305 | "issues": "https://github.com/phar-io/manifest/issues",
306 | "source": "https://github.com/phar-io/manifest/tree/master"
307 | },
308 | "funding": [
309 | {
310 | "url": "https://github.com/theseer",
311 | "type": "github"
312 | }
313 | ],
314 | "time": "2022-02-21T19:55:33+00:00"
315 | },
316 | {
317 | "name": "phar-io/version",
318 | "version": "3.2.1",
319 | "source": {
320 | "type": "git",
321 | "url": "https://github.com/phar-io/version.git",
322 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
323 | },
324 | "dist": {
325 | "type": "zip",
326 | "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
327 | "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
328 | "shasum": ""
329 | },
330 | "require": {
331 | "php": "^7.2 || ^8.0"
332 | },
333 | "type": "library",
334 | "autoload": {
335 | "classmap": [
336 | "src/"
337 | ]
338 | },
339 | "notification-url": "https://packagist.org/downloads/",
340 | "license": [
341 | "BSD-3-Clause"
342 | ],
343 | "authors": [
344 | {
345 | "name": "Arne Blankerts",
346 | "email": "arne@blankerts.de",
347 | "role": "Developer"
348 | },
349 | {
350 | "name": "Sebastian Heuer",
351 | "email": "sebastian@phpeople.de",
352 | "role": "Developer"
353 | },
354 | {
355 | "name": "Sebastian Bergmann",
356 | "email": "sebastian@phpunit.de",
357 | "role": "Developer"
358 | }
359 | ],
360 | "description": "Library for handling version information and constraints",
361 | "support": {
362 | "issues": "https://github.com/phar-io/version/issues",
363 | "source": "https://github.com/phar-io/version/tree/3.2.1"
364 | },
365 | "time": "2022-02-21T01:04:05+00:00"
366 | },
367 | {
368 | "name": "phpunit/php-code-coverage",
369 | "version": "dev-main",
370 | "source": {
371 | "type": "git",
372 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
373 | "reference": "bf4fbc9c13af7da12b3ea807574fb460f255daba"
374 | },
375 | "dist": {
376 | "type": "zip",
377 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bf4fbc9c13af7da12b3ea807574fb460f255daba",
378 | "reference": "bf4fbc9c13af7da12b3ea807574fb460f255daba",
379 | "shasum": ""
380 | },
381 | "require": {
382 | "ext-dom": "*",
383 | "ext-libxml": "*",
384 | "ext-xmlwriter": "*",
385 | "nikic/php-parser": "^4.14",
386 | "php": ">=8.1",
387 | "phpunit/php-file-iterator": "^4.0",
388 | "phpunit/php-text-template": "^3.0",
389 | "sebastian/code-unit-reverse-lookup": "^3.0",
390 | "sebastian/complexity": "^3.0",
391 | "sebastian/environment": "^6.0",
392 | "sebastian/lines-of-code": "^2.0",
393 | "sebastian/version": "^4.0",
394 | "theseer/tokenizer": "^1.2.0"
395 | },
396 | "require-dev": {
397 | "phpunit/phpunit": "^10.0"
398 | },
399 | "suggest": {
400 | "ext-pcov": "*",
401 | "ext-xdebug": "*"
402 | },
403 | "default-branch": true,
404 | "type": "library",
405 | "extra": {
406 | "branch-alias": {
407 | "dev-main": "10.0-dev"
408 | }
409 | },
410 | "autoload": {
411 | "classmap": [
412 | "src/"
413 | ]
414 | },
415 | "notification-url": "https://packagist.org/downloads/",
416 | "license": [
417 | "BSD-3-Clause"
418 | ],
419 | "authors": [
420 | {
421 | "name": "Sebastian Bergmann",
422 | "email": "sebastian@phpunit.de",
423 | "role": "lead"
424 | }
425 | ],
426 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
427 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
428 | "keywords": [
429 | "coverage",
430 | "testing",
431 | "xunit"
432 | ],
433 | "support": {
434 | "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
435 | "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.0.0"
436 | },
437 | "funding": [
438 | {
439 | "url": "https://github.com/sebastianbergmann",
440 | "type": "github"
441 | }
442 | ],
443 | "time": "2023-02-03T07:14:34+00:00"
444 | },
445 | {
446 | "name": "phpunit/php-file-iterator",
447 | "version": "dev-main",
448 | "source": {
449 | "type": "git",
450 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
451 | "reference": "7d66d4e816d34e90acec9db9d8d94b5cfbfe926f"
452 | },
453 | "dist": {
454 | "type": "zip",
455 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/7d66d4e816d34e90acec9db9d8d94b5cfbfe926f",
456 | "reference": "7d66d4e816d34e90acec9db9d8d94b5cfbfe926f",
457 | "shasum": ""
458 | },
459 | "require": {
460 | "php": ">=8.1"
461 | },
462 | "require-dev": {
463 | "phpunit/phpunit": "^10.0"
464 | },
465 | "default-branch": true,
466 | "type": "library",
467 | "extra": {
468 | "branch-alias": {
469 | "dev-main": "4.0-dev"
470 | }
471 | },
472 | "autoload": {
473 | "classmap": [
474 | "src/"
475 | ]
476 | },
477 | "notification-url": "https://packagist.org/downloads/",
478 | "license": [
479 | "BSD-3-Clause"
480 | ],
481 | "authors": [
482 | {
483 | "name": "Sebastian Bergmann",
484 | "email": "sebastian@phpunit.de",
485 | "role": "lead"
486 | }
487 | ],
488 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
489 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
490 | "keywords": [
491 | "filesystem",
492 | "iterator"
493 | ],
494 | "support": {
495 | "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
496 | "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.0.0"
497 | },
498 | "funding": [
499 | {
500 | "url": "https://github.com/sebastianbergmann",
501 | "type": "github"
502 | }
503 | ],
504 | "time": "2023-02-03T06:55:11+00:00"
505 | },
506 | {
507 | "name": "phpunit/php-invoker",
508 | "version": "dev-main",
509 | "source": {
510 | "type": "git",
511 | "url": "https://github.com/sebastianbergmann/php-invoker.git",
512 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
513 | },
514 | "dist": {
515 | "type": "zip",
516 | "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
517 | "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
518 | "shasum": ""
519 | },
520 | "require": {
521 | "php": ">=8.1"
522 | },
523 | "require-dev": {
524 | "ext-pcntl": "*",
525 | "phpunit/phpunit": "^10.0"
526 | },
527 | "suggest": {
528 | "ext-pcntl": "*"
529 | },
530 | "default-branch": true,
531 | "type": "library",
532 | "extra": {
533 | "branch-alias": {
534 | "dev-main": "4.0-dev"
535 | }
536 | },
537 | "autoload": {
538 | "classmap": [
539 | "src/"
540 | ]
541 | },
542 | "notification-url": "https://packagist.org/downloads/",
543 | "license": [
544 | "BSD-3-Clause"
545 | ],
546 | "authors": [
547 | {
548 | "name": "Sebastian Bergmann",
549 | "email": "sebastian@phpunit.de",
550 | "role": "lead"
551 | }
552 | ],
553 | "description": "Invoke callables with a timeout",
554 | "homepage": "https://github.com/sebastianbergmann/php-invoker/",
555 | "keywords": [
556 | "process"
557 | ],
558 | "support": {
559 | "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
560 | "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
561 | },
562 | "funding": [
563 | {
564 | "url": "https://github.com/sebastianbergmann",
565 | "type": "github"
566 | }
567 | ],
568 | "time": "2023-02-03T06:56:09+00:00"
569 | },
570 | {
571 | "name": "phpunit/php-text-template",
572 | "version": "dev-main",
573 | "source": {
574 | "type": "git",
575 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
576 | "reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d"
577 | },
578 | "dist": {
579 | "type": "zip",
580 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/9f3d3709577a527025f55bcf0f7ab8052c8bb37d",
581 | "reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d",
582 | "shasum": ""
583 | },
584 | "require": {
585 | "php": ">=8.1"
586 | },
587 | "require-dev": {
588 | "phpunit/phpunit": "^10.0"
589 | },
590 | "default-branch": true,
591 | "type": "library",
592 | "extra": {
593 | "branch-alias": {
594 | "dev-main": "3.0-dev"
595 | }
596 | },
597 | "autoload": {
598 | "classmap": [
599 | "src/"
600 | ]
601 | },
602 | "notification-url": "https://packagist.org/downloads/",
603 | "license": [
604 | "BSD-3-Clause"
605 | ],
606 | "authors": [
607 | {
608 | "name": "Sebastian Bergmann",
609 | "email": "sebastian@phpunit.de",
610 | "role": "lead"
611 | }
612 | ],
613 | "description": "Simple template engine.",
614 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
615 | "keywords": [
616 | "template"
617 | ],
618 | "support": {
619 | "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
620 | "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.0"
621 | },
622 | "funding": [
623 | {
624 | "url": "https://github.com/sebastianbergmann",
625 | "type": "github"
626 | }
627 | ],
628 | "time": "2023-02-03T06:56:46+00:00"
629 | },
630 | {
631 | "name": "phpunit/php-timer",
632 | "version": "dev-main",
633 | "source": {
634 | "type": "git",
635 | "url": "https://github.com/sebastianbergmann/php-timer.git",
636 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
637 | },
638 | "dist": {
639 | "type": "zip",
640 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
641 | "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
642 | "shasum": ""
643 | },
644 | "require": {
645 | "php": ">=8.1"
646 | },
647 | "require-dev": {
648 | "phpunit/phpunit": "^10.0"
649 | },
650 | "default-branch": true,
651 | "type": "library",
652 | "extra": {
653 | "branch-alias": {
654 | "dev-main": "6.0-dev"
655 | }
656 | },
657 | "autoload": {
658 | "classmap": [
659 | "src/"
660 | ]
661 | },
662 | "notification-url": "https://packagist.org/downloads/",
663 | "license": [
664 | "BSD-3-Clause"
665 | ],
666 | "authors": [
667 | {
668 | "name": "Sebastian Bergmann",
669 | "email": "sebastian@phpunit.de",
670 | "role": "lead"
671 | }
672 | ],
673 | "description": "Utility class for timing",
674 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
675 | "keywords": [
676 | "timer"
677 | ],
678 | "support": {
679 | "issues": "https://github.com/sebastianbergmann/php-timer/issues",
680 | "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
681 | },
682 | "funding": [
683 | {
684 | "url": "https://github.com/sebastianbergmann",
685 | "type": "github"
686 | }
687 | ],
688 | "time": "2023-02-03T06:57:52+00:00"
689 | },
690 | {
691 | "name": "phpunit/phpunit",
692 | "version": "dev-main",
693 | "source": {
694 | "type": "git",
695 | "url": "https://github.com/sebastianbergmann/phpunit.git",
696 | "reference": "8b1361ca3050006eb279390813eba842f8762ad7"
697 | },
698 | "dist": {
699 | "type": "zip",
700 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8b1361ca3050006eb279390813eba842f8762ad7",
701 | "reference": "8b1361ca3050006eb279390813eba842f8762ad7",
702 | "shasum": ""
703 | },
704 | "require": {
705 | "ext-dom": "*",
706 | "ext-json": "*",
707 | "ext-libxml": "*",
708 | "ext-mbstring": "*",
709 | "ext-xml": "*",
710 | "ext-xmlwriter": "*",
711 | "myclabs/deep-copy": "^1.10.1",
712 | "phar-io/manifest": "^2.0.3",
713 | "phar-io/version": "^3.0.2",
714 | "php": ">=8.1",
715 | "phpunit/php-code-coverage": "^10.0",
716 | "phpunit/php-file-iterator": "^4.0",
717 | "phpunit/php-invoker": "^4.0",
718 | "phpunit/php-text-template": "^3.0",
719 | "phpunit/php-timer": "^6.0",
720 | "sebastian/cli-parser": "^2.0",
721 | "sebastian/code-unit": "^2.0",
722 | "sebastian/comparator": "^5.0",
723 | "sebastian/diff": "^5.0",
724 | "sebastian/environment": "^6.0",
725 | "sebastian/exporter": "^5.0",
726 | "sebastian/global-state": "^6.0",
727 | "sebastian/object-enumerator": "^5.0",
728 | "sebastian/recursion-context": "^5.0",
729 | "sebastian/type": "^4.0",
730 | "sebastian/version": "^4.0"
731 | },
732 | "suggest": {
733 | "ext-soap": "*"
734 | },
735 | "default-branch": true,
736 | "bin": [
737 | "phpunit"
738 | ],
739 | "type": "library",
740 | "extra": {
741 | "branch-alias": {
742 | "dev-main": "10.1-dev"
743 | }
744 | },
745 | "autoload": {
746 | "files": [
747 | "src/Framework/Assert/Functions.php"
748 | ],
749 | "classmap": [
750 | "src/"
751 | ]
752 | },
753 | "notification-url": "https://packagist.org/downloads/",
754 | "license": [
755 | "BSD-3-Clause"
756 | ],
757 | "authors": [
758 | {
759 | "name": "Sebastian Bergmann",
760 | "email": "sebastian@phpunit.de",
761 | "role": "lead"
762 | }
763 | ],
764 | "description": "The PHP Unit Testing framework.",
765 | "homepage": "https://phpunit.de/",
766 | "keywords": [
767 | "phpunit",
768 | "testing",
769 | "xunit"
770 | ],
771 | "support": {
772 | "issues": "https://github.com/sebastianbergmann/phpunit/issues",
773 | "source": "https://github.com/sebastianbergmann/phpunit/tree/main"
774 | },
775 | "funding": [
776 | {
777 | "url": "https://phpunit.de/sponsors.html",
778 | "type": "custom"
779 | },
780 | {
781 | "url": "https://github.com/sebastianbergmann",
782 | "type": "github"
783 | },
784 | {
785 | "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
786 | "type": "tidelift"
787 | }
788 | ],
789 | "time": "2023-02-03T19:42:15+00:00"
790 | },
791 | {
792 | "name": "sebastian/cli-parser",
793 | "version": "dev-main",
794 | "source": {
795 | "type": "git",
796 | "url": "https://github.com/sebastianbergmann/cli-parser.git",
797 | "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae"
798 | },
799 | "dist": {
800 | "type": "zip",
801 | "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efdc130dbbbb8ef0b545a994fd811725c5282cae",
802 | "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae",
803 | "shasum": ""
804 | },
805 | "require": {
806 | "php": ">=8.1"
807 | },
808 | "require-dev": {
809 | "phpunit/phpunit": "^10.0"
810 | },
811 | "default-branch": true,
812 | "type": "library",
813 | "extra": {
814 | "branch-alias": {
815 | "dev-main": "2.0-dev"
816 | }
817 | },
818 | "autoload": {
819 | "classmap": [
820 | "src/"
821 | ]
822 | },
823 | "notification-url": "https://packagist.org/downloads/",
824 | "license": [
825 | "BSD-3-Clause"
826 | ],
827 | "authors": [
828 | {
829 | "name": "Sebastian Bergmann",
830 | "email": "sebastian@phpunit.de",
831 | "role": "lead"
832 | }
833 | ],
834 | "description": "Library for parsing CLI options",
835 | "homepage": "https://github.com/sebastianbergmann/cli-parser",
836 | "support": {
837 | "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
838 | "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.0"
839 | },
840 | "funding": [
841 | {
842 | "url": "https://github.com/sebastianbergmann",
843 | "type": "github"
844 | }
845 | ],
846 | "time": "2023-02-03T06:58:15+00:00"
847 | },
848 | {
849 | "name": "sebastian/code-unit",
850 | "version": "dev-main",
851 | "source": {
852 | "type": "git",
853 | "url": "https://github.com/sebastianbergmann/code-unit.git",
854 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
855 | },
856 | "dist": {
857 | "type": "zip",
858 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
859 | "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
860 | "shasum": ""
861 | },
862 | "require": {
863 | "php": ">=8.1"
864 | },
865 | "require-dev": {
866 | "phpunit/phpunit": "^10.0"
867 | },
868 | "default-branch": true,
869 | "type": "library",
870 | "extra": {
871 | "branch-alias": {
872 | "dev-main": "2.0-dev"
873 | }
874 | },
875 | "autoload": {
876 | "classmap": [
877 | "src/"
878 | ]
879 | },
880 | "notification-url": "https://packagist.org/downloads/",
881 | "license": [
882 | "BSD-3-Clause"
883 | ],
884 | "authors": [
885 | {
886 | "name": "Sebastian Bergmann",
887 | "email": "sebastian@phpunit.de",
888 | "role": "lead"
889 | }
890 | ],
891 | "description": "Collection of value objects that represent the PHP code units",
892 | "homepage": "https://github.com/sebastianbergmann/code-unit",
893 | "support": {
894 | "issues": "https://github.com/sebastianbergmann/code-unit/issues",
895 | "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
896 | },
897 | "funding": [
898 | {
899 | "url": "https://github.com/sebastianbergmann",
900 | "type": "github"
901 | }
902 | ],
903 | "time": "2023-02-03T06:58:43+00:00"
904 | },
905 | {
906 | "name": "sebastian/code-unit-reverse-lookup",
907 | "version": "dev-main",
908 | "source": {
909 | "type": "git",
910 | "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
911 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
912 | },
913 | "dist": {
914 | "type": "zip",
915 | "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
916 | "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
917 | "shasum": ""
918 | },
919 | "require": {
920 | "php": ">=8.1"
921 | },
922 | "require-dev": {
923 | "phpunit/phpunit": "^10.0"
924 | },
925 | "default-branch": true,
926 | "type": "library",
927 | "extra": {
928 | "branch-alias": {
929 | "dev-main": "3.0-dev"
930 | }
931 | },
932 | "autoload": {
933 | "classmap": [
934 | "src/"
935 | ]
936 | },
937 | "notification-url": "https://packagist.org/downloads/",
938 | "license": [
939 | "BSD-3-Clause"
940 | ],
941 | "authors": [
942 | {
943 | "name": "Sebastian Bergmann",
944 | "email": "sebastian@phpunit.de"
945 | }
946 | ],
947 | "description": "Looks up which function or method a line of code belongs to",
948 | "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
949 | "support": {
950 | "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
951 | "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
952 | },
953 | "funding": [
954 | {
955 | "url": "https://github.com/sebastianbergmann",
956 | "type": "github"
957 | }
958 | ],
959 | "time": "2023-02-03T06:59:15+00:00"
960 | },
961 | {
962 | "name": "sebastian/comparator",
963 | "version": "dev-main",
964 | "source": {
965 | "type": "git",
966 | "url": "https://github.com/sebastianbergmann/comparator.git",
967 | "reference": "72f01e6586e0caf6af81297897bd112eb7e9627c"
968 | },
969 | "dist": {
970 | "type": "zip",
971 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/72f01e6586e0caf6af81297897bd112eb7e9627c",
972 | "reference": "72f01e6586e0caf6af81297897bd112eb7e9627c",
973 | "shasum": ""
974 | },
975 | "require": {
976 | "ext-dom": "*",
977 | "ext-mbstring": "*",
978 | "php": ">=8.1",
979 | "sebastian/diff": "^5.0",
980 | "sebastian/exporter": "^5.0"
981 | },
982 | "require-dev": {
983 | "phpunit/phpunit": "^10.0"
984 | },
985 | "default-branch": true,
986 | "type": "library",
987 | "extra": {
988 | "branch-alias": {
989 | "dev-main": "5.0-dev"
990 | }
991 | },
992 | "autoload": {
993 | "classmap": [
994 | "src/"
995 | ]
996 | },
997 | "notification-url": "https://packagist.org/downloads/",
998 | "license": [
999 | "BSD-3-Clause"
1000 | ],
1001 | "authors": [
1002 | {
1003 | "name": "Sebastian Bergmann",
1004 | "email": "sebastian@phpunit.de"
1005 | },
1006 | {
1007 | "name": "Jeff Welch",
1008 | "email": "whatthejeff@gmail.com"
1009 | },
1010 | {
1011 | "name": "Volker Dusch",
1012 | "email": "github@wallbash.com"
1013 | },
1014 | {
1015 | "name": "Bernhard Schussek",
1016 | "email": "bschussek@2bepublished.at"
1017 | }
1018 | ],
1019 | "description": "Provides the functionality to compare PHP values for equality",
1020 | "homepage": "https://github.com/sebastianbergmann/comparator",
1021 | "keywords": [
1022 | "comparator",
1023 | "compare",
1024 | "equality"
1025 | ],
1026 | "support": {
1027 | "issues": "https://github.com/sebastianbergmann/comparator/issues",
1028 | "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.0"
1029 | },
1030 | "funding": [
1031 | {
1032 | "url": "https://github.com/sebastianbergmann",
1033 | "type": "github"
1034 | }
1035 | ],
1036 | "time": "2023-02-03T07:07:16+00:00"
1037 | },
1038 | {
1039 | "name": "sebastian/complexity",
1040 | "version": "dev-main",
1041 | "source": {
1042 | "type": "git",
1043 | "url": "https://github.com/sebastianbergmann/complexity.git",
1044 | "reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6"
1045 | },
1046 | "dist": {
1047 | "type": "zip",
1048 | "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/e67d240970c9dc7ea7b2123a6d520e334dd61dc6",
1049 | "reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6",
1050 | "shasum": ""
1051 | },
1052 | "require": {
1053 | "nikic/php-parser": "^4.10",
1054 | "php": ">=8.1"
1055 | },
1056 | "require-dev": {
1057 | "phpunit/phpunit": "^10.0"
1058 | },
1059 | "default-branch": true,
1060 | "type": "library",
1061 | "extra": {
1062 | "branch-alias": {
1063 | "dev-main": "3.0-dev"
1064 | }
1065 | },
1066 | "autoload": {
1067 | "classmap": [
1068 | "src/"
1069 | ]
1070 | },
1071 | "notification-url": "https://packagist.org/downloads/",
1072 | "license": [
1073 | "BSD-3-Clause"
1074 | ],
1075 | "authors": [
1076 | {
1077 | "name": "Sebastian Bergmann",
1078 | "email": "sebastian@phpunit.de",
1079 | "role": "lead"
1080 | }
1081 | ],
1082 | "description": "Library for calculating the complexity of PHP code units",
1083 | "homepage": "https://github.com/sebastianbergmann/complexity",
1084 | "support": {
1085 | "issues": "https://github.com/sebastianbergmann/complexity/issues",
1086 | "source": "https://github.com/sebastianbergmann/complexity/tree/3.0.0"
1087 | },
1088 | "funding": [
1089 | {
1090 | "url": "https://github.com/sebastianbergmann",
1091 | "type": "github"
1092 | }
1093 | ],
1094 | "time": "2023-02-03T06:59:47+00:00"
1095 | },
1096 | {
1097 | "name": "sebastian/diff",
1098 | "version": "dev-main",
1099 | "source": {
1100 | "type": "git",
1101 | "url": "https://github.com/sebastianbergmann/diff.git",
1102 | "reference": "70dd1b20bc198da394ad542e988381b44e64e39f"
1103 | },
1104 | "dist": {
1105 | "type": "zip",
1106 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/70dd1b20bc198da394ad542e988381b44e64e39f",
1107 | "reference": "70dd1b20bc198da394ad542e988381b44e64e39f",
1108 | "shasum": ""
1109 | },
1110 | "require": {
1111 | "php": ">=8.1"
1112 | },
1113 | "require-dev": {
1114 | "phpunit/phpunit": "^10.0",
1115 | "symfony/process": "^4.2 || ^5"
1116 | },
1117 | "default-branch": true,
1118 | "type": "library",
1119 | "extra": {
1120 | "branch-alias": {
1121 | "dev-main": "5.0-dev"
1122 | }
1123 | },
1124 | "autoload": {
1125 | "classmap": [
1126 | "src/"
1127 | ]
1128 | },
1129 | "notification-url": "https://packagist.org/downloads/",
1130 | "license": [
1131 | "BSD-3-Clause"
1132 | ],
1133 | "authors": [
1134 | {
1135 | "name": "Sebastian Bergmann",
1136 | "email": "sebastian@phpunit.de"
1137 | },
1138 | {
1139 | "name": "Kore Nordmann",
1140 | "email": "mail@kore-nordmann.de"
1141 | }
1142 | ],
1143 | "description": "Diff implementation",
1144 | "homepage": "https://github.com/sebastianbergmann/diff",
1145 | "keywords": [
1146 | "diff",
1147 | "udiff",
1148 | "unidiff",
1149 | "unified diff"
1150 | ],
1151 | "support": {
1152 | "issues": "https://github.com/sebastianbergmann/diff/issues",
1153 | "source": "https://github.com/sebastianbergmann/diff/tree/5.0.0"
1154 | },
1155 | "funding": [
1156 | {
1157 | "url": "https://github.com/sebastianbergmann",
1158 | "type": "github"
1159 | }
1160 | ],
1161 | "time": "2023-02-03T07:00:31+00:00"
1162 | },
1163 | {
1164 | "name": "sebastian/environment",
1165 | "version": "dev-main",
1166 | "source": {
1167 | "type": "git",
1168 | "url": "https://github.com/sebastianbergmann/environment.git",
1169 | "reference": "b6f3694c6386c7959915a0037652e0c40f6f69cc"
1170 | },
1171 | "dist": {
1172 | "type": "zip",
1173 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/b6f3694c6386c7959915a0037652e0c40f6f69cc",
1174 | "reference": "b6f3694c6386c7959915a0037652e0c40f6f69cc",
1175 | "shasum": ""
1176 | },
1177 | "require": {
1178 | "php": ">=8.1"
1179 | },
1180 | "require-dev": {
1181 | "phpunit/phpunit": "^10.0"
1182 | },
1183 | "suggest": {
1184 | "ext-posix": "*"
1185 | },
1186 | "default-branch": true,
1187 | "type": "library",
1188 | "extra": {
1189 | "branch-alias": {
1190 | "dev-main": "6.0-dev"
1191 | }
1192 | },
1193 | "autoload": {
1194 | "classmap": [
1195 | "src/"
1196 | ]
1197 | },
1198 | "notification-url": "https://packagist.org/downloads/",
1199 | "license": [
1200 | "BSD-3-Clause"
1201 | ],
1202 | "authors": [
1203 | {
1204 | "name": "Sebastian Bergmann",
1205 | "email": "sebastian@phpunit.de"
1206 | }
1207 | ],
1208 | "description": "Provides functionality to handle HHVM/PHP environments",
1209 | "homepage": "https://github.com/sebastianbergmann/environment",
1210 | "keywords": [
1211 | "Xdebug",
1212 | "environment",
1213 | "hhvm"
1214 | ],
1215 | "support": {
1216 | "issues": "https://github.com/sebastianbergmann/environment/issues",
1217 | "source": "https://github.com/sebastianbergmann/environment/tree/6.0.0"
1218 | },
1219 | "funding": [
1220 | {
1221 | "url": "https://github.com/sebastianbergmann",
1222 | "type": "github"
1223 | }
1224 | ],
1225 | "time": "2023-02-03T07:03:04+00:00"
1226 | },
1227 | {
1228 | "name": "sebastian/exporter",
1229 | "version": "dev-main",
1230 | "source": {
1231 | "type": "git",
1232 | "url": "https://github.com/sebastianbergmann/exporter.git",
1233 | "reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0"
1234 | },
1235 | "dist": {
1236 | "type": "zip",
1237 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0",
1238 | "reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0",
1239 | "shasum": ""
1240 | },
1241 | "require": {
1242 | "ext-mbstring": "*",
1243 | "php": ">=8.1",
1244 | "sebastian/recursion-context": "^5.0"
1245 | },
1246 | "require-dev": {
1247 | "phpunit/phpunit": "^10.0"
1248 | },
1249 | "default-branch": true,
1250 | "type": "library",
1251 | "extra": {
1252 | "branch-alias": {
1253 | "dev-main": "5.0-dev"
1254 | }
1255 | },
1256 | "autoload": {
1257 | "classmap": [
1258 | "src/"
1259 | ]
1260 | },
1261 | "notification-url": "https://packagist.org/downloads/",
1262 | "license": [
1263 | "BSD-3-Clause"
1264 | ],
1265 | "authors": [
1266 | {
1267 | "name": "Sebastian Bergmann",
1268 | "email": "sebastian@phpunit.de"
1269 | },
1270 | {
1271 | "name": "Jeff Welch",
1272 | "email": "whatthejeff@gmail.com"
1273 | },
1274 | {
1275 | "name": "Volker Dusch",
1276 | "email": "github@wallbash.com"
1277 | },
1278 | {
1279 | "name": "Adam Harvey",
1280 | "email": "aharvey@php.net"
1281 | },
1282 | {
1283 | "name": "Bernhard Schussek",
1284 | "email": "bschussek@gmail.com"
1285 | }
1286 | ],
1287 | "description": "Provides the functionality to export PHP variables for visualization",
1288 | "homepage": "https://www.github.com/sebastianbergmann/exporter",
1289 | "keywords": [
1290 | "export",
1291 | "exporter"
1292 | ],
1293 | "support": {
1294 | "issues": "https://github.com/sebastianbergmann/exporter/issues",
1295 | "source": "https://github.com/sebastianbergmann/exporter/tree/5.0.0"
1296 | },
1297 | "funding": [
1298 | {
1299 | "url": "https://github.com/sebastianbergmann",
1300 | "type": "github"
1301 | }
1302 | ],
1303 | "time": "2023-02-03T07:06:49+00:00"
1304 | },
1305 | {
1306 | "name": "sebastian/global-state",
1307 | "version": "dev-main",
1308 | "source": {
1309 | "type": "git",
1310 | "url": "https://github.com/sebastianbergmann/global-state.git",
1311 | "reference": "aab257c712de87b90194febd52e4d184551c2d44"
1312 | },
1313 | "dist": {
1314 | "type": "zip",
1315 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/aab257c712de87b90194febd52e4d184551c2d44",
1316 | "reference": "aab257c712de87b90194febd52e4d184551c2d44",
1317 | "shasum": ""
1318 | },
1319 | "require": {
1320 | "php": ">=8.1",
1321 | "sebastian/object-reflector": "^3.0",
1322 | "sebastian/recursion-context": "^5.0"
1323 | },
1324 | "require-dev": {
1325 | "ext-dom": "*",
1326 | "phpunit/phpunit": "^10.0"
1327 | },
1328 | "default-branch": true,
1329 | "type": "library",
1330 | "extra": {
1331 | "branch-alias": {
1332 | "dev-main": "6.0-dev"
1333 | }
1334 | },
1335 | "autoload": {
1336 | "classmap": [
1337 | "src/"
1338 | ]
1339 | },
1340 | "notification-url": "https://packagist.org/downloads/",
1341 | "license": [
1342 | "BSD-3-Clause"
1343 | ],
1344 | "authors": [
1345 | {
1346 | "name": "Sebastian Bergmann",
1347 | "email": "sebastian@phpunit.de"
1348 | }
1349 | ],
1350 | "description": "Snapshotting of global state",
1351 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1352 | "keywords": [
1353 | "global state"
1354 | ],
1355 | "support": {
1356 | "issues": "https://github.com/sebastianbergmann/global-state/issues",
1357 | "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.0"
1358 | },
1359 | "funding": [
1360 | {
1361 | "url": "https://github.com/sebastianbergmann",
1362 | "type": "github"
1363 | }
1364 | ],
1365 | "time": "2023-02-03T07:07:38+00:00"
1366 | },
1367 | {
1368 | "name": "sebastian/lines-of-code",
1369 | "version": "dev-main",
1370 | "source": {
1371 | "type": "git",
1372 | "url": "https://github.com/sebastianbergmann/lines-of-code.git",
1373 | "reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130"
1374 | },
1375 | "dist": {
1376 | "type": "zip",
1377 | "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/17c4d940ecafb3d15d2cf916f4108f664e28b130",
1378 | "reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130",
1379 | "shasum": ""
1380 | },
1381 | "require": {
1382 | "nikic/php-parser": "^4.10",
1383 | "php": ">=8.1"
1384 | },
1385 | "require-dev": {
1386 | "phpunit/phpunit": "^10.0"
1387 | },
1388 | "default-branch": true,
1389 | "type": "library",
1390 | "extra": {
1391 | "branch-alias": {
1392 | "dev-main": "2.0-dev"
1393 | }
1394 | },
1395 | "autoload": {
1396 | "classmap": [
1397 | "src/"
1398 | ]
1399 | },
1400 | "notification-url": "https://packagist.org/downloads/",
1401 | "license": [
1402 | "BSD-3-Clause"
1403 | ],
1404 | "authors": [
1405 | {
1406 | "name": "Sebastian Bergmann",
1407 | "email": "sebastian@phpunit.de",
1408 | "role": "lead"
1409 | }
1410 | ],
1411 | "description": "Library for counting the lines of code in PHP source code",
1412 | "homepage": "https://github.com/sebastianbergmann/lines-of-code",
1413 | "support": {
1414 | "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
1415 | "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.0"
1416 | },
1417 | "funding": [
1418 | {
1419 | "url": "https://github.com/sebastianbergmann",
1420 | "type": "github"
1421 | }
1422 | ],
1423 | "time": "2023-02-03T07:08:02+00:00"
1424 | },
1425 | {
1426 | "name": "sebastian/object-enumerator",
1427 | "version": "dev-main",
1428 | "source": {
1429 | "type": "git",
1430 | "url": "https://github.com/sebastianbergmann/object-enumerator.git",
1431 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
1432 | },
1433 | "dist": {
1434 | "type": "zip",
1435 | "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
1436 | "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
1437 | "shasum": ""
1438 | },
1439 | "require": {
1440 | "php": ">=8.1",
1441 | "sebastian/object-reflector": "^3.0",
1442 | "sebastian/recursion-context": "^5.0"
1443 | },
1444 | "require-dev": {
1445 | "phpunit/phpunit": "^10.0"
1446 | },
1447 | "default-branch": true,
1448 | "type": "library",
1449 | "extra": {
1450 | "branch-alias": {
1451 | "dev-main": "5.0-dev"
1452 | }
1453 | },
1454 | "autoload": {
1455 | "classmap": [
1456 | "src/"
1457 | ]
1458 | },
1459 | "notification-url": "https://packagist.org/downloads/",
1460 | "license": [
1461 | "BSD-3-Clause"
1462 | ],
1463 | "authors": [
1464 | {
1465 | "name": "Sebastian Bergmann",
1466 | "email": "sebastian@phpunit.de"
1467 | }
1468 | ],
1469 | "description": "Traverses array structures and object graphs to enumerate all referenced objects",
1470 | "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
1471 | "support": {
1472 | "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
1473 | "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
1474 | },
1475 | "funding": [
1476 | {
1477 | "url": "https://github.com/sebastianbergmann",
1478 | "type": "github"
1479 | }
1480 | ],
1481 | "time": "2023-02-03T07:08:32+00:00"
1482 | },
1483 | {
1484 | "name": "sebastian/object-reflector",
1485 | "version": "dev-main",
1486 | "source": {
1487 | "type": "git",
1488 | "url": "https://github.com/sebastianbergmann/object-reflector.git",
1489 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
1490 | },
1491 | "dist": {
1492 | "type": "zip",
1493 | "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
1494 | "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
1495 | "shasum": ""
1496 | },
1497 | "require": {
1498 | "php": ">=8.1"
1499 | },
1500 | "require-dev": {
1501 | "phpunit/phpunit": "^10.0"
1502 | },
1503 | "default-branch": true,
1504 | "type": "library",
1505 | "extra": {
1506 | "branch-alias": {
1507 | "dev-main": "3.0-dev"
1508 | }
1509 | },
1510 | "autoload": {
1511 | "classmap": [
1512 | "src/"
1513 | ]
1514 | },
1515 | "notification-url": "https://packagist.org/downloads/",
1516 | "license": [
1517 | "BSD-3-Clause"
1518 | ],
1519 | "authors": [
1520 | {
1521 | "name": "Sebastian Bergmann",
1522 | "email": "sebastian@phpunit.de"
1523 | }
1524 | ],
1525 | "description": "Allows reflection of object attributes, including inherited and non-public ones",
1526 | "homepage": "https://github.com/sebastianbergmann/object-reflector/",
1527 | "support": {
1528 | "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
1529 | "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
1530 | },
1531 | "funding": [
1532 | {
1533 | "url": "https://github.com/sebastianbergmann",
1534 | "type": "github"
1535 | }
1536 | ],
1537 | "time": "2023-02-03T07:06:18+00:00"
1538 | },
1539 | {
1540 | "name": "sebastian/recursion-context",
1541 | "version": "dev-main",
1542 | "source": {
1543 | "type": "git",
1544 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1545 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712"
1546 | },
1547 | "dist": {
1548 | "type": "zip",
1549 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712",
1550 | "reference": "05909fb5bc7df4c52992396d0116aed689f93712",
1551 | "shasum": ""
1552 | },
1553 | "require": {
1554 | "php": ">=8.1"
1555 | },
1556 | "require-dev": {
1557 | "phpunit/phpunit": "^10.0"
1558 | },
1559 | "default-branch": true,
1560 | "type": "library",
1561 | "extra": {
1562 | "branch-alias": {
1563 | "dev-main": "5.0-dev"
1564 | }
1565 | },
1566 | "autoload": {
1567 | "classmap": [
1568 | "src/"
1569 | ]
1570 | },
1571 | "notification-url": "https://packagist.org/downloads/",
1572 | "license": [
1573 | "BSD-3-Clause"
1574 | ],
1575 | "authors": [
1576 | {
1577 | "name": "Sebastian Bergmann",
1578 | "email": "sebastian@phpunit.de"
1579 | },
1580 | {
1581 | "name": "Jeff Welch",
1582 | "email": "whatthejeff@gmail.com"
1583 | },
1584 | {
1585 | "name": "Adam Harvey",
1586 | "email": "aharvey@php.net"
1587 | }
1588 | ],
1589 | "description": "Provides functionality to recursively process PHP variables",
1590 | "homepage": "https://github.com/sebastianbergmann/recursion-context",
1591 | "support": {
1592 | "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
1593 | "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0"
1594 | },
1595 | "funding": [
1596 | {
1597 | "url": "https://github.com/sebastianbergmann",
1598 | "type": "github"
1599 | }
1600 | ],
1601 | "time": "2023-02-03T07:05:40+00:00"
1602 | },
1603 | {
1604 | "name": "sebastian/type",
1605 | "version": "dev-main",
1606 | "source": {
1607 | "type": "git",
1608 | "url": "https://github.com/sebastianbergmann/type.git",
1609 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
1610 | },
1611 | "dist": {
1612 | "type": "zip",
1613 | "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
1614 | "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
1615 | "shasum": ""
1616 | },
1617 | "require": {
1618 | "php": ">=8.1"
1619 | },
1620 | "require-dev": {
1621 | "phpunit/phpunit": "^10.0"
1622 | },
1623 | "default-branch": true,
1624 | "type": "library",
1625 | "extra": {
1626 | "branch-alias": {
1627 | "dev-main": "4.0-dev"
1628 | }
1629 | },
1630 | "autoload": {
1631 | "classmap": [
1632 | "src/"
1633 | ]
1634 | },
1635 | "notification-url": "https://packagist.org/downloads/",
1636 | "license": [
1637 | "BSD-3-Clause"
1638 | ],
1639 | "authors": [
1640 | {
1641 | "name": "Sebastian Bergmann",
1642 | "email": "sebastian@phpunit.de",
1643 | "role": "lead"
1644 | }
1645 | ],
1646 | "description": "Collection of value objects that represent the types of the PHP type system",
1647 | "homepage": "https://github.com/sebastianbergmann/type",
1648 | "support": {
1649 | "issues": "https://github.com/sebastianbergmann/type/issues",
1650 | "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
1651 | },
1652 | "funding": [
1653 | {
1654 | "url": "https://github.com/sebastianbergmann",
1655 | "type": "github"
1656 | }
1657 | ],
1658 | "time": "2023-02-03T07:10:45+00:00"
1659 | },
1660 | {
1661 | "name": "sebastian/version",
1662 | "version": "dev-main",
1663 | "source": {
1664 | "type": "git",
1665 | "url": "https://github.com/sebastianbergmann/version.git",
1666 | "reference": "5facf5a20311ac44f79221274cdeb6c569ca11dd"
1667 | },
1668 | "dist": {
1669 | "type": "zip",
1670 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/5facf5a20311ac44f79221274cdeb6c569ca11dd",
1671 | "reference": "5facf5a20311ac44f79221274cdeb6c569ca11dd",
1672 | "shasum": ""
1673 | },
1674 | "require": {
1675 | "php": ">=8.1"
1676 | },
1677 | "default-branch": true,
1678 | "type": "library",
1679 | "extra": {
1680 | "branch-alias": {
1681 | "dev-main": "4.0-dev"
1682 | }
1683 | },
1684 | "autoload": {
1685 | "classmap": [
1686 | "src/"
1687 | ]
1688 | },
1689 | "notification-url": "https://packagist.org/downloads/",
1690 | "license": [
1691 | "BSD-3-Clause"
1692 | ],
1693 | "authors": [
1694 | {
1695 | "name": "Sebastian Bergmann",
1696 | "email": "sebastian@phpunit.de",
1697 | "role": "lead"
1698 | }
1699 | ],
1700 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1701 | "homepage": "https://github.com/sebastianbergmann/version",
1702 | "support": {
1703 | "issues": "https://github.com/sebastianbergmann/version/issues",
1704 | "source": "https://github.com/sebastianbergmann/version/tree/4.0.0"
1705 | },
1706 | "funding": [
1707 | {
1708 | "url": "https://github.com/sebastianbergmann",
1709 | "type": "github"
1710 | }
1711 | ],
1712 | "time": "2023-02-03T07:11:37+00:00"
1713 | },
1714 | {
1715 | "name": "symfony/polyfill-mbstring",
1716 | "version": "dev-main",
1717 | "source": {
1718 | "type": "git",
1719 | "url": "https://github.com/symfony/polyfill-mbstring.git",
1720 | "reference": "f9c7affe77a00ae32ca127ca6833d034e6d33f25"
1721 | },
1722 | "dist": {
1723 | "type": "zip",
1724 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f9c7affe77a00ae32ca127ca6833d034e6d33f25",
1725 | "reference": "f9c7affe77a00ae32ca127ca6833d034e6d33f25",
1726 | "shasum": ""
1727 | },
1728 | "require": {
1729 | "php": ">=7.1"
1730 | },
1731 | "provide": {
1732 | "ext-mbstring": "*"
1733 | },
1734 | "suggest": {
1735 | "ext-mbstring": "For best performance"
1736 | },
1737 | "default-branch": true,
1738 | "type": "library",
1739 | "extra": {
1740 | "branch-alias": {
1741 | "dev-main": "1.28-dev"
1742 | },
1743 | "thanks": {
1744 | "name": "symfony/polyfill",
1745 | "url": "https://github.com/symfony/polyfill"
1746 | }
1747 | },
1748 | "autoload": {
1749 | "files": [
1750 | "bootstrap.php"
1751 | ],
1752 | "psr-4": {
1753 | "Symfony\\Polyfill\\Mbstring\\": ""
1754 | }
1755 | },
1756 | "notification-url": "https://packagist.org/downloads/",
1757 | "license": [
1758 | "MIT"
1759 | ],
1760 | "authors": [
1761 | {
1762 | "name": "Nicolas Grekas",
1763 | "email": "p@tchwork.com"
1764 | },
1765 | {
1766 | "name": "Symfony Community",
1767 | "homepage": "https://symfony.com/contributors"
1768 | }
1769 | ],
1770 | "description": "Symfony polyfill for the Mbstring extension",
1771 | "homepage": "https://symfony.com",
1772 | "keywords": [
1773 | "compatibility",
1774 | "mbstring",
1775 | "polyfill",
1776 | "portable",
1777 | "shim"
1778 | ],
1779 | "support": {
1780 | "source": "https://github.com/symfony/polyfill-mbstring/tree/main"
1781 | },
1782 | "funding": [
1783 | {
1784 | "url": "https://symfony.com/sponsor",
1785 | "type": "custom"
1786 | },
1787 | {
1788 | "url": "https://github.com/fabpot",
1789 | "type": "github"
1790 | },
1791 | {
1792 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1793 | "type": "tidelift"
1794 | }
1795 | ],
1796 | "time": "2023-01-30T17:25:47+00:00"
1797 | },
1798 | {
1799 | "name": "symfony/var-dumper",
1800 | "version": "6.3.x-dev",
1801 | "source": {
1802 | "type": "git",
1803 | "url": "https://github.com/symfony/var-dumper.git",
1804 | "reference": "967f55b434dbdc00edb570ed7a7c6fcce8bb272a"
1805 | },
1806 | "dist": {
1807 | "type": "zip",
1808 | "url": "https://api.github.com/repos/symfony/var-dumper/zipball/967f55b434dbdc00edb570ed7a7c6fcce8bb272a",
1809 | "reference": "967f55b434dbdc00edb570ed7a7c6fcce8bb272a",
1810 | "shasum": ""
1811 | },
1812 | "require": {
1813 | "php": ">=8.1",
1814 | "symfony/polyfill-mbstring": "~1.0"
1815 | },
1816 | "conflict": {
1817 | "phpunit/phpunit": "<5.4.3",
1818 | "symfony/console": "<5.4"
1819 | },
1820 | "require-dev": {
1821 | "ext-iconv": "*",
1822 | "symfony/console": "^5.4|^6.0",
1823 | "symfony/process": "^5.4|^6.0",
1824 | "symfony/uid": "^5.4|^6.0",
1825 | "twig/twig": "^2.13|^3.0.4"
1826 | },
1827 | "suggest": {
1828 | "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
1829 | "ext-intl": "To show region name in time zone dump",
1830 | "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
1831 | },
1832 | "bin": [
1833 | "Resources/bin/var-dump-server"
1834 | ],
1835 | "type": "library",
1836 | "autoload": {
1837 | "files": [
1838 | "Resources/functions/dump.php"
1839 | ],
1840 | "psr-4": {
1841 | "Symfony\\Component\\VarDumper\\": ""
1842 | },
1843 | "exclude-from-classmap": [
1844 | "/Tests/"
1845 | ]
1846 | },
1847 | "notification-url": "https://packagist.org/downloads/",
1848 | "license": [
1849 | "MIT"
1850 | ],
1851 | "authors": [
1852 | {
1853 | "name": "Nicolas Grekas",
1854 | "email": "p@tchwork.com"
1855 | },
1856 | {
1857 | "name": "Symfony Community",
1858 | "homepage": "https://symfony.com/contributors"
1859 | }
1860 | ],
1861 | "description": "Provides mechanisms for walking through any arbitrary PHP variable",
1862 | "homepage": "https://symfony.com",
1863 | "keywords": [
1864 | "debug",
1865 | "dump"
1866 | ],
1867 | "support": {
1868 | "source": "https://github.com/symfony/var-dumper/tree/6.3"
1869 | },
1870 | "funding": [
1871 | {
1872 | "url": "https://symfony.com/sponsor",
1873 | "type": "custom"
1874 | },
1875 | {
1876 | "url": "https://github.com/fabpot",
1877 | "type": "github"
1878 | },
1879 | {
1880 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
1881 | "type": "tidelift"
1882 | }
1883 | ],
1884 | "time": "2023-01-26T14:58:07+00:00"
1885 | },
1886 | {
1887 | "name": "theseer/tokenizer",
1888 | "version": "1.2.1",
1889 | "source": {
1890 | "type": "git",
1891 | "url": "https://github.com/theseer/tokenizer.git",
1892 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
1893 | },
1894 | "dist": {
1895 | "type": "zip",
1896 | "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
1897 | "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
1898 | "shasum": ""
1899 | },
1900 | "require": {
1901 | "ext-dom": "*",
1902 | "ext-tokenizer": "*",
1903 | "ext-xmlwriter": "*",
1904 | "php": "^7.2 || ^8.0"
1905 | },
1906 | "type": "library",
1907 | "autoload": {
1908 | "classmap": [
1909 | "src/"
1910 | ]
1911 | },
1912 | "notification-url": "https://packagist.org/downloads/",
1913 | "license": [
1914 | "BSD-3-Clause"
1915 | ],
1916 | "authors": [
1917 | {
1918 | "name": "Arne Blankerts",
1919 | "email": "arne@blankerts.de",
1920 | "role": "Developer"
1921 | }
1922 | ],
1923 | "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
1924 | "support": {
1925 | "issues": "https://github.com/theseer/tokenizer/issues",
1926 | "source": "https://github.com/theseer/tokenizer/tree/1.2.1"
1927 | },
1928 | "funding": [
1929 | {
1930 | "url": "https://github.com/theseer",
1931 | "type": "github"
1932 | }
1933 | ],
1934 | "time": "2021-07-28T10:34:58+00:00"
1935 | }
1936 | ],
1937 | "aliases": [],
1938 | "minimum-stability": "dev",
1939 | "stability-flags": {
1940 | "nikic/fast-route": 20,
1941 | "psr/container": 20,
1942 | "symfony/var-dumper": 20,
1943 | "phpunit/phpunit": 20
1944 | },
1945 | "prefer-stable": false,
1946 | "prefer-lowest": false,
1947 | "platform": [],
1948 | "platform-dev": [],
1949 | "plugin-api-version": "2.3.0"
1950 | }
1951 |
--------------------------------------------------------------------------------
/framework/src/Authentication/AuthRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | authRepository->findByUsername($username);
23 |
24 | if (!$user) {
25 | return false;
26 | }
27 |
28 | // Does the hashed user pw match the hash of the attempted password
29 | if (!password_verify($password, $user->getPassword())) {
30 |
31 | return false;
32 | }
33 |
34 | $this->login($user);
35 |
36 | return true;
37 | }
38 |
39 | public function login(AuthUserInterface $user)
40 | {
41 | // Start a session
42 | $this->session->start();
43 |
44 | // Log the user in
45 | $this->session->set(Session::AUTH_KEY, $user->getAuthId());
46 |
47 | // Set the user
48 | $this->user = $user;
49 | }
50 |
51 | public function logout()
52 | {
53 | $this->session->remove(Session::AUTH_KEY);
54 | }
55 |
56 | public function getUser(): AuthUserInterface
57 | {
58 | return $this->user;
59 | }
60 |
61 | }
--------------------------------------------------------------------------------
/framework/src/Console/Application.php:
--------------------------------------------------------------------------------
1 | container->get($commandName);
26 |
27 | // Parse variables to obtain options and args
28 | $args = array_slice($argv, 2);
29 |
30 | $options = $this->parseOptions($args);
31 |
32 | // Execute the command, returning the status code
33 | $status = $command->execute($options);
34 |
35 | // Return the status code
36 | return $status;
37 | }
38 |
39 | private function parseOptions(array $args): array
40 | {
41 | $options = [];
42 |
43 | foreach ($args as $arg) {
44 | if (str_starts_with($arg, '--')) {
45 | // This is an option
46 | $option = explode('=', substr($arg, 2));
47 | $options[$option[0]] = $option[1] ?? true;
48 |
49 | }
50 | }
51 |
52 | return $options;
53 | }
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | }
--------------------------------------------------------------------------------
/framework/src/Console/Command/CommandInterface.php:
--------------------------------------------------------------------------------
1 | createMigrationsTable();
26 |
27 | $this->connection->beginTransaction();
28 |
29 | // Get $appliedMigrations which are already in the database.migrations table
30 | $appliedMigrations = $this->getAppliedMigrations();
31 |
32 | // Get the $migrationFiles from the migrations folder
33 | $migrationFiles = $this->getMigrationFiles();
34 |
35 | // Get the migrations to apply. i.e. they are in $migrationFiles but not in $appliedMigrations
36 | $migrationsToApply = array_diff($migrationFiles, $appliedMigrations);
37 |
38 | $schema = new Schema();
39 |
40 | // Create SQL for any migrations which have not been run ..i.e. which are not in the database
41 | foreach ($migrationsToApply as $migration) {
42 |
43 | // require the object
44 | $migrationObject = require $this->migrationsPath . '/' . $migration;
45 |
46 | // call up method
47 | $migrationObject->up($schema);
48 |
49 | // Add migration to database
50 | $this->insertMigration($migration);
51 | }
52 |
53 | // Execute the SQL query
54 | $sqlArray = $schema->toSql($this->connection->getDatabasePlatform());
55 |
56 | foreach ($sqlArray as $sql) {
57 | $this->connection->executeQuery($sql);
58 | }
59 |
60 | $this->connection->commit();
61 |
62 | return 0;
63 |
64 | } catch (\Throwable $throwable) {
65 |
66 | $this->connection->rollBack();
67 |
68 | throw $throwable;
69 | }
70 | }
71 |
72 | private function insertMigration(string $migration): void
73 | {
74 | $sql = "INSERT INTO migrations (migration) VALUES (?)";
75 |
76 | $stmt = $this->connection->prepare($sql);
77 |
78 | $stmt->bindValue(1, $migration);
79 |
80 | $stmt->executeStatement();
81 | }
82 |
83 | private function getMigrationFiles(): array
84 | {
85 | $migrationFiles = scandir($this->migrationsPath);
86 |
87 | $filteredFiles = array_filter($migrationFiles, function($file) {
88 | return !in_array($file, ['.', '..']);
89 | });
90 |
91 | return $filteredFiles;
92 | }
93 |
94 | private function getAppliedMigrations(): array
95 | {
96 | $sql = "SELECT migration FROM migrations;";
97 |
98 | $appliedMigrations = $this->connection->executeQuery($sql)->fetchFirstColumn();
99 |
100 | return $appliedMigrations;
101 | }
102 |
103 | private function createMigrationsTable(): void
104 | {
105 | $schemaManager = $this->connection->createSchemaManager();
106 |
107 | if (!$schemaManager->tablesExist('migrations')) {
108 | $schema = new Schema();
109 | $table = $schema->createTable('migrations');
110 | $table->addColumn('id', Types::INTEGER, ['unsigned' => true, 'autoincrement' => true]);
111 | $table->addColumn('migration', Types::STRING);
112 | $table->addColumn('created_at', Types::DATETIME_IMMUTABLE, ['default' => 'CURRENT_TIMESTAMP']);
113 | $table->setPrimaryKey(['id']);
114 |
115 | $sqlArray = $schema->toSql($this->connection->getDatabasePlatform());
116 |
117 | $this->connection->executeQuery($sqlArray[0]);
118 |
119 | echo 'migrations table created' . PHP_EOL;
120 | }
121 | }
122 | }
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/framework/src/Console/ConsoleException.php:
--------------------------------------------------------------------------------
1 | registerCommands();
21 |
22 | // Run the console application, returning a status code
23 | $status = $this->application->run();
24 |
25 | // return the status code
26 | return $status;
27 | }
28 |
29 | private function registerCommands(): void
30 | {
31 | // === Register All Built In Commands ===
32 | // Get all files in the Commands dir
33 | $commandFiles = new \DirectoryIterator(__DIR__ . '/Command');
34 |
35 | $namespace = $this->container->get('base-commands-namespace');
36 |
37 | // Loop over all files in the commands folder
38 | foreach ($commandFiles as $commandFile) {
39 |
40 | if (!$commandFile->isFile()) {
41 | continue;
42 | }
43 |
44 | // Get the Command class name..using psr4 this will be same as filename
45 | $command = $namespace.pathinfo($commandFile, PATHINFO_FILENAME);
46 |
47 | // If it is a subclass of CommandInterface
48 | if (is_subclass_of($command, CommandInterface::class)) {
49 | // Add to the container, using the name as the ID e.g. $container->add('database:migrations:migrate', MigrateDatabase::class)
50 | $commandName = (new \ReflectionClass($command))->getProperty('name')->getDefaultValue();
51 |
52 | $this->container->add($commandName, $command);
53 | }
54 | }
55 |
56 | // === Register all user-defined commands (@todo) ===
57 | }
58 | }
--------------------------------------------------------------------------------
/framework/src/Container/Container.php:
--------------------------------------------------------------------------------
1 | services[$id] = $concrete;
25 | }
26 |
27 | public function get(string $id)
28 | {
29 | if (!$this->has($id)) {
30 | if (!class_exists($id)) {
31 | throw new ContainerException("Service $id could not be resolved");
32 | }
33 |
34 | $this->add($id);
35 | }
36 |
37 | $object = $this->resolve($this->services[$id]);
38 |
39 | return $object;
40 | }
41 |
42 | private function resolve($class): object
43 | {
44 | // 1. Instantiate a Reflection class (dump and check)
45 | $reflectionClass = new \ReflectionClass($class);
46 |
47 | // 2. Use Reflection to try to obtain a class constructor
48 | $constructor = $reflectionClass->getConstructor();
49 |
50 | // 3. If there is no constructor, simply instantiate
51 | if (null === $constructor) {
52 | return $reflectionClass->newInstance();
53 | }
54 |
55 | // 4. Get the constructor parameters
56 | $constructorParams = $constructor->getParameters();
57 |
58 | // 5. Obtain dependencies
59 | $classDependencies = $this->resolveClassDependencies($constructorParams);
60 |
61 | // 6. Instantiate with dependencies
62 | $service = $reflectionClass->newInstanceArgs($classDependencies);
63 |
64 | // 7. Return the object
65 | return $service;
66 | }
67 |
68 | private function resolveClassDependencies(array $reflectionParameters): array
69 | {
70 | // 1. Initialize empty dependencies array (required by newInstanceArgs)
71 | $classDependencies = [];
72 |
73 | // 2. Try to locate and instantiate each parameter
74 | /** @var \ReflectionParameter $parameter */
75 | foreach ($reflectionParameters as $parameter) {
76 |
77 | // Get the parameter's ReflectionNamedType as $serviceType
78 | $serviceType = $parameter->getType();
79 |
80 | // Try to instantiate using $serviceType's name
81 | $service = $this->get($serviceType->getName());
82 |
83 | // Add the service to the classDependencies array
84 | $classDependencies[] = $service;
85 | }
86 |
87 | // 3. Return the classDependencies array
88 | return $classDependencies;
89 | }
90 |
91 | public function has(string $id): bool
92 | {
93 | return array_key_exists($id, $this->services);
94 | }
95 | }
--------------------------------------------------------------------------------
/framework/src/Container/ContainerException.php:
--------------------------------------------------------------------------------
1 | container = $container;
17 | }
18 |
19 | public function setRequest(Request $request): void
20 | {
21 | $this->request = $request;
22 | }
23 |
24 | public function render(string $template, array $parameters = [], Response $response = null): Response
25 | {
26 | $content = $this->container->get('twig')->render($template, $parameters);
27 |
28 | $response ??= new Response();
29 |
30 | $response->setContent($content);
31 |
32 | return $response;
33 | }
34 | }
--------------------------------------------------------------------------------
/framework/src/Dbal/ConnectionFactory.php:
--------------------------------------------------------------------------------
1 | $this->databaseUrl]);
17 | }
18 | }
--------------------------------------------------------------------------------
/framework/src/Dbal/DataMapper.php:
--------------------------------------------------------------------------------
1 | connection;
21 | }
22 |
23 | public function save(Entity $subject): int|string|null
24 | {
25 | // Dispatch PostPersist event
26 | $this->eventDispatcher->dispatch(new PostPersist($subject));
27 |
28 | // Return lastInsertId
29 | return $this->connection->lastInsertId();
30 | }
31 | }
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/framework/src/Dbal/Entity.php:
--------------------------------------------------------------------------------
1 | propagationStopped;
14 | }
15 |
16 | public function stopPropagation(): void
17 | {
18 | $this->propagationStopped = true;
19 | }
20 | }
--------------------------------------------------------------------------------
/framework/src/EventDispatcher/EventDispatcher.php:
--------------------------------------------------------------------------------
1 | getListenersForEvent($event) as $listener) {
16 | // Break if propagation stopped
17 | if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
18 | return $event;
19 | }
20 |
21 | // Call the listener, passing in the event (each listener will be a callable)
22 | $listener($event);
23 | }
24 |
25 | return $event;
26 | }
27 |
28 | // $eventName e.g. Framework\EventDispatcher\ResponseEvent
29 | public function addListener(string $eventName, callable $listener): self
30 | {
31 | $this->listeners[$eventName][] = $listener;
32 |
33 | return $this;
34 | }
35 |
36 | /**
37 | * @param object $event
38 | * An event for which to return the relevant listeners.
39 | * @return iterable
40 | * An iterable (array, iterator, or generator) of callables. Each
41 | * callable MUST be type-compatible with $event.
42 | */
43 | public function getListenersForEvent(object $event) : iterable
44 | {
45 | $eventName = get_class($event);
46 |
47 | if (array_key_exists($eventName, $this->listeners)) {
48 | return $this->listeners[$eventName];
49 | }
50 |
51 | return [];
52 | }
53 | }
--------------------------------------------------------------------------------
/framework/src/Http/Event/ResponseEvent.php:
--------------------------------------------------------------------------------
1 | request;
21 | }
22 |
23 | public function getResponse(): Response
24 | {
25 | return $this->response;
26 | }
27 | }
--------------------------------------------------------------------------------
/framework/src/Http/HttpException.php:
--------------------------------------------------------------------------------
1 | statusCode;
12 | }
13 |
14 | public function setStatusCode(int $statusCode): void
15 | {
16 | $this->statusCode = $statusCode;
17 | }
18 | }
--------------------------------------------------------------------------------
/framework/src/Http/HttpRequestMethodException.php:
--------------------------------------------------------------------------------
1 | appEnv = $this->container->get('APP_ENV');
24 | }
25 |
26 | public function handle(Request $request): Response
27 | {
28 | try {
29 |
30 | $response = $this->requestHandler->handle($request);
31 |
32 | } catch (\Exception $exception) {
33 | $response = $this->createExceptionResponse($exception);
34 | }
35 |
36 | $this->eventDispatcher->dispatch(new ResponseEvent($request, $response));
37 |
38 | return $response;
39 | }
40 |
41 | /**
42 | * @throws \Exception $exception
43 | */
44 | private function createExceptionResponse(\Exception $exception): Response
45 | {
46 | if (in_array($this->appEnv, ['dev', 'test'])) {
47 | throw $exception;
48 | }
49 |
50 | if ($exception instanceof HttpException) {
51 | return new Response($exception->getMessage(), $exception->getStatusCode());
52 | }
53 |
54 | return new Response('Server error', Response::HTTP_INTERNAL_SERVER_ERROR);
55 | }
56 |
57 | public function terminate(Request $request, Response $response): void
58 | {
59 | $request->getSession()?->clearFlash();
60 | }
61 | }
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/Authenticate.php:
--------------------------------------------------------------------------------
1 | session->start();
21 |
22 | if (!$this->session->has(Session::AUTH_KEY)) {
23 | $this->session->setFlash('error', 'Please sign in');
24 | return new RedirectResponse('/login');
25 | }
26 |
27 | return $requestHandler->handle($request);
28 | }
29 | }
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/Dummy.php:
--------------------------------------------------------------------------------
1 | handle($request);
13 | }
14 | }
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/ExtractRouteInfo.php:
--------------------------------------------------------------------------------
1 | routes as $route) {
25 | $routeCollector->addRoute(...$route);
26 | }
27 | });
28 |
29 | // Dispatch a URI, to obtain the route info
30 | $routeInfo = $dispatcher->dispatch(
31 | $request->getMethod(),
32 | $request->getPathInfo()
33 | );
34 |
35 | switch ($routeInfo[0]) {
36 | case Dispatcher::FOUND:
37 | // Set $request->routeHandler
38 | $request->setRouteHandler($routeInfo[1]);
39 | // Set $request->routeHandlerArgs
40 | $request->setRouteHandlerArgs($routeInfo[2]);
41 | // Inject route middleware on handler
42 | if (is_array($routeInfo[1]) && isset($routeInfo[1][2])) {
43 | $requestHandler->injectMiddleware($routeInfo[1][2]);
44 | }
45 | break;
46 | case Dispatcher::METHOD_NOT_ALLOWED:
47 | $allowedMethods = implode(', ', $routeInfo[1]);
48 | $e = new HttpRequestMethodException("The allowed methods are $allowedMethods");
49 | $e->setStatusCode(405);
50 | throw $e;
51 | default:
52 | $e = new HttpException('Not found');
53 | $e->setStatusCode(404);
54 | throw $e;
55 | }
56 |
57 | return $requestHandler->handle($request);
58 | }
59 | }
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/Guest.php:
--------------------------------------------------------------------------------
1 | session->start();
21 |
22 | if ($this->session->has(Session::AUTH_KEY)) {
23 | return new RedirectResponse('/dashboard');
24 | }
25 |
26 | return $requestHandler->handle($request);
27 | }
28 | }
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/MiddlewareInterface.php:
--------------------------------------------------------------------------------
1 | middleware)) {
27 | return new Response("It's totally borked, mate. Contact support", 500);
28 | }
29 |
30 | // Get the next middleware class to execute
31 | $middlewareClass = array_shift($this->middleware);
32 |
33 | $middleware = $this->container->get($middlewareClass);
34 |
35 | // Create a new instance of the middleware call process on it
36 | $response = $middleware->process($request, $this);
37 |
38 | return $response;
39 | }
40 |
41 | public function injectMiddleware(array $middleware): void
42 | {
43 | array_splice($this->middleware, 0, 0, $middleware);
44 | }
45 | }
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/RequestHandlerInterface.php:
--------------------------------------------------------------------------------
1 | router->dispatch($request, $this->container);
22 |
23 | $response = call_user_func_array($routeHandler, $vars);
24 |
25 | return $response;
26 | }
27 | }
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/StartSession.php:
--------------------------------------------------------------------------------
1 | getPathInfo(), $this->apiPrefix)) {
21 | $this->session->start();
22 |
23 | $request->setSession($this->session);
24 | }
25 |
26 | return $requestHandler->handle($request);
27 | }
28 | }
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/framework/src/Http/Middleware/Success.php:
--------------------------------------------------------------------------------
1 | $url]);
10 | }
11 |
12 | public function send(): void
13 | {
14 | header('Location: ' . $this->getHeader('location'), true, $this->getStatus());
15 | exit;
16 | }
17 | }
--------------------------------------------------------------------------------
/framework/src/Http/Request.php:
--------------------------------------------------------------------------------
1 | server['REQUEST_URI'], '?');
31 | }
32 |
33 | public function getMethod(): string
34 | {
35 | return $this->server['REQUEST_METHOD'];
36 | }
37 |
38 | public function getSession(): SessionInterface
39 | {
40 | return $this->session;
41 | }
42 |
43 | public function setSession(SessionInterface $session): void
44 | {
45 | $this->session = $session;
46 | }
47 |
48 | public function input($key): mixed
49 | {
50 | return $this->postParams[$key];
51 | }
52 |
53 | public function getRouteHandler(): mixed
54 | {
55 | return $this->routeHandler;
56 | }
57 |
58 | public function setRouteHandler(mixed $routeHandler): void
59 | {
60 | $this->routeHandler = $routeHandler;
61 | }
62 |
63 | public function getRouteHandlerArgs(): array
64 | {
65 | return $this->routeHandlerArgs;
66 | }
67 |
68 | public function setRouteHandlerArgs(array $routeHandlerArgs): void
69 | {
70 | $this->routeHandlerArgs = $routeHandlerArgs;
71 | }
72 | }
--------------------------------------------------------------------------------
/framework/src/Http/Response.php:
--------------------------------------------------------------------------------
1 | status);
18 | }
19 |
20 | public function send(): void
21 | {
22 | // start output buffering
23 | ob_start();
24 |
25 | // send headers
26 | foreach ($this->headers as $key => $value) {
27 | header("$key: $value");
28 | }
29 |
30 | // This will actually add the content to the buffer
31 | echo $this->content;
32 |
33 | // Flush the buffer, sending the content to the client
34 | ob_end_flush();
35 | }
36 |
37 | public function setContent(?string $content): void
38 | {
39 | $this->content = $content;
40 | }
41 |
42 | public function getStatus(): int
43 | {
44 | return $this->status;
45 | }
46 |
47 | public function setStatus(int $status): void
48 | {
49 | $this->status = $status;
50 | }
51 |
52 | public function getHeader(string $header): mixed
53 | {
54 | return $this->headers[$header];
55 | }
56 |
57 | public function getHeaders(): array
58 | {
59 | return $this->headers;
60 | }
61 |
62 | public function setHeader($key, $value): void
63 | {
64 | $this->headers[$key] = $value;
65 | }
66 |
67 | public function getContent(): ?string
68 | {
69 | return $this->content;
70 | }
71 | }
--------------------------------------------------------------------------------
/framework/src/Routing/Router.php:
--------------------------------------------------------------------------------
1 | extractRouteInfo($request);
21 |
22 | [$handler, $vars] = $routeInfo;
23 |
24 | if (is_array($handler)) {
25 | [$controllerId, $method] = $handler;
26 | $controller = $container->get($controllerId);
27 | if (is_subclass_of($controller, AbstractController::class)) {
28 | $controller->setRequest($request);
29 | }
30 | $handler = [$controller, $method];
31 | }
32 |
33 | return [$handler, $vars];
34 | }
35 |
36 | public function setRoutes(array $routes): void
37 | {
38 | $this->routes = $routes;
39 | }
40 |
41 | private function extractRouteInfo(Request $request): array
42 | {
43 | // Create a dispatcher
44 | $dispatcher = simpleDispatcher(function (RouteCollector $routeCollector) {
45 |
46 | foreach ($this->routes as $route) {
47 | $routeCollector->addRoute(...$route);
48 | }
49 | });
50 |
51 | // Dispatch a URI, to obtain the route info
52 | $routeInfo = $dispatcher->dispatch(
53 | $request->getMethod(),
54 | $request->getPathInfo()
55 | );
56 |
57 | switch ($routeInfo[0]) {
58 | case Dispatcher::FOUND:
59 | return [$routeInfo[1], $routeInfo[2]]; // routeHandler, vars
60 | case Dispatcher::METHOD_NOT_ALLOWED:
61 | $allowedMethods = implode(', ', $routeInfo[1]);
62 | $e = new HttpRequestMethodException("The allowed methods are $allowedMethods");
63 | $e->setStatusCode(405);
64 | throw $e;
65 | default:
66 | $e = new HttpException('Not found');
67 | $e->setStatusCode(404);
68 | throw $e;
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/framework/src/Routing/RouterInterface.php:
--------------------------------------------------------------------------------
1 | get(self::FLASH_KEY) ?? [];
40 | if (isset($flash[$type])) {
41 | $messages = $flash[$type];
42 | unset($flash[$type]);
43 | $this->set(self::FLASH_KEY, $flash);
44 | return $messages;
45 | }
46 |
47 | return [];
48 | }
49 |
50 | public function setFlash(string $type, string $message): void
51 | {
52 | $flash = $this->get(self::FLASH_KEY) ?? [];
53 | $flash[$type][] = $message;
54 | $this->set(self::FLASH_KEY, $flash);
55 | }
56 |
57 | public function hasFlash(string $type): bool
58 | {
59 | return isset($_SESSION[self::FLASH_KEY][$type]);
60 | }
61 |
62 | public function clearFlash(): void
63 | {
64 | unset($_SESSION[self::FLASH_KEY]);
65 | }
66 |
67 | public function isAuthenticated(): bool
68 | {
69 | return $this->has(self::AUTH_KEY);
70 | }
71 | }
--------------------------------------------------------------------------------
/framework/src/Session/SessionInterface.php:
--------------------------------------------------------------------------------
1 | templatesPath);
24 |
25 | // instantiate Twig Environment with loader
26 | $twig = new Environment($loader, [
27 | 'debug' => true,
28 | 'cache' => false,
29 | ]);
30 |
31 | // add new twig session() function to Environment
32 | $twig->addExtension(new DebugExtension());
33 | $twig->addFunction(new TwigFunction('session', [$this, 'getSession']));
34 |
35 | return $twig;
36 | }
37 |
38 | public function getSession(): SessionInterface
39 | {
40 | return $this->session;
41 | }
42 | }
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/framework/tests/ContainerTest.php:
--------------------------------------------------------------------------------
1 | add('dependant-class', DependantClass::class);
20 |
21 | // Make assertions
22 | $this->assertInstanceOf(DependantClass::class, $container->get('dependant-class'));
23 | }
24 |
25 | /** @test */
26 | public function a_ContainerException_is_thrown_if_a_service_cannot_be_found()
27 | {
28 | // Setup
29 | $container = new Container();
30 |
31 | // Expect exception
32 | $this->expectException(ContainerException::class);
33 |
34 | // Do something
35 | $container->add('foobar');
36 | }
37 |
38 | /** @test */
39 | public function can_check_if_the_container_has_a_service(): void
40 | {
41 | // Setup
42 | $container = new Container();
43 |
44 | // Do something
45 | $container->add('dependant-class', DependantClass::class);
46 |
47 | $this->assertTrue($container->has('dependant-class'));
48 | $this->assertFalse($container->has('non-existent-class'));
49 | }
50 |
51 | /** @test */
52 | public function services_can_be_recursively_autowired()
53 | {
54 | $container = new Container();
55 |
56 | $dependantService = $container->get(DependantClass::class);
57 |
58 | $dependancyService = $dependantService->getDependency();
59 |
60 | $this->assertInstanceOf(DependencyClass::class, $dependancyService);
61 | $this->assertInstanceOf(SubDependencyClass::class, $dependancyService->getSubDependency());
62 | }
63 | }
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/framework/tests/DependantClass.php:
--------------------------------------------------------------------------------
1 | dependency;
14 | }
15 | }
--------------------------------------------------------------------------------
/framework/tests/DependencyClass.php:
--------------------------------------------------------------------------------
1 | subDependency;
14 | }
15 | }
--------------------------------------------------------------------------------
/framework/tests/SessionTest.php:
--------------------------------------------------------------------------------
1 | setFlash('success', 'Great job!');
19 | $session->setFlash('error', 'Bad job!');
20 | $this->assertTrue($session->hasFlash('success'));
21 | $this->assertTrue($session->hasFlash('error'));
22 | $this->assertEquals(['Great job!'], $session->getFlash('success'));
23 | $this->assertEquals(['Bad job!'], $session->getFlash('error'));
24 | $this->assertEquals([], $session->getFlash('warning'));
25 | }
26 | }
--------------------------------------------------------------------------------
/framework/tests/SubDependencyClass.php:
--------------------------------------------------------------------------------
1 | createTable('posts');
11 | $table->addColumn('id', Types::INTEGER, ['autoincrement' => true, 'unsigned' => true]);
12 | $table->addColumn('title', Types::STRING, ['length' => 255]);
13 | $table->addColumn('body', Types::TEXT);
14 | $table->addColumn('created_at', Types::DATETIME_IMMUTABLE, ['default' => 'CURRENT_TIMESTAMP']);
15 | $table->setPrimaryKey(['id']);
16 | }
17 |
18 | public function down(): void
19 | {
20 | // Table drop / modification code goes here
21 |
22 | echo get_class($this) . ' "down" method called' . PHP_EOL;
23 | }
24 | };
25 |
26 |
--------------------------------------------------------------------------------
/migrations/20230407133000.php:
--------------------------------------------------------------------------------
1 | createTable('users');
11 | $table->addColumn('id', Types::INTEGER, ['autoincrement' => true, 'unsigned' => true]);
12 | $table->addColumn('username', Types::STRING, ['length' => 255]);
13 | $table->addColumn('password', Types::STRING, ['length' => 60]);
14 | $table->addColumn('created_at', Types::DATETIME_IMMUTABLE, ['default' => 'CURRENT_TIMESTAMP']);
15 | $table->setPrimaryKey(['id']);
16 | }
17 |
18 | public function down(Schema $schema): void
19 | {
20 | echo get_class($this) . ' "down" method called' . PHP_EOL;
21 | }
22 | };
23 |
24 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | get(Kernel::class);
20 |
21 | // send response (string of content)
22 | $response = $kernel->handle($request);
23 |
24 | $response->send();
25 |
26 | $kernel->terminate($request, $response);
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | render('dashboard.html.twig');
13 | }
14 | }
--------------------------------------------------------------------------------
/src/Controller/HomeController.php:
--------------------------------------------------------------------------------
1 | render('home.html.twig');
19 | }
20 | }
--------------------------------------------------------------------------------
/src/Controller/LoginController.php:
--------------------------------------------------------------------------------
1 | render('login.html.twig');
19 | }
20 |
21 | public function login(): Response
22 | {
23 | // Attempt to authenticate the user using a security component (bool)
24 | // create a session for the user
25 | $userIsAuthenticated = $this->authComponent->authenticate(
26 | $this->request->input('username'),
27 | $this->request->input('password')
28 | );
29 |
30 | // If successful, retrieve the user
31 | if (!$userIsAuthenticated) {
32 | $this->request->getSession()->setFlash('error', 'Bad creds');
33 | return new RedirectResponse('/login');
34 | }
35 |
36 | $user = $this->authComponent->getUser();
37 |
38 | $this->request->getSession()->setFlash('success', 'You are now logged in');
39 |
40 | // Redirect the user to intended location
41 | return new RedirectResponse('/dashboard');
42 | }
43 |
44 | public function logout(): Response
45 | {
46 | // Log the user out
47 | $this->authComponent->logout();
48 |
49 | // Set a logout session message
50 | $this->request->getSession()->setFlash('success', 'Bye..see you soon!');
51 |
52 | // Redirect to login page
53 | return new RedirectResponse('/login');
54 | }
55 | }
--------------------------------------------------------------------------------
/src/Controller/PostsController.php:
--------------------------------------------------------------------------------
1 | postRepository->findOrFail($id);
26 |
27 | return $this->render('post.html.twig', [
28 | 'post' => $post
29 | ]);
30 | }
31 |
32 | public function create(): Response
33 | {
34 | return $this->render('create-post.html.twig');
35 | }
36 |
37 | public function store(): Response
38 | {
39 | $title = $this->request->postParams['title'];
40 | $body = $this->request->postParams['body'];
41 |
42 | $post = Post::create($title, $body);
43 |
44 | $this->postMapper->save($post);
45 |
46 | $this->request->getSession()->setFlash(
47 | 'success',
48 | sprintf('Post "%s" successfully created', $title)
49 | );
50 |
51 | return new RedirectResponse('/posts');
52 | }
53 | }
--------------------------------------------------------------------------------
/src/Controller/RegistrationController.php:
--------------------------------------------------------------------------------
1 | render('register.html.twig');
25 | }
26 |
27 | public function register(): Response
28 | {
29 | // Create a form model which will:
30 | // - validate fields
31 | // - map the fields to User object properties
32 | // - ultimately save the new User to the DB
33 | $form = new RegistrationForm($this->userMapper);
34 | $form->setFields(
35 | $this->request->input('username'),
36 | $this->request->input('password')
37 | );
38 |
39 | // Validate
40 | // If validation errors,
41 | if ($form->hasValidationErrors()) {
42 | // add to session, redirect to form
43 | foreach ($form->getValidationErrors() as $error) {
44 | $this->request->getSession()->setFlash('error', $error);
45 | }
46 | return new RedirectResponse('/register');
47 | }
48 |
49 | // register the user by calling $form->save()
50 | $user = $form->save();
51 |
52 | // Add a session success message
53 | $this->request->getSession()->setFlash(
54 | 'success',
55 | sprintf('User %s created', $user->getUsername())
56 | );
57 |
58 | // Log the user in
59 | $this->authComponent->login($user);
60 |
61 | // Redirect to somewhere useful
62 | return new RedirectResponse('/dashboard');
63 | }
64 | }
--------------------------------------------------------------------------------
/src/Entity/Post.php:
--------------------------------------------------------------------------------
1 | id;
31 | }
32 |
33 | public function setId(?int $id): void
34 | {
35 | $this->id = $id;
36 | }
37 |
38 | public function getTitle(): string
39 | {
40 | return $this->title;
41 | }
42 |
43 | public function setTitle(string $title): void
44 | {
45 | $this->title = $title;
46 | }
47 |
48 | public function getBody(): string
49 | {
50 | return $this->body;
51 | }
52 |
53 | public function setBody(string $body): void
54 | {
55 | $this->body = $body;
56 | }
57 |
58 | public function getCreatedAt(): \DateTimeImmutable
59 | {
60 | return $this->createdAt;
61 | }
62 |
63 | public function setCreatedAt(\DateTimeImmutable $createdAt): void
64 | {
65 | $this->createdAt = $createdAt;
66 | }
67 | }
--------------------------------------------------------------------------------
/src/Entity/User.php:
--------------------------------------------------------------------------------
1 | id = $id;
32 | }
33 |
34 | public function getAuthId(): int
35 | {
36 | return $this->id;
37 | }
38 |
39 | public function getUsername(): string
40 | {
41 | return $this->username;
42 | }
43 |
44 | public function getPassword(): string
45 | {
46 | return $this->password;
47 | }
48 |
49 | public function getCreatedAt(): \DateTimeImmutable
50 | {
51 | return $this->createdAt;
52 | }
53 | }
--------------------------------------------------------------------------------
/src/EventListener/ContentLengthListener.php:
--------------------------------------------------------------------------------
1 | getResponse();
12 |
13 | if (!array_key_exists('Content-Length', $response->getHeaders())) {
14 | $response->setHeader('Content-Length', strlen($response->getContent()));
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/EventListener/InternalErrorListener.php:
--------------------------------------------------------------------------------
1 | getResponse()->getStatus();
14 |
15 | if ($status > self::INTERNAL_ERROR_MIN_VALUE) {
16 | $event->stopPropagation();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/Form/User/RegistrationForm.php:
--------------------------------------------------------------------------------
1 | username = $username;
21 | $this->password = $password;
22 | }
23 |
24 | public function save(): User
25 | {
26 | $user = User::create($this->username, $this->password);
27 |
28 | $this->userMapper->save($user);
29 |
30 | return $user;
31 | }
32 |
33 | public function hasValidationErrors(): bool
34 | {
35 | return count($this->getValidationErrors()) > 0;
36 | }
37 |
38 | public function getValidationErrors(): array
39 | {
40 | if (!empty($this->errors)) {
41 | return $this->errors;
42 | }
43 |
44 | // username length
45 | if (strlen($this->username) < 5 || strlen($this->username) > 20) {
46 | $this->errors[] = 'Username must be between 5 and 20 characters';
47 | }
48 |
49 | // username char type
50 | if (!preg_match('/^\w+$/', $this->username)) {
51 | $this->errors[] = 'Username can only consist of word characters without spaces';
52 | }
53 |
54 | // password length
55 | if (strlen($this->password) < 8) {
56 | $this->errors[] = 'Password must be at least 8 characters';
57 | }
58 |
59 | return $this->errors;
60 | }
61 | }
--------------------------------------------------------------------------------
/src/Provider/EventServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
16 | InternalErrorListener::class,
17 | ContentLengthListener::class
18 | ],
19 | PostPersist::class => [
20 | ]
21 | ];
22 |
23 | public function __construct(private EventDispatcher $eventDispatcher)
24 | {
25 | }
26 |
27 | public function register(): void
28 | {
29 | // loop over each event in the listen array
30 | foreach ($this->listen as $eventName => $listeners) {
31 | // loop over each listener
32 | foreach (array_unique($listeners) as $listener) {
33 | // call eventDispatcher->addListener
34 | $this->eventDispatcher->addListener($eventName, new $listener());
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/Repository/PostMapper.php:
--------------------------------------------------------------------------------
1 | dataMapper->getConnection()->prepare("
18 | INSERT INTO posts (title, body, created_at)
19 | VALUES (:title, :body, :created_at)
20 | ");
21 |
22 | $stmt->bindValue(':title', $post->getTitle());
23 | $stmt->bindValue(':body', $post->getBody());
24 | $stmt->bindValue(':created_at', $post->getCreatedAt()->format('Y-m-d H:i:s'));
25 |
26 | $stmt->executeStatement();
27 |
28 | $id = $this->dataMapper->save($post);
29 |
30 | $post->setId($id);
31 | }
32 | }
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/Repository/PostRepository.php:
--------------------------------------------------------------------------------
1 | connection->createQueryBuilder();
18 |
19 | $queryBuilder
20 | ->select('id', 'title', 'body', 'created_at')
21 | ->from('posts')
22 | ->where('id = :id')
23 | ->setParameter('id', $id);
24 |
25 | $result = $queryBuilder->executeQuery();
26 |
27 | $row = $result->fetchAssociative();
28 |
29 | if (!$row) {
30 | return null;
31 | }
32 |
33 | $post = Post::create(
34 | id: $row['id'],
35 | title: $row['title'],
36 | body: $row['body'],
37 | createdAt: new \DateTimeImmutable($row['created_at'])
38 | );
39 |
40 | return $post;
41 | }
42 |
43 | public function findOrFail(int $id): Post
44 | {
45 | $post = $this->findById($id);
46 |
47 | if (!$post) {
48 | throw new NotFoundException(sprintf('Post with ID %d not found', $id));
49 | }
50 |
51 | return $post;
52 | }
53 | }
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/src/Repository/UserMapper.php:
--------------------------------------------------------------------------------
1 | dataMapper->getConnection()->prepare("
18 | INSERT INTO users (username, password, created_at)
19 | VALUES (:username, :password, :created_at)
20 | ");
21 |
22 | $stmt->bindValue(':username', $user->getUsername());
23 | $stmt->bindValue(':password', $user->getPassword());
24 | $stmt->bindValue(':created_at', $user->getCreatedAt()->format('Y-m-d H:i:s'));
25 |
26 | $stmt->executeStatement();
27 |
28 | $id = $this->dataMapper->save($user);
29 |
30 | $user->setId($id);
31 | }
32 | }
--------------------------------------------------------------------------------
/src/Repository/UserRepository.php:
--------------------------------------------------------------------------------
1 | connection->createQueryBuilder();
20 |
21 | $queryBuilder
22 | ->select('id', 'username', 'password', 'created_at')
23 | ->from('users')
24 | ->where('username = :username')
25 | ->setParameter('username', $username);
26 |
27 | $result = $queryBuilder->executeQuery();
28 |
29 | $row = $result->fetchAssociative();
30 |
31 | if (!$row) {
32 | return null;
33 | }
34 |
35 | $user = new User(
36 | id: $row['id'],
37 | username: $row['username'],
38 | password: $row['password'],
39 | createdAt: new \DateTimeImmutable($row['created_at'])
40 | );
41 |
42 | return $user;
43 | }
44 | }
--------------------------------------------------------------------------------
/src/Widget.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | PHP Framework PRO
8 |
9 |
10 |
11 |
69 |
70 |
71 |
72 |
73 |
83 |
84 |
85 | {% if session().hasFlash('success') %}
86 |
87 |
88 | {% for message in session().getFlash('success') %}
89 | - {{ message }}
90 | {% endfor %}
91 |
92 |
93 | {% endif %}
94 |
95 | {% if session().hasFlash('error') %}
96 |
97 |
98 | {% for message in session().getFlash('error') %}
99 | - {{ message }}
100 | {% endfor %}
101 |
102 |
103 | {% endif %}
104 |
105 |
106 | {% block main %} {% endblock %}
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/templates/create-post.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block main %}
4 |
16 | {% endblock %}
--------------------------------------------------------------------------------
/templates/dashboard.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 | {% block main %}
3 | Dashboard
4 | {% endblock %}
5 |
--------------------------------------------------------------------------------
/templates/home.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block main %}
4 | garyclarke.tech
5 | Welcome to garyclarke.tech. I hope you're learning lots of cool stuff!
6 | {% endblock %}
--------------------------------------------------------------------------------
/templates/login.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block main %}
4 |
5 | Login
6 |
7 |
18 |
19 | {% endblock %}
--------------------------------------------------------------------------------
/templates/post.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block main %}
4 | {{ post.title }}
5 | {{ post.body }}
6 | {% endblock %}
--------------------------------------------------------------------------------
/templates/register.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block main %}
4 |
5 | Register
6 |
7 |
18 |
19 | {% endblock %}
--------------------------------------------------------------------------------
/var/.gitignore:
--------------------------------------------------------------------------------
1 | db.sqlite
--------------------------------------------------------------------------------