├── README.md ├── db └── migrations │ └── 20160111202556_tickets_table.php └── src ├── .gitignore ├── classes ├── ComponentEntity.php ├── ComponentMapper.php ├── Mapper.php ├── TicketEntity.php └── TicketMapper.php ├── composer.json ├── composer.lock ├── composer.phar ├── phinx.yml ├── public └── index.php └── templates ├── 404.phtml ├── ticketadd.phtml ├── ticketdetail.phtml └── tickets.phtml /README.md: -------------------------------------------------------------------------------- 1 | # Slim Tutorial 2 | 3 | This is the companion source code for the Slim Framework [First Application Walkthrough][1] tutorial. 4 | 5 | It is a very simple Slim project to serve as an example application of using Slim 3 with Monolog, Phinx, PHP views and Composer to manage dependencies. In order to use the application as it stands: 6 | 7 | * change the shell working directory to `src` 8 | * run `php composer.phar install` to get the dependencies 9 | * create database to use 10 | * then run `php vendor/bin/phinx migrate` (or vendor\bin\phinx migrate on Windows 10) to get your database set up (the config is in `phinx.yml` so adjust as appropriate for your platform) 11 | * adjust `$config['db']` in `public/index.php` too 12 | * create `logs/app.log` and adjust permission as appropriate for your platform 13 | 14 | Patches to both tutorial and code are welcome. 15 | 16 | 17 | [1]: https://www.slimframework.com/docs/v3/tutorial/first-app.html 18 | -------------------------------------------------------------------------------- /db/migrations/20160111202556_tickets_table.php: -------------------------------------------------------------------------------- 1 | table('components'); 10 | $components_table->addColumn('component', 'string') 11 | ->create(); 12 | 13 | $components_table->insert([ 14 | ["component" => "website"], 15 | ["component" => "mobile app"] 16 | ]); 17 | $components_table->saveData(); 18 | 19 | $tickets_table = $this->table('tickets'); 20 | $tickets_table->addColumn('title', 'string') 21 | ->addColumn('description', 'text') 22 | ->addColumn('component_id', 'integer') 23 | ->addForeignKey('component_id', 'components', 'id') 24 | ->create(); 25 | 26 | } 27 | 28 | public function down() { 29 | $this->dropTable('tickets'); 30 | $this->dropTable('components'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | vendor/* 2 | logs/* 3 | -------------------------------------------------------------------------------- /src/classes/ComponentEntity.php: -------------------------------------------------------------------------------- 1 | id = $data['id']; 16 | $this->name = $data['component']; 17 | } 18 | 19 | public function getId() { 20 | return $this->id; 21 | } 22 | 23 | public function getName() { 24 | return $this->name; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/classes/ComponentMapper.php: -------------------------------------------------------------------------------- 1 | db->query($sql); 9 | 10 | $results = []; 11 | while($row = $stmt->fetch()) { 12 | $results[] = new ComponentEntity($row); 13 | } 14 | return $results; 15 | } 16 | 17 | public function getComponentById($id) { 18 | $sql = "SELECT id, component 19 | from components where id = :component_id"; 20 | $stmt = $this->db->prepare($sql); 21 | $stmt->execute(["component_id" => $id]); 22 | 23 | return new ComponentEntity($stmt->fetch()); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/classes/Mapper.php: -------------------------------------------------------------------------------- 1 | db = $db; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/classes/TicketEntity.php: -------------------------------------------------------------------------------- 1 | id = $data['id']; 20 | } 21 | 22 | $this->title = $data['title']; 23 | $this->description = $data['description']; 24 | $this->component = $data['component']; 25 | } 26 | 27 | public function getId() { 28 | return $this->id; 29 | } 30 | 31 | public function getTitle() { 32 | return $this->title; 33 | } 34 | 35 | public function getDescription() { 36 | return $this->description; 37 | } 38 | 39 | public function getShortDescription() { 40 | return substr($this->description, 0, 20); 41 | } 42 | 43 | public function getComponent() { 44 | return $this->component; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/classes/TicketMapper.php: -------------------------------------------------------------------------------- 1 | db->query($sql); 10 | 11 | $results = []; 12 | while($row = $stmt->fetch()) { 13 | $results[] = new TicketEntity($row); 14 | } 15 | return $results; 16 | } 17 | 18 | /** 19 | * Get one ticket by its ID 20 | * 21 | * @param int $ticket_id The ID of the ticket 22 | * @return TicketEntity The ticket 23 | */ 24 | public function getTicketById($ticket_id) { 25 | $sql = "SELECT t.id, t.title, t.description, c.component 26 | from tickets t 27 | join components c on (c.id = t.component_id) 28 | where t.id = :ticket_id"; 29 | $stmt = $this->db->prepare($sql); 30 | $result = $stmt->execute(["ticket_id" => $ticket_id]); 31 | 32 | if($result) { 33 | return new TicketEntity($stmt->fetch()); 34 | } 35 | 36 | } 37 | 38 | public function save(TicketEntity $ticket) { 39 | $sql = "insert into tickets 40 | (title, description, component_id) values 41 | (:title, :description, 42 | (select id from components where component = :component))"; 43 | 44 | $stmt = $this->db->prepare($sql); 45 | $result = $stmt->execute([ 46 | "title" => $ticket->getTitle(), 47 | "description" => $ticket->getDescription(), 48 | "component" => $ticket->getComponent(), 49 | ]); 50 | 51 | if(!$result) { 52 | throw new Exception("could not save record"); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "slim/slim": "^3.1", 4 | "slim/php-view": "^2.0", 5 | "monolog/monolog": "^1.17", 6 | "robmorgan/phinx": "^0.5.1" 7 | }, 8 | "autoload": { 9 | "psr-4": { 10 | "": "classes/" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/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#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "6157ca146536b8da6d7ac44d1f4a7566", 8 | "content-hash": "4244cd9b3b352dd29d0504282b7b0418", 9 | "packages": [ 10 | { 11 | "name": "container-interop/container-interop", 12 | "version": "1.1.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/container-interop/container-interop.git", 16 | "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", 21 | "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", 22 | "shasum": "" 23 | }, 24 | "type": "library", 25 | "autoload": { 26 | "psr-4": { 27 | "Interop\\Container\\": "src/Interop/Container/" 28 | } 29 | }, 30 | "notification-url": "https://packagist.org/downloads/", 31 | "license": [ 32 | "MIT" 33 | ], 34 | "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", 35 | "time": "2014-12-30 15:22:37" 36 | }, 37 | { 38 | "name": "monolog/monolog", 39 | "version": "1.21.0", 40 | "source": { 41 | "type": "git", 42 | "url": "https://github.com/Seldaek/monolog.git", 43 | "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952" 44 | }, 45 | "dist": { 46 | "type": "zip", 47 | "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952", 48 | "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952", 49 | "shasum": "" 50 | }, 51 | "require": { 52 | "php": ">=5.3.0", 53 | "psr/log": "~1.0" 54 | }, 55 | "provide": { 56 | "psr/log-implementation": "1.0.0" 57 | }, 58 | "require-dev": { 59 | "aws/aws-sdk-php": "^2.4.9", 60 | "doctrine/couchdb": "~1.0@dev", 61 | "graylog2/gelf-php": "~1.0", 62 | "jakub-onderka/php-parallel-lint": "0.9", 63 | "php-amqplib/php-amqplib": "~2.4", 64 | "php-console/php-console": "^3.1.3", 65 | "phpunit/phpunit": "~4.5", 66 | "phpunit/phpunit-mock-objects": "2.3.0", 67 | "ruflin/elastica": ">=0.90 <3.0", 68 | "sentry/sentry": "^0.13", 69 | "swiftmailer/swiftmailer": "~5.3" 70 | }, 71 | "suggest": { 72 | "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", 73 | "doctrine/couchdb": "Allow sending log messages to a CouchDB server", 74 | "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", 75 | "ext-mongo": "Allow sending log messages to a MongoDB server", 76 | "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", 77 | "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", 78 | "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", 79 | "php-console/php-console": "Allow sending log messages to Google Chrome", 80 | "rollbar/rollbar": "Allow sending log messages to Rollbar", 81 | "ruflin/elastica": "Allow sending log messages to an Elastic Search server", 82 | "sentry/sentry": "Allow sending log messages to a Sentry server" 83 | }, 84 | "type": "library", 85 | "extra": { 86 | "branch-alias": { 87 | "dev-master": "2.0.x-dev" 88 | } 89 | }, 90 | "autoload": { 91 | "psr-4": { 92 | "Monolog\\": "src/Monolog" 93 | } 94 | }, 95 | "notification-url": "https://packagist.org/downloads/", 96 | "license": [ 97 | "MIT" 98 | ], 99 | "authors": [ 100 | { 101 | "name": "Jordi Boggiano", 102 | "email": "j.boggiano@seld.be", 103 | "homepage": "http://seld.be" 104 | } 105 | ], 106 | "description": "Sends your logs to files, sockets, inboxes, databases and various web services", 107 | "homepage": "http://github.com/Seldaek/monolog", 108 | "keywords": [ 109 | "log", 110 | "logging", 111 | "psr-3" 112 | ], 113 | "time": "2016-07-29 03:23:52" 114 | }, 115 | { 116 | "name": "nikic/fast-route", 117 | "version": "v1.0.1", 118 | "source": { 119 | "type": "git", 120 | "url": "https://github.com/nikic/FastRoute.git", 121 | "reference": "8ea928195fa9b907f0d6e48312d323c1a13cc2af" 122 | }, 123 | "dist": { 124 | "type": "zip", 125 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/8ea928195fa9b907f0d6e48312d323c1a13cc2af", 126 | "reference": "8ea928195fa9b907f0d6e48312d323c1a13cc2af", 127 | "shasum": "" 128 | }, 129 | "require": { 130 | "php": ">=5.4.0" 131 | }, 132 | "type": "library", 133 | "autoload": { 134 | "psr-4": { 135 | "FastRoute\\": "src/" 136 | }, 137 | "files": [ 138 | "src/functions.php" 139 | ] 140 | }, 141 | "notification-url": "https://packagist.org/downloads/", 142 | "license": [ 143 | "BSD-3-Clause" 144 | ], 145 | "authors": [ 146 | { 147 | "name": "Nikita Popov", 148 | "email": "nikic@php.net" 149 | } 150 | ], 151 | "description": "Fast request router for PHP", 152 | "keywords": [ 153 | "router", 154 | "routing" 155 | ], 156 | "time": "2016-06-12 19:08:51" 157 | }, 158 | { 159 | "name": "pimple/pimple", 160 | "version": "v3.0.2", 161 | "source": { 162 | "type": "git", 163 | "url": "https://github.com/silexphp/Pimple.git", 164 | "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a" 165 | }, 166 | "dist": { 167 | "type": "zip", 168 | "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a", 169 | "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a", 170 | "shasum": "" 171 | }, 172 | "require": { 173 | "php": ">=5.3.0" 174 | }, 175 | "type": "library", 176 | "extra": { 177 | "branch-alias": { 178 | "dev-master": "3.0.x-dev" 179 | } 180 | }, 181 | "autoload": { 182 | "psr-0": { 183 | "Pimple": "src/" 184 | } 185 | }, 186 | "notification-url": "https://packagist.org/downloads/", 187 | "license": [ 188 | "MIT" 189 | ], 190 | "authors": [ 191 | { 192 | "name": "Fabien Potencier", 193 | "email": "fabien@symfony.com" 194 | } 195 | ], 196 | "description": "Pimple, a simple Dependency Injection Container", 197 | "homepage": "http://pimple.sensiolabs.org", 198 | "keywords": [ 199 | "container", 200 | "dependency injection" 201 | ], 202 | "time": "2015-09-11 15:10:35" 203 | }, 204 | { 205 | "name": "psr/http-message", 206 | "version": "1.0.1", 207 | "source": { 208 | "type": "git", 209 | "url": "https://github.com/php-fig/http-message.git", 210 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" 211 | }, 212 | "dist": { 213 | "type": "zip", 214 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", 215 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", 216 | "shasum": "" 217 | }, 218 | "require": { 219 | "php": ">=5.3.0" 220 | }, 221 | "type": "library", 222 | "extra": { 223 | "branch-alias": { 224 | "dev-master": "1.0.x-dev" 225 | } 226 | }, 227 | "autoload": { 228 | "psr-4": { 229 | "Psr\\Http\\Message\\": "src/" 230 | } 231 | }, 232 | "notification-url": "https://packagist.org/downloads/", 233 | "license": [ 234 | "MIT" 235 | ], 236 | "authors": [ 237 | { 238 | "name": "PHP-FIG", 239 | "homepage": "http://www.php-fig.org/" 240 | } 241 | ], 242 | "description": "Common interface for HTTP messages", 243 | "homepage": "https://github.com/php-fig/http-message", 244 | "keywords": [ 245 | "http", 246 | "http-message", 247 | "psr", 248 | "psr-7", 249 | "request", 250 | "response" 251 | ], 252 | "time": "2016-08-06 14:39:51" 253 | }, 254 | { 255 | "name": "psr/log", 256 | "version": "1.0.2", 257 | "source": { 258 | "type": "git", 259 | "url": "https://github.com/php-fig/log.git", 260 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" 261 | }, 262 | "dist": { 263 | "type": "zip", 264 | "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 265 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 266 | "shasum": "" 267 | }, 268 | "require": { 269 | "php": ">=5.3.0" 270 | }, 271 | "type": "library", 272 | "extra": { 273 | "branch-alias": { 274 | "dev-master": "1.0.x-dev" 275 | } 276 | }, 277 | "autoload": { 278 | "psr-4": { 279 | "Psr\\Log\\": "Psr/Log/" 280 | } 281 | }, 282 | "notification-url": "https://packagist.org/downloads/", 283 | "license": [ 284 | "MIT" 285 | ], 286 | "authors": [ 287 | { 288 | "name": "PHP-FIG", 289 | "homepage": "http://www.php-fig.org/" 290 | } 291 | ], 292 | "description": "Common interface for logging libraries", 293 | "homepage": "https://github.com/php-fig/log", 294 | "keywords": [ 295 | "log", 296 | "psr", 297 | "psr-3" 298 | ], 299 | "time": "2016-10-10 12:19:37" 300 | }, 301 | { 302 | "name": "robmorgan/phinx", 303 | "version": "v0.5.5", 304 | "source": { 305 | "type": "git", 306 | "url": "https://github.com/robmorgan/phinx.git", 307 | "reference": "da9950a5e5b9314ebf72ddc6317ed587ce9ba8dc" 308 | }, 309 | "dist": { 310 | "type": "zip", 311 | "url": "https://api.github.com/repos/robmorgan/phinx/zipball/da9950a5e5b9314ebf72ddc6317ed587ce9ba8dc", 312 | "reference": "da9950a5e5b9314ebf72ddc6317ed587ce9ba8dc", 313 | "shasum": "" 314 | }, 315 | "require": { 316 | "php": ">=5.4", 317 | "symfony/config": "~2.8|~3.0", 318 | "symfony/console": "~2.8|~3.0", 319 | "symfony/yaml": "~2.8|~3.0" 320 | }, 321 | "require-dev": { 322 | "phpunit/phpunit": "^3.7|^4.0|^5.0" 323 | }, 324 | "bin": [ 325 | "bin/phinx" 326 | ], 327 | "type": "library", 328 | "autoload": { 329 | "psr-4": { 330 | "Phinx\\": "src/Phinx" 331 | } 332 | }, 333 | "notification-url": "https://packagist.org/downloads/", 334 | "license": [ 335 | "MIT" 336 | ], 337 | "authors": [ 338 | { 339 | "name": "Woody Gilk", 340 | "email": "woody.gilk@gmail.com", 341 | "homepage": "http://shadowhand.me", 342 | "role": "Developer" 343 | }, 344 | { 345 | "name": "Rob Morgan", 346 | "email": "robbym@gmail.com", 347 | "homepage": "https://robmorgan.id.au", 348 | "role": "Lead Developer" 349 | } 350 | ], 351 | "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.", 352 | "homepage": "https://phinx.org", 353 | "keywords": [ 354 | "database", 355 | "database migrations", 356 | "db", 357 | "migrations", 358 | "phinx" 359 | ], 360 | "time": "2016-06-17 15:29:02" 361 | }, 362 | { 363 | "name": "slim/php-view", 364 | "version": "2.1.0", 365 | "source": { 366 | "type": "git", 367 | "url": "https://github.com/slimphp/PHP-View.git", 368 | "reference": "8bae5b10d10c51596ef8d8113b3b63678718adcb" 369 | }, 370 | "dist": { 371 | "type": "zip", 372 | "url": "https://api.github.com/repos/slimphp/PHP-View/zipball/8bae5b10d10c51596ef8d8113b3b63678718adcb", 373 | "reference": "8bae5b10d10c51596ef8d8113b3b63678718adcb", 374 | "shasum": "" 375 | }, 376 | "require": { 377 | "psr/http-message": "^1.0" 378 | }, 379 | "require-dev": { 380 | "phpunit/phpunit": "^5.0", 381 | "slim/slim": "^3.0" 382 | }, 383 | "type": "library", 384 | "autoload": { 385 | "psr-4": { 386 | "Slim\\Views\\": "src" 387 | } 388 | }, 389 | "notification-url": "https://packagist.org/downloads/", 390 | "license": [ 391 | "MIT" 392 | ], 393 | "authors": [ 394 | { 395 | "name": "Glenn Eggleton", 396 | "email": "geggleto@gmail.com" 397 | } 398 | ], 399 | "description": "Render PHP view scripts into a PSR-7 Response object.", 400 | "keywords": [ 401 | "framework", 402 | "php", 403 | "phtml", 404 | "renderer", 405 | "slim", 406 | "template", 407 | "view" 408 | ], 409 | "time": "2016-03-04 09:48:50" 410 | }, 411 | { 412 | "name": "slim/slim", 413 | "version": "3.5.0", 414 | "source": { 415 | "type": "git", 416 | "url": "https://github.com/slimphp/Slim.git", 417 | "reference": "184352bc1913d7ba552ab4131d62f4730ddb0893" 418 | }, 419 | "dist": { 420 | "type": "zip", 421 | "url": "https://api.github.com/repos/slimphp/Slim/zipball/184352bc1913d7ba552ab4131d62f4730ddb0893", 422 | "reference": "184352bc1913d7ba552ab4131d62f4730ddb0893", 423 | "shasum": "" 424 | }, 425 | "require": { 426 | "container-interop/container-interop": "^1.1", 427 | "nikic/fast-route": "^1.0", 428 | "php": ">=5.5.0", 429 | "pimple/pimple": "^3.0", 430 | "psr/http-message": "^1.0" 431 | }, 432 | "provide": { 433 | "psr/http-message-implementation": "1.0" 434 | }, 435 | "require-dev": { 436 | "phpunit/phpunit": "^4.0", 437 | "squizlabs/php_codesniffer": "^2.5" 438 | }, 439 | "type": "library", 440 | "autoload": { 441 | "psr-4": { 442 | "Slim\\": "Slim" 443 | } 444 | }, 445 | "notification-url": "https://packagist.org/downloads/", 446 | "license": [ 447 | "MIT" 448 | ], 449 | "authors": [ 450 | { 451 | "name": "Rob Allen", 452 | "email": "rob@akrabat.com", 453 | "homepage": "http://akrabat.com" 454 | }, 455 | { 456 | "name": "Josh Lockhart", 457 | "email": "hello@joshlockhart.com", 458 | "homepage": "https://joshlockhart.com" 459 | }, 460 | { 461 | "name": "Gabriel Manricks", 462 | "email": "gmanricks@me.com", 463 | "homepage": "http://gabrielmanricks.com" 464 | }, 465 | { 466 | "name": "Andrew Smith", 467 | "email": "a.smith@silentworks.co.uk", 468 | "homepage": "http://silentworks.co.uk" 469 | } 470 | ], 471 | "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", 472 | "homepage": "http://slimframework.com", 473 | "keywords": [ 474 | "api", 475 | "framework", 476 | "micro", 477 | "router" 478 | ], 479 | "time": "2016-07-26 15:12:13" 480 | }, 481 | { 482 | "name": "symfony/config", 483 | "version": "v3.1.5", 484 | "source": { 485 | "type": "git", 486 | "url": "https://github.com/symfony/config.git", 487 | "reference": "949e7e846743a7f9e46dc50eb639d5fde1f53341" 488 | }, 489 | "dist": { 490 | "type": "zip", 491 | "url": "https://api.github.com/repos/symfony/config/zipball/949e7e846743a7f9e46dc50eb639d5fde1f53341", 492 | "reference": "949e7e846743a7f9e46dc50eb639d5fde1f53341", 493 | "shasum": "" 494 | }, 495 | "require": { 496 | "php": ">=5.5.9", 497 | "symfony/filesystem": "~2.8|~3.0" 498 | }, 499 | "suggest": { 500 | "symfony/yaml": "To use the yaml reference dumper" 501 | }, 502 | "type": "library", 503 | "extra": { 504 | "branch-alias": { 505 | "dev-master": "3.1-dev" 506 | } 507 | }, 508 | "autoload": { 509 | "psr-4": { 510 | "Symfony\\Component\\Config\\": "" 511 | }, 512 | "exclude-from-classmap": [ 513 | "/Tests/" 514 | ] 515 | }, 516 | "notification-url": "https://packagist.org/downloads/", 517 | "license": [ 518 | "MIT" 519 | ], 520 | "authors": [ 521 | { 522 | "name": "Fabien Potencier", 523 | "email": "fabien@symfony.com" 524 | }, 525 | { 526 | "name": "Symfony Community", 527 | "homepage": "https://symfony.com/contributors" 528 | } 529 | ], 530 | "description": "Symfony Config Component", 531 | "homepage": "https://symfony.com", 532 | "time": "2016-09-25 08:27:07" 533 | }, 534 | { 535 | "name": "symfony/console", 536 | "version": "v3.1.5", 537 | "source": { 538 | "type": "git", 539 | "url": "https://github.com/symfony/console.git", 540 | "reference": "6cb0872fb57b38b3b09ff213c21ed693956b9eb0" 541 | }, 542 | "dist": { 543 | "type": "zip", 544 | "url": "https://api.github.com/repos/symfony/console/zipball/6cb0872fb57b38b3b09ff213c21ed693956b9eb0", 545 | "reference": "6cb0872fb57b38b3b09ff213c21ed693956b9eb0", 546 | "shasum": "" 547 | }, 548 | "require": { 549 | "php": ">=5.5.9", 550 | "symfony/debug": "~2.8|~3.0", 551 | "symfony/polyfill-mbstring": "~1.0" 552 | }, 553 | "require-dev": { 554 | "psr/log": "~1.0", 555 | "symfony/event-dispatcher": "~2.8|~3.0", 556 | "symfony/process": "~2.8|~3.0" 557 | }, 558 | "suggest": { 559 | "psr/log": "For using the console logger", 560 | "symfony/event-dispatcher": "", 561 | "symfony/process": "" 562 | }, 563 | "type": "library", 564 | "extra": { 565 | "branch-alias": { 566 | "dev-master": "3.1-dev" 567 | } 568 | }, 569 | "autoload": { 570 | "psr-4": { 571 | "Symfony\\Component\\Console\\": "" 572 | }, 573 | "exclude-from-classmap": [ 574 | "/Tests/" 575 | ] 576 | }, 577 | "notification-url": "https://packagist.org/downloads/", 578 | "license": [ 579 | "MIT" 580 | ], 581 | "authors": [ 582 | { 583 | "name": "Fabien Potencier", 584 | "email": "fabien@symfony.com" 585 | }, 586 | { 587 | "name": "Symfony Community", 588 | "homepage": "https://symfony.com/contributors" 589 | } 590 | ], 591 | "description": "Symfony Console Component", 592 | "homepage": "https://symfony.com", 593 | "time": "2016-09-28 00:11:12" 594 | }, 595 | { 596 | "name": "symfony/debug", 597 | "version": "v3.1.5", 598 | "source": { 599 | "type": "git", 600 | "url": "https://github.com/symfony/debug.git", 601 | "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8" 602 | }, 603 | "dist": { 604 | "type": "zip", 605 | "url": "https://api.github.com/repos/symfony/debug/zipball/e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", 606 | "reference": "e2b3f74a67fc928adc3c1b9027f73e1bc01190a8", 607 | "shasum": "" 608 | }, 609 | "require": { 610 | "php": ">=5.5.9", 611 | "psr/log": "~1.0" 612 | }, 613 | "conflict": { 614 | "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" 615 | }, 616 | "require-dev": { 617 | "symfony/class-loader": "~2.8|~3.0", 618 | "symfony/http-kernel": "~2.8|~3.0" 619 | }, 620 | "type": "library", 621 | "extra": { 622 | "branch-alias": { 623 | "dev-master": "3.1-dev" 624 | } 625 | }, 626 | "autoload": { 627 | "psr-4": { 628 | "Symfony\\Component\\Debug\\": "" 629 | }, 630 | "exclude-from-classmap": [ 631 | "/Tests/" 632 | ] 633 | }, 634 | "notification-url": "https://packagist.org/downloads/", 635 | "license": [ 636 | "MIT" 637 | ], 638 | "authors": [ 639 | { 640 | "name": "Fabien Potencier", 641 | "email": "fabien@symfony.com" 642 | }, 643 | { 644 | "name": "Symfony Community", 645 | "homepage": "https://symfony.com/contributors" 646 | } 647 | ], 648 | "description": "Symfony Debug Component", 649 | "homepage": "https://symfony.com", 650 | "time": "2016-09-06 11:02:40" 651 | }, 652 | { 653 | "name": "symfony/filesystem", 654 | "version": "v3.1.5", 655 | "source": { 656 | "type": "git", 657 | "url": "https://github.com/symfony/filesystem.git", 658 | "reference": "682fd8fdb3135fdf05fc496a01579ccf6c85c0e5" 659 | }, 660 | "dist": { 661 | "type": "zip", 662 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/682fd8fdb3135fdf05fc496a01579ccf6c85c0e5", 663 | "reference": "682fd8fdb3135fdf05fc496a01579ccf6c85c0e5", 664 | "shasum": "" 665 | }, 666 | "require": { 667 | "php": ">=5.5.9" 668 | }, 669 | "type": "library", 670 | "extra": { 671 | "branch-alias": { 672 | "dev-master": "3.1-dev" 673 | } 674 | }, 675 | "autoload": { 676 | "psr-4": { 677 | "Symfony\\Component\\Filesystem\\": "" 678 | }, 679 | "exclude-from-classmap": [ 680 | "/Tests/" 681 | ] 682 | }, 683 | "notification-url": "https://packagist.org/downloads/", 684 | "license": [ 685 | "MIT" 686 | ], 687 | "authors": [ 688 | { 689 | "name": "Fabien Potencier", 690 | "email": "fabien@symfony.com" 691 | }, 692 | { 693 | "name": "Symfony Community", 694 | "homepage": "https://symfony.com/contributors" 695 | } 696 | ], 697 | "description": "Symfony Filesystem Component", 698 | "homepage": "https://symfony.com", 699 | "time": "2016-09-14 00:18:46" 700 | }, 701 | { 702 | "name": "symfony/polyfill-mbstring", 703 | "version": "v1.2.0", 704 | "source": { 705 | "type": "git", 706 | "url": "https://github.com/symfony/polyfill-mbstring.git", 707 | "reference": "dff51f72b0706335131b00a7f49606168c582594" 708 | }, 709 | "dist": { 710 | "type": "zip", 711 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", 712 | "reference": "dff51f72b0706335131b00a7f49606168c582594", 713 | "shasum": "" 714 | }, 715 | "require": { 716 | "php": ">=5.3.3" 717 | }, 718 | "suggest": { 719 | "ext-mbstring": "For best performance" 720 | }, 721 | "type": "library", 722 | "extra": { 723 | "branch-alias": { 724 | "dev-master": "1.2-dev" 725 | } 726 | }, 727 | "autoload": { 728 | "psr-4": { 729 | "Symfony\\Polyfill\\Mbstring\\": "" 730 | }, 731 | "files": [ 732 | "bootstrap.php" 733 | ] 734 | }, 735 | "notification-url": "https://packagist.org/downloads/", 736 | "license": [ 737 | "MIT" 738 | ], 739 | "authors": [ 740 | { 741 | "name": "Nicolas Grekas", 742 | "email": "p@tchwork.com" 743 | }, 744 | { 745 | "name": "Symfony Community", 746 | "homepage": "https://symfony.com/contributors" 747 | } 748 | ], 749 | "description": "Symfony polyfill for the Mbstring extension", 750 | "homepage": "https://symfony.com", 751 | "keywords": [ 752 | "compatibility", 753 | "mbstring", 754 | "polyfill", 755 | "portable", 756 | "shim" 757 | ], 758 | "time": "2016-05-18 14:26:46" 759 | }, 760 | { 761 | "name": "symfony/yaml", 762 | "version": "v3.1.5", 763 | "source": { 764 | "type": "git", 765 | "url": "https://github.com/symfony/yaml.git", 766 | "reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3" 767 | }, 768 | "dist": { 769 | "type": "zip", 770 | "url": "https://api.github.com/repos/symfony/yaml/zipball/368b9738d4033c8b93454cb0dbd45d305135a6d3", 771 | "reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3", 772 | "shasum": "" 773 | }, 774 | "require": { 775 | "php": ">=5.5.9" 776 | }, 777 | "type": "library", 778 | "extra": { 779 | "branch-alias": { 780 | "dev-master": "3.1-dev" 781 | } 782 | }, 783 | "autoload": { 784 | "psr-4": { 785 | "Symfony\\Component\\Yaml\\": "" 786 | }, 787 | "exclude-from-classmap": [ 788 | "/Tests/" 789 | ] 790 | }, 791 | "notification-url": "https://packagist.org/downloads/", 792 | "license": [ 793 | "MIT" 794 | ], 795 | "authors": [ 796 | { 797 | "name": "Fabien Potencier", 798 | "email": "fabien@symfony.com" 799 | }, 800 | { 801 | "name": "Symfony Community", 802 | "homepage": "https://symfony.com/contributors" 803 | } 804 | ], 805 | "description": "Symfony Yaml Component", 806 | "homepage": "https://symfony.com", 807 | "time": "2016-09-25 08:27:07" 808 | } 809 | ], 810 | "packages-dev": [], 811 | "aliases": [], 812 | "minimum-stability": "stable", 813 | "stability-flags": [], 814 | "prefer-stable": false, 815 | "prefer-lowest": false, 816 | "platform": [], 817 | "platform-dev": [] 818 | } 819 | -------------------------------------------------------------------------------- /src/composer.phar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slimphp/Tutorial-First-Application/a21e5f4bb39ebfa5a807d46ef5e8503b72ffe438/src/composer.phar -------------------------------------------------------------------------------- /src/phinx.yml: -------------------------------------------------------------------------------- 1 | paths: 2 | migrations: ../db/migrations 3 | seeds: ../db/seeds 4 | 5 | environments: 6 | default_migration_table: phinxlog 7 | default_database: development 8 | 9 | development: 10 | adapter: mysql 11 | host: localhost 12 | name: exampleapp 13 | user: user 14 | pass: password 15 | port: 3306 16 | charset: utf8 17 | -------------------------------------------------------------------------------- /src/public/index.php: -------------------------------------------------------------------------------- 1 | $config]); 16 | $container = $app->getContainer(); 17 | 18 | $container['view'] = new \Slim\Views\PhpRenderer("../templates/"); 19 | 20 | $container['logger'] = function($c) { 21 | $logger = new \Monolog\Logger('my_logger'); 22 | $file_handler = new \Monolog\Handler\StreamHandler("../logs/app.log"); 23 | $logger->pushHandler($file_handler); 24 | return $logger; 25 | }; 26 | 27 | $container['db'] = function ($c) { 28 | $db = $c['settings']['db']; 29 | $pdo = new PDO("mysql:host=" . $db['host'] . ";dbname=" . $db['dbname'], 30 | $db['user'], $db['pass']); 31 | $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 32 | $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 33 | return $pdo; 34 | }; 35 | 36 | $app->get('/tickets', function (Request $request, Response $response) { 37 | $this->logger->addInfo("Ticket list"); 38 | $mapper = new TicketMapper($this->db); 39 | $tickets = $mapper->getTickets(); 40 | 41 | $response = $this->view->render($response, "tickets.phtml", ["tickets" => $tickets, "router" => $this->router]); 42 | return $response; 43 | }); 44 | 45 | $app->get('/ticket/new', function (Request $request, Response $response) { 46 | $component_mapper = new ComponentMapper($this->db); 47 | $components = $component_mapper->getComponents(); 48 | $response = $this->view->render($response, "ticketadd.phtml", ["components" => $components]); 49 | return $response; 50 | }); 51 | 52 | $app->post('/ticket/new', function (Request $request, Response $response) { 53 | $data = $request->getParsedBody(); 54 | $ticket_data = []; 55 | $ticket_data['title'] = filter_var($data['title'], FILTER_SANITIZE_STRING); 56 | $ticket_data['description'] = filter_var($data['description'], FILTER_SANITIZE_STRING); 57 | 58 | // work out the component 59 | $component_id = (int)$data['component']; 60 | $component_mapper = new ComponentMapper($this->db); 61 | $component = $component_mapper->getComponentById($component_id); 62 | $ticket_data['component'] = $component->getName(); 63 | 64 | $ticket = new TicketEntity($ticket_data); 65 | $ticket_mapper = new TicketMapper($this->db); 66 | $ticket_mapper->save($ticket); 67 | 68 | $response = $response->withRedirect("/tickets"); 69 | return $response; 70 | }); 71 | 72 | $app->get('/ticket/{id}', function (Request $request, Response $response, $args) { 73 | $ticket_id = (int)$args['id']; 74 | $mapper = new TicketMapper($this->db); 75 | $ticket = $mapper->getTicketById($ticket_id); 76 | 77 | $response = $this->view->render($response, "ticketdetail.phtml", ["ticket" => $ticket]); 78 | return $response; 79 | })->setName('ticket-detail'); 80 | 81 | $app->run(); 82 | -------------------------------------------------------------------------------- /src/templates/404.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example Application 4 | 5 | 6 | 7 |

Ooooops!

8 | 9 |

Message: getMessage();?>

10 |

On line getLine();?> in getFile();?>

11 | 12 | 13 | -------------------------------------------------------------------------------- /src/templates/ticketadd.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example Application 4 | 5 | 6 | 7 |

New Ticket

8 | 9 |
10 | 11 |
12 | 13 | 14 |
15 | 16 | 17 |
26 | 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/templates/ticketdetail.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example Application 4 | 5 | 6 | 7 |

getTitle()?>

8 | 9 |

getDescription()?>

10 | 11 |

Component: getComponent()?>

12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/templates/tickets.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example Application 4 | 5 | 6 | 7 |

All Tickets

8 | 9 |

Add new ticket

10 | 11 | 0): 13 | ?> 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | > 27 | 28 | 29 | 30 | 33 | 34 | 35 | 38 |
TitleComponentDescriptionActions
getTitle() ?>getComponent() ?>getShortDescription() ?> ... 31 | view 32 |
39 | 40 |

No current tickets

41 | 42 | 43 | 44 | 45 | 46 | --------------------------------------------------------------------------------