├── public
├── index.php
├── css
│ └── style.css
├── package-lock.json
└── package.json
├── src
├── Model
│ ├── UserModel.php
│ ├── Factory
│ │ ├── PdoFactory.php
│ │ └── ModelFactory.php
│ ├── PdoDb.php
│ └── MainModel.php
├── View
│ ├── layout
│ │ ├── navbar.twig
│ │ ├── footer.twig
│ │ └── layout.twig
│ └── home.twig
├── Controller
│ ├── HomeController.php
│ └── MainController.php
└── Router.php
├── .gitignore
├── .htaccess
├── config
├── db.php
└── db.sql
├── LICENSE.md
├── composer.json
├── README.md
└── composer.lock
/public/index.php:
--------------------------------------------------------------------------------
1 | run();
7 |
--------------------------------------------------------------------------------
/src/Model/UserModel.php:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | Options +FollowSymLinks -Multiviews
3 |
4 | RewriteEngine on
5 | RewriteBase /
6 |
7 | # Force https
8 | RewriteCond %{REQUEST_SCHEME} =http
9 | RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
10 |
11 | # Force non-www
12 | RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
13 | RewriteRule ^(.*)$ https://%1/$1 [NE,R=301,L]
14 |
15 | # Remove public/
16 | RewriteCond %{REQUEST_URI} !/public/ [NC]
17 | RewriteRule ^(.*?)/?$ public/$1 [L]
18 |
--------------------------------------------------------------------------------
/config/db.php:
--------------------------------------------------------------------------------
1 | PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
13 |
--------------------------------------------------------------------------------
/public/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "php-mvc",
3 | "description": "Instructional Template to start a Web Application with a PHP MVC Architecture",
4 | "keywords": [
5 | "pedagogic",
6 | "template",
7 | "web",
8 | "application",
9 | "php",
10 | "mvc"
11 | ],
12 | "license": "MIT",
13 | "main": "index.php",
14 | "homepage": "https://philippebeck.net",
15 | "repository": "github:philippebeck/php-mvc",
16 | "bugs": "https://github.com/philippebeck/php-mvc/issues",
17 | "dependencies": {
18 | "@fortawesome/fontawesome-free": "^5.13.1"
19 | },
20 | "author": {
21 | "name": "Philippe Beck",
22 | "email": "philippe@philippebeck.net",
23 | "url": "https://philippebeck.net"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Controller/HomeController.php:
--------------------------------------------------------------------------------
1 | listData();
27 |
28 | return $this->twig->render("home.twig", ["allUsers" => $allUsers]);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/View/layout/footer.twig:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/src/Model/Factory/PdoFactory.php:
--------------------------------------------------------------------------------
1 | exec("SET NAMES UTF8");
31 | }
32 |
33 | return self::$pdo;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Model/Factory/ModelFactory.php:
--------------------------------------------------------------------------------
1 | twig = new Environment(new FilesystemLoader("../src/View"), array("cache" => false));
27 | }
28 |
29 | /**
30 | * Redirects to another URL
31 | * @param string $page
32 | * @param array $params
33 | */
34 | public function redirect(string $page, array $params = [])
35 | {
36 | $params["access"] = $page;
37 | header("Location: index.php?" . http_build_query($params));
38 |
39 | exit;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/config/db.sql:
--------------------------------------------------------------------------------
1 | -- WARNING : Don't forget to add the file name inside the .gitignore file when you add sensible datas here (like passwords)
2 |
3 | -- For Development only ! (Depends on your online server architecture)
4 | DROP DATABASE IF EXISTS `php_mvc`;
5 | CREATE DATABASE `php_mvc` CHARACTER SET utf8;
6 |
7 | -- Needs to be replaced in Production with the db name of the online server
8 | USE `php_mvc`;
9 |
10 | -- Creates the table User
11 | CREATE TABLE `User`
12 | (
13 | `id` SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
14 | `name` VARCHAR(50) NOT NULL,
15 | `image` VARCHAR(50) UNIQUE,
16 | `email` VARCHAR(100) NOT NULL UNIQUE,
17 | `pass` VARCHAR(60) NOT NULL
18 | )
19 | ENGINE=INNODB DEFAULT CHARSET=utf8;
20 |
21 | -- Inserts the User data
22 | -- WARNING : Never store real passwords in a commit file
23 | INSERT INTO `User`
24 | (`name`, `image`, `email`, `pass`)
25 | VALUES
26 | ('John', 'john.jpg', 'john@doe.com', 'john465'),
27 | ('Jane', 'jane.jpg', 'jane@doe.com', 'jane465');
28 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Philippe Beck
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "philippebeck/php-mvc",
3 | "version": "1.1.0",
4 | "type": "project",
5 | "description": "Instructional Template to start a Web Application with a PHP MVC Architecture",
6 | "keywords": [
7 | "pedagogic",
8 | "template",
9 | "web",
10 | "application",
11 | "php",
12 | "mvc"
13 | ],
14 | "homepage": "https://php-mvc.philippebeck.net",
15 | "license": "MIT",
16 | "authors": [
17 | {
18 | "name": "Philippe Beck",
19 | "email": "philippe@philippebeck.net",
20 | "homepage": "https://philippebeck.net",
21 | "role": "Lead Developer"
22 | }
23 | ],
24 | "autoload": {
25 | "psr-4": {
26 | "App\\": "src/"
27 | }
28 | },
29 | "require": {
30 | "php": "7.3",
31 | "twig/twig": "^3.0.3"
32 | },
33 | "config": {
34 | "platform": {
35 | "php": "7.3"
36 | }
37 | },
38 | "support": {
39 | "email": "admin@philippebeck.net",
40 | "issues": "https://github.com/philippebeck/php-mvc/issues",
41 | "wiki": "https://github.com/philippebeck/php-mvc/wiki",
42 | "source": "https://github.com/philippebeck/php-mvc"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/View/home.twig:
--------------------------------------------------------------------------------
1 | {% extends 'layout/layout.twig' %}
2 |
3 | {% block title %}Home{% endblock %}
4 |
5 | {% block description %}Homepage of the PHP-MVC project{% endblock %}
6 |
7 | {% block main %}
8 |
9 |
10 | Introduction
11 |
12 | This project is a pedagogic template to start a Web application with a PHP MVC architecture...
13 | You will find the documentation here...
14 | Don't hesitate to send issues or pull requests, I will watch them with interest...
15 |
16 |
17 |
18 | Demonstration
19 |
20 | The example users are :
21 |
22 | {% for user in allUsers %}
23 | -
24 | {{ user.name }}
{{ user.email }}
25 |
26 | {% endfor %}
27 |
28 |
29 |
30 | {% endblock %}
31 |
--------------------------------------------------------------------------------
/src/Model/PdoDb.php:
--------------------------------------------------------------------------------
1 | pdo = $pdo;
28 | }
29 |
30 | /**
31 | * Returns a unique result from the Database
32 | * @param string $query
33 | * @param array $params
34 | * @return mixed
35 | */
36 | public function getData(string $query, array $params = [])
37 | {
38 | $PDOStatement = $this->pdo->prepare($query);
39 | $PDOStatement->execute($params);
40 |
41 | return $PDOStatement->fetch();
42 | }
43 |
44 | /**
45 | * Returns many results from the Database
46 | * @param string $query
47 | * @param array $params
48 | * @return array|mixed
49 | */
50 | public function getAllData(string $query, array $params = [])
51 | {
52 | $PDOStatement = $this->pdo->prepare($query);
53 | $PDOStatement->execute($params);
54 |
55 | return $PDOStatement->fetchAll();
56 | }
57 |
58 | /**
59 | * Executes an action to the Database
60 | * @param string $query
61 | * @param array $params
62 | * @return bool|mixed
63 | */
64 | public function setData(string $query, array $params = [])
65 | {
66 | $PDOStatement = $this->pdo->prepare($query);
67 |
68 | return $PDOStatement->execute($params);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/View/layout/layout.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{ block('title') }}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | {{ include('layout/navbar.twig') }}
40 |
41 |
42 | {{ block('title') }}
43 |
44 |
45 | {% block main %}{% endblock %}
46 |
47 | {{ include('layout/footer.twig') }}
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/Router.php:
--------------------------------------------------------------------------------
1 | parseUrl();
46 | $this->setController();
47 | $this->setMethod();
48 | }
49 |
50 | /**
51 | * Parses the URL to get the Controller & his Method
52 | */
53 | public function parseUrl()
54 | {
55 | $access = filter_input(INPUT_GET, "access");
56 |
57 | if (!isset($access)) {
58 | $access = "home";
59 | }
60 |
61 | $access = explode("!", $access);
62 | $this->controller = $access[0];
63 | $this->method = count($access) == 1 ? "default" : $access[1];
64 | }
65 |
66 | /**
67 | * Sets the requested Controller
68 | */
69 | public function setController()
70 | {
71 | $this->controller = ucfirst(strtolower($this->controller)) . "Controller";
72 | $this->controller = self::DEFAULT_PATH . $this->controller;
73 |
74 | if (!class_exists($this->controller)) {
75 | $this->controller = self::DEFAULT_PATH . self::DEFAULT_CONTROLLER;
76 | }
77 | }
78 |
79 | /**
80 | * Sets the requested Method
81 | */
82 | public function setMethod()
83 | {
84 | $this->method = strtolower($this->method) . "Method";
85 |
86 | if (!method_exists($this->controller, $this->method)) {
87 | $this->method = self::DEFAULT_METHOD;
88 | }
89 | }
90 |
91 | /**
92 | * Creates the Controller object & calls the Method on it
93 | */
94 | public function run()
95 | {
96 | $this->controller = new $this->controller();
97 | $response = call_user_func([$this->controller, $this->method]);
98 |
99 | echo filter_var($response);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/Model/MainModel.php:
--------------------------------------------------------------------------------
1 | database = $database;
32 | $model = explode("\\", get_class($this));
33 | $this->table = ucfirst(str_replace("Model", "", array_pop($model)));
34 | }
35 |
36 | /**
37 | * Lists all Datas from the id or another key
38 | * @param string $value
39 | * @param string $key
40 | * @return array|mixed
41 | */
42 | public function listData(string $value = null, string $key = null)
43 | {
44 | if (isset($key)) {
45 | $query = "SELECT * FROM " . $this->table . " WHERE " . $key . " = ?";
46 |
47 | return $this->database->getAllData($query, [$value]);
48 | }
49 | $query = "SELECT * FROM " . $this->table;
50 |
51 | return $this->database->getAllData($query);
52 | }
53 |
54 | /**
55 | * Creates a new Data entry
56 | * @param array $data
57 | */
58 | public function createData(array $data)
59 | {
60 | $keys = implode(", ", array_keys($data));
61 | $values = implode("', '", $data);
62 | $query = "INSERT INTO " . $this->table . " (" . $keys . ") VALUES ('" . $values . "')";
63 |
64 | $this->database->setData($query);
65 | }
66 |
67 | /**
68 | * Reads Data from its id or another key
69 | * @param string $value
70 | * @param string|null $key
71 | * @return mixed
72 | */
73 | public function readData(string $value, string $key = null)
74 | {
75 | if (isset($key)) {
76 | $query = "SELECT * FROM " . $this->table . " WHERE " . $key . " = ?";
77 | } else {
78 | $query = "SELECT * FROM " . $this->table . " WHERE id = ?";
79 | }
80 |
81 | return $this->database->getData($query, [$value]);
82 | }
83 |
84 | /**
85 | * Updates Data from its id or another key
86 | * @param string $value
87 | * @param array $data
88 | * @param string|null $key
89 | */
90 | public function updateData(string $value, array $data, string $key = null)
91 | {
92 | $set = null;
93 |
94 | foreach ($data as $dataKey => $dataValue) {
95 | $set .= $dataKey . " = '" . $dataValue . "', ";
96 | }
97 |
98 | $set = substr_replace($set, "", -2);
99 |
100 | if (isset($key)) {
101 | $query = "UPDATE " . $this->table . " SET " . $set . " WHERE " . $key . " = ?";
102 | } else {
103 | $query = "UPDATE " . $this->table . " SET " . $set . " WHERE id = ?";
104 | }
105 |
106 | $this->database->setData($query, [$value]);
107 | }
108 |
109 | /**
110 | * Deletes Data from its id or another key
111 | * @param string $value
112 | * @param string|null $key
113 | */
114 | public function deleteData(string $value, string $key = null)
115 | {
116 | if (isset($key)) {
117 | $query = "DELETE FROM " . $this->table . " WHERE " . $key . " = ?";
118 | } else {
119 | $query = "DELETE FROM " . $this->table . " WHERE id = ?";
120 | }
121 |
122 | $this->database->setData($query, [$value]);
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP-MVC
2 |
3 | Instructional Template to start a Web Application with a PHP MVC Architecture
4 |
5 | ## Overview
6 |
7 | This project is a pedagogic template to start a Web application with a PHP MVC architecture...
8 |
9 | Issues presents what steps are necessary to build it.
10 |
11 | Wiki presents the procedure to create your own PHP MVC application with this example.
12 |
13 | ## Summary
14 |
15 | - [Download](#download)
16 | - [Support](#support)
17 | - [Open-Source](#open-source)
18 | - [Documentation](#documentation)
19 | - [Issues](#issues)
20 | - [Pull Requests](#pull-requests)
21 | - [Contributing](#contributing)
22 | - [Versioning](#versioning)
23 | - [Creator](#creator)
24 | - [Copyright](#copyright)
25 |
26 | ---
27 |
28 | ## Download
29 |
30 | [Latest Release](https://github.com/philippebeck/php-mvc/releases)
31 |
32 | `git clone https://github.com/philippebeck/php-mvc.git`
33 |
34 | [](https://github.com/philippebeck/php-mvc/tree/master)
35 |
36 | ---
37 |
38 | ## Support
39 |
40 | php-mvc has no continuous support !
41 |
42 | [](https://github.com/philippebeck/php-mvc)
43 | [](https://github.com/philippebeck/php-mvc/commits/master)
44 |
45 | ---
46 |
47 | ## Open-Source
48 |
49 | [](https://github.com/philippebeck/php-mvc)
50 |
51 | ---
52 |
53 | ## Documentation
54 |
55 | Documentation is available !
56 |
57 | [](https://github.com/philippebeck/php-mvc/wiki)
58 |
59 | ---
60 |
61 | ## Issues
62 |
63 | Issues can be created here
64 |
65 | [](https://github.com/philippebeck/php-mvc/issues)
66 |
67 | ---
68 |
69 | ## Pull Requests
70 |
71 | And Pull Requests can be created there
72 |
73 | [](https://github.com/philippebeck/php-mvc/pulls)
74 |
75 | ---
76 |
77 | ## Contributing
78 |
79 | php-mvc needs you if you like it : sends pull requests on GitHub to improve it !!
80 |
81 | [](https://github.com/philippebeck/php-mvc/graphs/contributors)
82 |
83 | ---
84 |
85 | ## Versioning
86 |
87 | php-mvc is maintained under the [Semantic Versioning 2.0.0](https://semver.org)
88 |
89 | [](https://github.com/philippebeck/php-mvc/blob/master/composer.json)
90 |
91 | ---
92 |
93 | ## Creator
94 |
95 | Philippe Beck
96 |
97 | [](https://philippebeck.net)
98 | [](https://github.com/philippebeck)
99 | [](https://twitter.com/philippepjbeck)
100 |
101 | ---
102 |
103 | ## Copyright
104 |
105 | Code released under the MIT License
106 |
107 | [](https://github.com/philippebeck/php-mvc/blob/master/LICENSE)
108 |
--------------------------------------------------------------------------------
/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": "f38893f72f8687f562c2436cca7971f4",
8 | "packages": [
9 | {
10 | "name": "symfony/polyfill-ctype",
11 | "version": "v1.17.0",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/symfony/polyfill-ctype.git",
15 | "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
20 | "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "php": ">=5.3.3"
25 | },
26 | "suggest": {
27 | "ext-ctype": "For best performance"
28 | },
29 | "type": "library",
30 | "extra": {
31 | "branch-alias": {
32 | "dev-master": "1.17-dev"
33 | }
34 | },
35 | "autoload": {
36 | "psr-4": {
37 | "Symfony\\Polyfill\\Ctype\\": ""
38 | },
39 | "files": [
40 | "bootstrap.php"
41 | ]
42 | },
43 | "notification-url": "https://packagist.org/downloads/",
44 | "license": [
45 | "MIT"
46 | ],
47 | "authors": [
48 | {
49 | "name": "Gert de Pagter",
50 | "email": "BackEndTea@gmail.com"
51 | },
52 | {
53 | "name": "Symfony Community",
54 | "homepage": "https://symfony.com/contributors"
55 | }
56 | ],
57 | "description": "Symfony polyfill for ctype functions",
58 | "homepage": "https://symfony.com",
59 | "keywords": [
60 | "compatibility",
61 | "ctype",
62 | "polyfill",
63 | "portable"
64 | ],
65 | "funding": [
66 | {
67 | "url": "https://symfony.com/sponsor",
68 | "type": "custom"
69 | },
70 | {
71 | "url": "https://github.com/fabpot",
72 | "type": "github"
73 | },
74 | {
75 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
76 | "type": "tidelift"
77 | }
78 | ],
79 | "time": "2020-05-12T16:14:59+00:00"
80 | },
81 | {
82 | "name": "symfony/polyfill-mbstring",
83 | "version": "v1.17.0",
84 | "source": {
85 | "type": "git",
86 | "url": "https://github.com/symfony/polyfill-mbstring.git",
87 | "reference": "fa79b11539418b02fc5e1897267673ba2c19419c"
88 | },
89 | "dist": {
90 | "type": "zip",
91 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c",
92 | "reference": "fa79b11539418b02fc5e1897267673ba2c19419c",
93 | "shasum": ""
94 | },
95 | "require": {
96 | "php": ">=5.3.3"
97 | },
98 | "suggest": {
99 | "ext-mbstring": "For best performance"
100 | },
101 | "type": "library",
102 | "extra": {
103 | "branch-alias": {
104 | "dev-master": "1.17-dev"
105 | }
106 | },
107 | "autoload": {
108 | "psr-4": {
109 | "Symfony\\Polyfill\\Mbstring\\": ""
110 | },
111 | "files": [
112 | "bootstrap.php"
113 | ]
114 | },
115 | "notification-url": "https://packagist.org/downloads/",
116 | "license": [
117 | "MIT"
118 | ],
119 | "authors": [
120 | {
121 | "name": "Nicolas Grekas",
122 | "email": "p@tchwork.com"
123 | },
124 | {
125 | "name": "Symfony Community",
126 | "homepage": "https://symfony.com/contributors"
127 | }
128 | ],
129 | "description": "Symfony polyfill for the Mbstring extension",
130 | "homepage": "https://symfony.com",
131 | "keywords": [
132 | "compatibility",
133 | "mbstring",
134 | "polyfill",
135 | "portable",
136 | "shim"
137 | ],
138 | "funding": [
139 | {
140 | "url": "https://symfony.com/sponsor",
141 | "type": "custom"
142 | },
143 | {
144 | "url": "https://github.com/fabpot",
145 | "type": "github"
146 | },
147 | {
148 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
149 | "type": "tidelift"
150 | }
151 | ],
152 | "time": "2020-05-12T16:47:27+00:00"
153 | },
154 | {
155 | "name": "twig/twig",
156 | "version": "v3.0.3",
157 | "source": {
158 | "type": "git",
159 | "url": "https://github.com/twigphp/Twig.git",
160 | "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2"
161 | },
162 | "dist": {
163 | "type": "zip",
164 | "url": "https://api.github.com/repos/twigphp/Twig/zipball/3b88ccd180a6b61ebb517aea3b1a8906762a1dc2",
165 | "reference": "3b88ccd180a6b61ebb517aea3b1a8906762a1dc2",
166 | "shasum": ""
167 | },
168 | "require": {
169 | "php": "^7.2.5",
170 | "symfony/polyfill-ctype": "^1.8",
171 | "symfony/polyfill-mbstring": "^1.3"
172 | },
173 | "require-dev": {
174 | "psr/container": "^1.0",
175 | "symfony/phpunit-bridge": "^4.4|^5.0"
176 | },
177 | "type": "library",
178 | "extra": {
179 | "branch-alias": {
180 | "dev-master": "3.0-dev"
181 | }
182 | },
183 | "autoload": {
184 | "psr-4": {
185 | "Twig\\": "src/"
186 | }
187 | },
188 | "notification-url": "https://packagist.org/downloads/",
189 | "license": [
190 | "BSD-3-Clause"
191 | ],
192 | "authors": [
193 | {
194 | "name": "Fabien Potencier",
195 | "email": "fabien@symfony.com",
196 | "homepage": "http://fabien.potencier.org",
197 | "role": "Lead Developer"
198 | },
199 | {
200 | "name": "Twig Team",
201 | "role": "Contributors"
202 | },
203 | {
204 | "name": "Armin Ronacher",
205 | "email": "armin.ronacher@active-4.com",
206 | "role": "Project Founder"
207 | }
208 | ],
209 | "description": "Twig, the flexible, fast, and secure template language for PHP",
210 | "homepage": "https://twig.symfony.com",
211 | "keywords": [
212 | "templating"
213 | ],
214 | "time": "2020-02-11T15:33:47+00:00"
215 | }
216 | ],
217 | "packages-dev": [],
218 | "aliases": [],
219 | "minimum-stability": "stable",
220 | "stability-flags": [],
221 | "prefer-stable": false,
222 | "prefer-lowest": false,
223 | "platform": {
224 | "php": "7.3"
225 | },
226 | "platform-dev": [],
227 | "platform-overrides": {
228 | "php": "7.3"
229 | },
230 | "plugin-api-version": "1.1.0"
231 | }
232 |
--------------------------------------------------------------------------------