From 90f12ab916dea2a999e5d19cd3112c707592a640 Mon Sep 17 00:00:00 2001
From: Cerbu Andrei Mihnea
<100320074+andrei-mihnea-cerbu@users.noreply.github.com>
Date: Wed, 10 May 2023 00:47:48 +0300
Subject: [PATCH] facut pana la video 7
---
Lab 1/index.html | 41 --
knowyourfood/.env.example | 3 +
knowyourfood/.gitignore | 4 +
knowyourfood/.htaccess | 14 +
knowyourfood/composer.json | 17 +
knowyourfood/composer.lock | 488 ++++++++++++++++++
knowyourfood/controllers/AuthController.php | 71 +++
knowyourfood/controllers/siteController.php | 32 ++
knowyourfood/core/Application.php | 91 ++++
knowyourfood/core/Controller.php | 26 +
knowyourfood/core/Database.php | 78 +++
knowyourfood/core/DbModel.php | 51 ++
knowyourfood/core/Model.php | 104 ++++
knowyourfood/core/Request.php | 54 ++
knowyourfood/core/Response.php | 13 +
knowyourfood/core/Router.php | 100 ++++
knowyourfood/core/Session.php | 50 ++
.../core/exceptions/ForbiddenException.php | 8 +
.../core/exceptions/NotFoundException.php | 8 +
knowyourfood/core/form/Button.php | 12 +
knowyourfood/core/form/Field.php | 43 ++
knowyourfood/core/form/Form.php | 23 +
.../core/middlewares/AuthMiddleware.php | 21 +
.../core/middlewares/BaseMiddleware.php | 7 +
knowyourfood/dbconfig.php | 10 +
knowyourfood/index.php | 39 ++
knowyourfood/migrations.php | 10 +
knowyourfood/migrations/m01_initial.php | 25 +
.../migrations/m02_add_password_column.php | 17 +
knowyourfood/models/LoginForm.php | 40 ++
knowyourfood/models/User.php | 53 ++
knowyourfood/runtime/.gitignore | 1 +
knowyourfood/views/_error.php | 1 +
knowyourfood/views/contact.php | 17 +
knowyourfood/views/home.php | 2 +
knowyourfood/views/layouts/auth.php | 27 +
knowyourfood/views/layouts/main.php | 50 ++
knowyourfood/views/login.php | 16 +
knowyourfood/views/profile.php | 1 +
knowyourfood/views/register.php | 17 +
40 files changed, 1644 insertions(+), 41 deletions(-)
delete mode 100644 Lab 1/index.html
create mode 100644 knowyourfood/.env.example
create mode 100644 knowyourfood/.gitignore
create mode 100644 knowyourfood/.htaccess
create mode 100644 knowyourfood/composer.json
create mode 100644 knowyourfood/composer.lock
create mode 100644 knowyourfood/controllers/AuthController.php
create mode 100644 knowyourfood/controllers/siteController.php
create mode 100644 knowyourfood/core/Application.php
create mode 100644 knowyourfood/core/Controller.php
create mode 100644 knowyourfood/core/Database.php
create mode 100644 knowyourfood/core/DbModel.php
create mode 100644 knowyourfood/core/Model.php
create mode 100644 knowyourfood/core/Request.php
create mode 100644 knowyourfood/core/Response.php
create mode 100644 knowyourfood/core/Router.php
create mode 100644 knowyourfood/core/Session.php
create mode 100644 knowyourfood/core/exceptions/ForbiddenException.php
create mode 100644 knowyourfood/core/exceptions/NotFoundException.php
create mode 100644 knowyourfood/core/form/Button.php
create mode 100644 knowyourfood/core/form/Field.php
create mode 100644 knowyourfood/core/form/Form.php
create mode 100644 knowyourfood/core/middlewares/AuthMiddleware.php
create mode 100644 knowyourfood/core/middlewares/BaseMiddleware.php
create mode 100644 knowyourfood/dbconfig.php
create mode 100644 knowyourfood/index.php
create mode 100644 knowyourfood/migrations.php
create mode 100644 knowyourfood/migrations/m01_initial.php
create mode 100644 knowyourfood/migrations/m02_add_password_column.php
create mode 100644 knowyourfood/models/LoginForm.php
create mode 100644 knowyourfood/models/User.php
create mode 100644 knowyourfood/runtime/.gitignore
create mode 100644 knowyourfood/views/_error.php
create mode 100644 knowyourfood/views/contact.php
create mode 100644 knowyourfood/views/home.php
create mode 100644 knowyourfood/views/layouts/auth.php
create mode 100644 knowyourfood/views/layouts/main.php
create mode 100644 knowyourfood/views/login.php
create mode 100644 knowyourfood/views/profile.php
create mode 100644 knowyourfood/views/register.php
diff --git a/Lab 1/index.html b/Lab 1/index.html
deleted file mode 100644
index 2f6af9b..0000000
--- a/Lab 1/index.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
- My test page
-
-
- Titlul paginii
- de Andrei Cerbu
- Capitolul 0
-
- Acesta este un paragraf f interesant despre aceasta pagina foarte interesanta
-
-
- Drive to the end of the road
- Turn right
- Go straight across the first two roundabouts
- Turn left at the third roundabout
- The school is on your right, 300 meters up the road
-
-
-
-
-
-
-
-
- I'm creating a link to
- the Mozilla homepage .
-
-
- Chris Mills, Manchester, The Grim North, UK
- Acesta este
- un
- test
-
-
-
-
-
-
diff --git a/knowyourfood/.env.example b/knowyourfood/.env.example
new file mode 100644
index 0000000..e499597
--- /dev/null
+++ b/knowyourfood/.env.example
@@ -0,0 +1,3 @@
+DB_DSN = mysql:host=localhost;port=3306;dbname=Web
+DB_USER = root
+DB_PASSWORD = root
\ No newline at end of file
diff --git a/knowyourfood/.gitignore b/knowyourfood/.gitignore
new file mode 100644
index 0000000..105e5d8
--- /dev/null
+++ b/knowyourfood/.gitignore
@@ -0,0 +1,4 @@
+vendor
+.idea
+dbconfig
+!.gitignore
\ No newline at end of file
diff --git a/knowyourfood/.htaccess b/knowyourfood/.htaccess
new file mode 100644
index 0000000..8d79af1
--- /dev/null
+++ b/knowyourfood/.htaccess
@@ -0,0 +1,14 @@
+ErrorDocument 403 /404.php
+ErrorDocument 404 /404.php
+DirectoryINdex index.php
+
+
+RewriteEngine on
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule ^(.*)$ index.php?page=$1 [L,QSA]
+
+RewriteCond %{REQUEST_URI} !^/$
+RewriteCond %{REQUEST_URI} !^/admin
+RewriteRule .*/ [L,R=301]
+
\ No newline at end of file
diff --git a/knowyourfood/composer.json b/knowyourfood/composer.json
new file mode 100644
index 0000000..ce8993e
--- /dev/null
+++ b/knowyourfood/composer.json
@@ -0,0 +1,17 @@
+{
+ "name": "andrei/knowyourfood",
+ "authors": [
+ {
+ "name": "Cerbu Andrei Mihnea",
+ "email": "andreimihneacerbu@gmail.com"
+ }
+ ],
+ "autoload" : {
+ "psr-4" : {
+ "app\\": "./"
+ }
+ },
+ "require": {
+ "vlucas/phpdotenv": "^5.5"
+ }
+}
diff --git a/knowyourfood/composer.lock b/knowyourfood/composer.lock
new file mode 100644
index 0000000..5a0612e
--- /dev/null
+++ b/knowyourfood/composer.lock
@@ -0,0 +1,488 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "c85ce2bf1fa0099ca65ec02d2a26abb1",
+ "packages": [
+ {
+ "name": "graham-campbell/result-type",
+ "version": "v1.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/GrahamCampbell/Result-Type.git",
+ "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831",
+ "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0",
+ "phpoption/phpoption": "^1.9.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "GrahamCampbell\\ResultType\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ }
+ ],
+ "description": "An Implementation Of The Result Type",
+ "keywords": [
+ "Graham Campbell",
+ "GrahamCampbell",
+ "Result Type",
+ "Result-Type",
+ "result"
+ ],
+ "support": {
+ "issues": "https://github.com/GrahamCampbell/Result-Type/issues",
+ "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-02-25T20:23:15+00:00"
+ },
+ {
+ "name": "phpoption/phpoption",
+ "version": "1.9.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/schmittjoh/php-option.git",
+ "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e",
+ "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": true
+ },
+ "branch-alias": {
+ "dev-master": "1.9-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpOption\\": "src/PhpOption/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Johannes M. Schmitt",
+ "email": "schmittjoh@gmail.com",
+ "homepage": "https://github.com/schmittjoh"
+ },
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ }
+ ],
+ "description": "Option Type for PHP",
+ "keywords": [
+ "language",
+ "option",
+ "php",
+ "type"
+ ],
+ "support": {
+ "issues": "https://github.com/schmittjoh/php-option/issues",
+ "source": "https://github.com/schmittjoh/php-option/tree/1.9.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-02-25T19:38:58+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
+ "reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+ "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.27.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+ "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.27-dev"
+ },
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-11-03T14:55:06+00:00"
+ },
+ {
+ "name": "vlucas/phpdotenv",
+ "version": "v5.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/vlucas/phpdotenv.git",
+ "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7",
+ "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7",
+ "shasum": ""
+ },
+ "require": {
+ "ext-pcre": "*",
+ "graham-campbell/result-type": "^1.0.2",
+ "php": "^7.1.3 || ^8.0",
+ "phpoption/phpoption": "^1.8",
+ "symfony/polyfill-ctype": "^1.23",
+ "symfony/polyfill-mbstring": "^1.23.1",
+ "symfony/polyfill-php80": "^1.23.1"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.4.1",
+ "ext-filter": "*",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25"
+ },
+ "suggest": {
+ "ext-filter": "Required to use the boolean validator."
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": true
+ },
+ "branch-alias": {
+ "dev-master": "5.5-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dotenv\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Vance Lucas",
+ "email": "vance@vancelucas.com",
+ "homepage": "https://github.com/vlucas"
+ }
+ ],
+ "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
+ "keywords": [
+ "dotenv",
+ "env",
+ "environment"
+ ],
+ "support": {
+ "issues": "https://github.com/vlucas/phpdotenv/issues",
+ "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-10-16T01:01:54+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.3.0"
+}
diff --git a/knowyourfood/controllers/AuthController.php b/knowyourfood/controllers/AuthController.php
new file mode 100644
index 0000000..0277e13
--- /dev/null
+++ b/knowyourfood/controllers/AuthController.php
@@ -0,0 +1,71 @@
+registerMiddleware(new AuthMiddleware(['profile']));
+ }
+
+ public function login(Request $request, Response $response){
+ $loginForm = new LoginForm();
+
+ if($request->isPost()){
+ $loginForm->loadData($request->getBody());
+ if($loginForm->validate() && $loginForm->login()){
+ $response->redirect('home');
+ exit;
+ }
+
+ $this->setLayout('auth');
+ return $this->render('login', [
+ 'model' => $loginForm
+ ]);
+ }
+
+ $this->setLayout('auth');
+ return $this->render('login', [
+ 'model' => $loginForm
+ ]);
+ }
+
+ public function register(Request $request, $response){
+ $user = new User();
+
+ if($request->isPost()){
+ $user->loadData($request->getBody());
+
+ if($user->validate() && $user->save()){
+ Application::$app->session->setFlash('success', 'Thanks for registering');
+ $response->redirect('home');
+ exit;
+ }
+
+ $this->setLayout('auth');
+ return $this->render('register', [
+ 'model'=>$user
+ ]);
+ }
+
+ $this->setLayout('auth');
+ return $this->render('register', [
+ 'model'=>$user
+ ]);
+ }
+
+ public function logout($request, $response){
+ Application::$app->logout();
+ $response->redirect('/');
+ }
+
+ public function profile(){
+ return $this->render('profile');
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/controllers/siteController.php b/knowyourfood/controllers/siteController.php
new file mode 100644
index 0000000..39c8554
--- /dev/null
+++ b/knowyourfood/controllers/siteController.php
@@ -0,0 +1,32 @@
+getBody();
+ return 'handling requested data';
+ }
+
+ public function contact(){
+ return $this->render('contact');
+ }
+
+ public function home(){
+ $params = [
+ 'name' => "TheCodeholic"
+ ];
+
+ return $this->render('home', $params);
+ }
+
+ public function profile(){
+ return $this->render('profile');
+ }
+
+ public function _404(){
+ return $this->render('_404');
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/Application.php b/knowyourfood/core/Application.php
new file mode 100644
index 0000000..7206480
--- /dev/null
+++ b/knowyourfood/core/Application.php
@@ -0,0 +1,91 @@
+userClass = $config['userClass'];
+ self::$app = $this;
+
+ $this->request = new Request();
+ $this->response = new Response();
+ $this->router = new Router($this->request, $this->response);
+
+ $this->db = new Database($config['db']);
+ $this->session = new Session();
+
+ $primaryValue = $this->session->get('user');
+ if ($primaryValue) {
+ $userObj = new $this->userClass();
+ $primaryKey = $userObj->primaryKey();
+ $this->user = $userObj->findOne([$primaryKey => $primaryValue]);
+ } else {
+ $this->user = null;
+ }
+ }
+
+ public function setController($controller)
+ {
+ $this->controller = $controller;
+ }
+
+ public function getController()
+ {
+ return $this->controller;
+ }
+
+ public function login(DbModel $user)
+ {
+ $this->user = $user;
+ $primaryKey = $user->primaryKey();
+ $primaryValue = $user->{$primaryKey};
+ $this->session->set('user', $primaryValue);
+ return true;
+ }
+
+ public function logout()
+ {
+ $this->user = null;
+ $this->session->remove('user');
+ }
+
+ public static function isLoggedIn()
+ {
+ return !self::$app->user;
+ }
+
+ public function run()
+ {
+ try{
+ echo $this->router->resolve();
+ }catch(ForbiddenException $e){
+ $this->response->setStatusCode(403);
+ echo $this->router->renderView('_error', [
+ 'exception' => $e
+ ]);
+ }catch(NotFoundException $e){
+ $this->response->setStatusCode(404);
+ echo $this->router->renderView('_error', [
+ 'exception' => $e
+ ]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/Controller.php b/knowyourfood/core/Controller.php
new file mode 100644
index 0000000..fcbb677
--- /dev/null
+++ b/knowyourfood/core/Controller.php
@@ -0,0 +1,26 @@
+router->renderView($view, $params);
+ }
+
+ public function setLayout($layout){
+ $this->layout = $layout;
+ }
+
+ public function registerMiddleware(BaseMiddleware $middleware){
+ $this->middlewares[] = $middleware;
+ }
+
+ public function getMiddlewares(){
+ return $this->middlewares;
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/Database.php b/knowyourfood/core/Database.php
new file mode 100644
index 0000000..ba3a5bd
--- /dev/null
+++ b/knowyourfood/core/Database.php
@@ -0,0 +1,78 @@
+pdo = new \PDO($dsn, $user, $password);
+ $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+ }
+
+ public function applyMigrations(){
+ $this->createMigrationsTable();
+ $appliedMigrations = $this->getAppliedMigrations();
+
+ $newMigrations = [];
+ $files = scandir(Application::$ROOT_DIR.'/migrations');
+ $toApplyMigrations = array_diff($files, $appliedMigrations);
+
+ foreach($toApplyMigrations as $migration){
+ if($migration === '.' || $migration === '..'){
+ continue;
+ }
+
+ require_once Application::$ROOT_DIR.'/migrations/'.$migration;
+ $className = pathinfo($migration, PATHINFO_FILENAME);
+
+ $instance = new $className();
+ $this->log("Applying migration $migration" . PHP_EOL);
+ $instance->up();
+ $this->log("Applied migration $migration" . PHP_EOL);
+
+ $newMigrations[] = $migration;
+ }
+
+ if(!empty($newMigrations)){
+ $this->saveMigrations($newMigrations);
+ }else{
+ $this->log('All migrations are applied');
+ }
+ }
+
+ public function createMigrationsTable(){
+ $this->pdo->exec("
+ CREATE TABLE IF NOT EXISTS migrations (
+ id INT AUTO_INCREMENT,
+ migration varchar(255),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (id)
+ )
+ ENGINE=INNODB;");
+ }
+
+ public function getAppliedMigrations(){
+ $statement = $this->pdo->prepare("SELECT migration FROM migrations");
+ $statement->execute();
+
+ return $statement->fetchAll(\PDO::FETCH_COLUMN);
+ }
+
+ public function saveMigrations(array $migrations){
+ $str = implode(",", array_map(fn($m) => "('$m')", $migrations));
+ $statement = $this->pdo->prepare("INSERT INTO migrations (migration) VALUES $str");
+ $statement->execute();
+ }
+
+ public function prepare($sql){
+ return $this->pdo->prepare($sql);
+ }
+
+ protected function log($message){
+ echo '['.date('Y-m-d H:i:s').'] - '.$message.PHP_EOL;
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/DbModel.php b/knowyourfood/core/DbModel.php
new file mode 100644
index 0000000..b6928c0
--- /dev/null
+++ b/knowyourfood/core/DbModel.php
@@ -0,0 +1,51 @@
+tableName();
+ $attributes = $this->attributes();
+ $params = array_map(fn($attr) => ":$attr", $attributes);
+
+ $statement = self::prepare("INSERT INTO $tableName ("
+ .implode(',', $attributes)
+ .") VALUES ("
+ .implode(',', $params)
+ .")"
+ );
+
+ foreach($attributes as $attribute){
+ $statement->bindValue(":$attribute", $this->{$attribute});
+ }
+
+ $statement->execute();
+ return true;
+ }
+
+ public static function prepare($sql){
+ return Application::$app->db->pdo->prepare($sql);
+ }
+
+ public function findOne($where){
+ $tableName = static::tableName();
+ $attributes = array_keys($where);
+
+ $sql = implode("AND ", array_map(fn($attr) => "$attr = :$attr", $attributes));
+ $statement = self::prepare("SELECT * from $tableName WHERE $sql");
+
+ foreach($where as $key => $item){
+ $statement->bindValue(":$key", $item);
+ }
+
+ $statement->execute();
+
+ return $statement->fetchObject(static::class);
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/Model.php b/knowyourfood/core/Model.php
new file mode 100644
index 0000000..250c137
--- /dev/null
+++ b/knowyourfood/core/Model.php
@@ -0,0 +1,104 @@
+ $value){
+ if(property_exists($this, $key)){
+ $this->{$key} = $value;
+ }
+ }
+ }
+
+ abstract public function rules():array;
+
+ public function labels(): array{
+ return [];
+ }
+
+ public array $errors = [];
+
+ private function addErrorForRule(string $attribute, string $rule, $params =[]){
+ $message = $this->errorMessages()[$rule] ?? '';
+ foreach($params as $key => $value){
+ $message = str_replace("{{$key}}", $value, $message);
+ }
+
+ $this->errors[$attribute][] = $message;
+ }
+
+ public function addError(string $attribute, string $message){
+ $this->errors[$attribute][] = $message;
+ }
+
+ public function errorMessages(){
+ return [
+ self::RULE_REQUIRED => 'This field is required',
+ self::RULE_EMAIL => 'This field must be valid email address',
+ self::RULE_MIN => 'Min length of this field must be {min}',
+ self::RULE_MAX => 'Max length of this field must be {max}',
+ self::RULE_UNIQUE => 'Email already exists'
+ ];
+ }
+
+ public function validate(){
+ foreach($this->rules() as $attribute => $rules){
+ $value = $this->{$attribute};
+ foreach($rules as $rule){
+ $ruleName = $rule;
+
+ if(!is_string($ruleName)){
+ $ruleName = $rule[0];
+ }
+
+ if($ruleName === self::RULE_REQUIRED && !$value){
+ $this->addErrorForRule($attribute, self::RULE_REQUIRED);
+ }
+
+ if($ruleName === self::RULE_EMAIL && !filter_var($value, FILTER_VALIDATE_EMAIL)){
+ $this->addErrorForRule($attribute, self::RULE_EMAIL);
+ }
+
+ if($ruleName === self::RULE_MIN && strlen($value) < $rule['min']){
+ $this->addErrorForRule($attribute, self::RULE_MIN, $rule);
+ }
+
+ if($ruleName === self::RULE_MAX && strlen($value) > $rule['max']){
+ $this->addErrorForRule($attribute, self::RULE_MAX, $rule);
+ }
+
+ if($ruleName === self::RULE_UNIQUE){
+ $className = $rule['class'];
+ $uniqueAttr = $rule['attirubute'] ?? $attribute;
+ $tableName = $className::tableName();
+
+ $statement = Application::$app->db->prepare(("SELECT * FROM $tableName WHERE $uniqueAttr = :attr"));
+ $statement->bindValue(":attr", $value);
+ $statement->execute();
+ $record = $statement->fetchObject();
+
+ if($record){
+ $this->addErrorForRule($attribute, SELF::RULE_UNIQUE);
+ }
+ }
+ }
+ }
+
+ return empty($this->errors);
+ }
+
+ public function hasError($attribute){
+ return $this->errors[$attribute] ?? false;
+ }
+
+ public function getFirstError($attribute){
+ return $this->errors[$attribute][0] ?? '';
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/Request.php b/knowyourfood/core/Request.php
new file mode 100644
index 0000000..b59f214
--- /dev/null
+++ b/knowyourfood/core/Request.php
@@ -0,0 +1,54 @@
+lengthOfRoot = strlen('knowyourfood') + 1;
+ }
+
+ public function getPath(){//identificam din URL pe pagina trebuie accesata
+ $path = $_SERVER['REQUEST_URI'];
+ $path = substr($path, $this->lengthOfRoot);
+
+ $position = strpos($path, '?');
+
+ if(!$position){
+ return $path;
+ }
+
+ return substr($path, 0, $position);
+ }
+
+ public function method(){
+ return strtolower($_SERVER['REQUEST_METHOD']);
+ }
+
+ public function isGet(){
+ return $this->method() === 'get';
+ }
+
+ public function isPost(){
+ return $this->method() === 'post';
+ }
+
+ //bazat pe tipul de request, accesam tuplele key/value pentru a identifica body ul requestului
+ public function getBody(){
+ $body = [];
+ if($this->method() === 'get'){
+ foreach($_GET as $key => $value){
+ $body[$key] = filter_input(INPUT_GET, $key, FILTER_SANITIZE_SPECIAL_CHARS);
+ }
+ }
+
+ if($this->method() === 'post'){
+ foreach($_POST as $key => $value){
+ $body[$key] = filter_input(INPUT_POST, $key, FILTER_SANITIZE_SPECIAL_CHARS);
+ }
+ }
+
+ return $body;
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/Response.php b/knowyourfood/core/Response.php
new file mode 100644
index 0000000..27487ed
--- /dev/null
+++ b/knowyourfood/core/Response.php
@@ -0,0 +1,13 @@
+request = $request;
+ $this->response = $response;
+ }
+
+ public function get($path, $callback)
+ {
+ $this->routes['get'][$path] = $callback;
+ }
+
+ public function post($path, $callback)
+ {
+ $this->routes['post'][$path] = $callback;
+ }
+
+ /*
+ in aceasta functie se identifica path ul catre fisier, metoda (GET/POST) si se identifica un "routes" callback ul (in general controller ul) pe care trebuie sa l returneze
+ astfel, in call_user_function, se ofera clasa de tip constructor si request ul de la user ca dupa controller ul sa se ocupe de restul
+ */
+
+ public function resolve()
+ {
+ $path = $this->request->getPath();
+ $method = $this->request->method();
+ $callback = $this->routes[$method][$path] ?? false;
+
+ if (!$callback) {
+ throw new NotFoundException();
+ }
+
+ if (is_string($callback)) {
+ return $this->renderView($callback);
+ }
+
+ if (is_array($callback)) {
+ $controller = new $callback[0]();
+ Application::$app->controller = $controller;
+ $controller->action = $callback[1];
+ $callback[0] = $controller;
+
+ foreach($controller->getMiddlewares() as $middleware){
+ $middleware->execute();
+ }
+ }
+
+
+ return call_user_func($callback, $this->request, $this->response);
+ }
+
+ //layout ne va ajuta sa identificam ce fel de layout trebuie sa aiba pagina pe care o trimitem (elemente extra in afara de continut: navbar, elemente din baza de date etc)
+ protected function layoutContent()
+ {
+ $layout = Application::$app->layout;
+ if (Application::$app->controller) {
+ $layout = Application::$app->controller->layout;
+ }
+
+ ob_start();
+ include_once Application::$ROOT_DIR . "/views/layouts/$layout.php";
+ return ob_get_clean();
+ }
+
+
+ public function renderView($view, $params = [])
+ {
+ $layoutContent = $this->layoutContent();
+ $viewContent = $this->renderOnlyView($view, $params);
+
+ return str_replace('{{content}}', $viewContent, $layoutContent);
+ }
+
+ public function renderContent($viewContent)
+ {
+ $layoutContent = $this->layoutContent();
+ return str_replace('{{content}}', $viewContent, $layoutContent);
+ }
+
+ protected function renderOnlyView($view, $params)
+ {
+ foreach ($params as $key => $value) {
+ $$key = $value;
+ }
+
+ ob_start();
+ include_once Application::$ROOT_DIR . "/views/$view.php";
+ return ob_get_clean();
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/Session.php b/knowyourfood/core/Session.php
new file mode 100644
index 0000000..a4cf901
--- /dev/null
+++ b/knowyourfood/core/Session.php
@@ -0,0 +1,50 @@
+ &$flashMessage){
+ $flashMessage['remove'] = 'true';
+ }
+
+ $_SESSION[self::FLASH_KEY] = $flashMessages;
+ }
+
+ public function setFlash($key, $message){
+ $_SESSION[self::FLASH_KEY][$key] = [
+ 'value' => $message,
+ 'remove' => 'false'
+ ];
+ }
+
+ public function getFlash($key){
+ return $_SESSION[self::FLASH_KEY][$key]['value'] ?? false;
+ }
+
+ public function set($key, $value){
+ $_SESSION[$key] = $value;
+ }
+
+ public function get($key){
+ return $_SESSION[$key] ?? false;
+ }
+
+ public function remove($key){
+ unset($_SESSION[$key]);
+ }
+
+ public function __destruct(){
+ $flashMessages = $_SESSION[self::FLASH_KEY] ?? [];
+ foreach($flashMessages as $key => &$flashMessage){
+ if($flashMessage['remove']){
+ unset($flashMessages[$key]);
+ }
+ }
+
+ $_SESSION[self::FLASH_KEY] = $flashMessages;
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/exceptions/ForbiddenException.php b/knowyourfood/core/exceptions/ForbiddenException.php
new file mode 100644
index 0000000..b6ed42a
--- /dev/null
+++ b/knowyourfood/core/exceptions/ForbiddenException.php
@@ -0,0 +1,8 @@
+Submit
+ ',
+ );
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/form/Field.php b/knowyourfood/core/form/Field.php
new file mode 100644
index 0000000..2d7379b
--- /dev/null
+++ b/knowyourfood/core/form/Field.php
@@ -0,0 +1,43 @@
+type = self::TYPE_TEXT;
+ $this->model = $model;
+ $this->attribute = $attribute;
+ }
+
+ public function __toString(){
+ return sprintf('
+
+ ',
+ $this->model->labels()[$this->attribute] ?? $this->attribute,
+ $this->type,
+ $this->attribute,
+ $this->model->{$this->attribute},
+ $this->model->hasError($this->attribute) ? ' is invalid' : '',
+ $this->model->getFirstError($this->attribute)
+ );
+ }
+
+ public function passwordField(){
+ $this->type = self::TYPE_PASSWORD;
+ return $this;
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/form/Form.php b/knowyourfood/core/form/Form.php
new file mode 100644
index 0000000..329064f
--- /dev/null
+++ b/knowyourfood/core/form/Form.php
@@ -0,0 +1,23 @@
+', $action, $method);
+ return new Form();
+ }
+
+ public static function end(){
+ echo '';
+ }
+
+ public function field(Model $model, $attribute){
+ return new Field($model, $attribute);
+ }
+
+ public function button(){
+ return new Button();
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/middlewares/AuthMiddleware.php b/knowyourfood/core/middlewares/AuthMiddleware.php
new file mode 100644
index 0000000..aa6a702
--- /dev/null
+++ b/knowyourfood/core/middlewares/AuthMiddleware.php
@@ -0,0 +1,21 @@
+actions = $actions;
+ }
+
+ public function execute(){
+ if(Application::isLoggedIn()){
+ if(empty($this->actions) || in_array(Application::$app->controller->action, $this->actions)){
+ throw new ForbiddenException;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/core/middlewares/BaseMiddleware.php b/knowyourfood/core/middlewares/BaseMiddleware.php
new file mode 100644
index 0000000..4bb4ec1
--- /dev/null
+++ b/knowyourfood/core/middlewares/BaseMiddleware.php
@@ -0,0 +1,7 @@
+ \app\models\User::class,
+ 'db' => [
+ 'dsn' => 'mysql:host=localhost;port=3306;dbname=Web',
+ 'user' => 'root',
+ 'password' => '',
+ ]
+];
\ No newline at end of file
diff --git a/knowyourfood/index.php b/knowyourfood/index.php
new file mode 100644
index 0000000..a5335eb
--- /dev/null
+++ b/knowyourfood/index.php
@@ -0,0 +1,39 @@
+router->get('/', [SiteController::class, '/']);
+
+$app->router->get('/home', [SiteController::class, 'home']);
+
+$app->router->get('/_404', [SiteController::class, '_404']);
+
+$app->router->get('/contact', [SiteController::class, 'contact']);
+$app->router->post('/contact', [SiteController::class, 'handleContact']);
+
+$app->router->get('/login', [AuthController::class, 'login']);
+$app->router->post('/login', [AuthController::class, 'login']);
+
+$app->router->get('/register', [AuthController::class, 'register']);
+$app->router->post('/register', [AuthController::class, 'register']);
+
+$app->router->get('/profile', [AuthController::class, 'profile']);
+$app->router->post('/profile', [AuthController::class, 'profile']);
+
+$app->router->get('/logout', [AuthController::class, 'logout']);
+
+$app->run();
diff --git a/knowyourfood/migrations.php b/knowyourfood/migrations.php
new file mode 100644
index 0000000..8924ef1
--- /dev/null
+++ b/knowyourfood/migrations.php
@@ -0,0 +1,10 @@
+db->applyMigrations();
diff --git a/knowyourfood/migrations/m01_initial.php b/knowyourfood/migrations/m01_initial.php
new file mode 100644
index 0000000..3e5fef3
--- /dev/null
+++ b/knowyourfood/migrations/m01_initial.php
@@ -0,0 +1,25 @@
+db;
+ $SQL = "CREATE TABLE users(
+ id INT AUTO_INCREMENT,
+ email VARCHAR(255) NOT NULL,
+ firstname VARCHAR(255) NOT NULL,
+ lastname VARCHAR(255) NOT NULL,
+ status TINYINT NOT NULL,
+ create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (id)
+ ) Engine=INNODB;
+ ";
+ $db->pdo->exec($SQL);
+ }
+
+ public function down(){
+ $db = Application::$app->db;
+ $SQL = "DROP TABLE users";
+ $db->pdo->exec($SQL);
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/migrations/m02_add_password_column.php b/knowyourfood/migrations/m02_add_password_column.php
new file mode 100644
index 0000000..5061466
--- /dev/null
+++ b/knowyourfood/migrations/m02_add_password_column.php
@@ -0,0 +1,17 @@
+db;
+ $SQL = "ALTER TABLE users ADD COLUMN password VARCHAR(512) NOT NULL";
+ $db->pdo->exec($SQL);
+ }
+
+ public function down(){
+ $db = Application::$app->db;
+ $SQL = "ALTER TABLE users DROP COLUMN password";
+ $db->pdo->exec($SQL);
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/models/LoginForm.php b/knowyourfood/models/LoginForm.php
new file mode 100644
index 0000000..b9e1894
--- /dev/null
+++ b/knowyourfood/models/LoginForm.php
@@ -0,0 +1,40 @@
+ [self::RULE_REQUIRED, self::RULE_EMAIL],
+ 'password' => [self::RULE_REQUIRED]
+ ];
+ }
+
+ public function labels():array {
+ return [
+ 'email' => 'Email',
+ 'password' => 'Password'
+ ];
+ }
+
+ public function login(){
+ $user = new User();
+ $user = $user->findOne(['email' => $this->email]);
+ if(!$user){
+ $this->addError('email', 'User does not exist with this email');
+ return false;
+ }
+
+ if(!password_verify($this->password, $user->password)){
+ $this->addError('password', 'Incorrect password');
+ return false;
+ }
+
+ return Application::$app->login($user);
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/models/User.php b/knowyourfood/models/User.php
new file mode 100644
index 0000000..281b244
--- /dev/null
+++ b/knowyourfood/models/User.php
@@ -0,0 +1,53 @@
+status = self::STATUS_INACTIVE;
+ $this->password = password_hash($this->password, PASSWORD_DEFAULT);
+ return parent::save();
+ }
+
+ public function tableName(): string{
+ return 'users';
+ }
+
+ public function rules(): array{
+ return [
+ 'firstname' => [self::RULE_REQUIRED],
+ 'lastname' => [self::RULE_REQUIRED],
+ 'email' => [self::RULE_REQUIRED, self::RULE_EMAIL, [self::RULE_UNIQUE, 'class' => self::class]],
+ 'password' => [self::RULE_REQUIRED, [self::RULE_MIN, 'min' => 8], [self::RULE_MAX, 'max' => 15]]
+ ];
+ }
+
+ public function primaryKey(): string{
+ return 'id';
+ }
+
+ public function labels():array {
+ return [
+ 'firstname' => 'First name',
+ 'lastname' => 'Last name',
+ 'email' => 'Email',
+ 'password' => 'Password'
+ ];
+ }
+
+ public function attributes(): array{
+ return ['firstname', 'lastname', 'email', 'password', 'status'];
+ }
+}
\ No newline at end of file
diff --git a/knowyourfood/runtime/.gitignore b/knowyourfood/runtime/.gitignore
new file mode 100644
index 0000000..b722e9e
--- /dev/null
+++ b/knowyourfood/runtime/.gitignore
@@ -0,0 +1 @@
+!.gitignore
\ No newline at end of file
diff --git a/knowyourfood/views/_error.php b/knowyourfood/views/_error.php
new file mode 100644
index 0000000..53bbef0
--- /dev/null
+++ b/knowyourfood/views/_error.php
@@ -0,0 +1 @@
+getCode() ?> - getMessage();?>
\ No newline at end of file
diff --git a/knowyourfood/views/contact.php b/knowyourfood/views/contact.php
new file mode 100644
index 0000000..46dd3fa
--- /dev/null
+++ b/knowyourfood/views/contact.php
@@ -0,0 +1,17 @@
+Contact
+
+
\ No newline at end of file
diff --git a/knowyourfood/views/home.php b/knowyourfood/views/home.php
new file mode 100644
index 0000000..1a1f5b0
--- /dev/null
+++ b/knowyourfood/views/home.php
@@ -0,0 +1,2 @@
+Home
+ Welcome to our site!
\ No newline at end of file
diff --git a/knowyourfood/views/layouts/auth.php b/knowyourfood/views/layouts/auth.php
new file mode 100644
index 0000000..a8dc0b9
--- /dev/null
+++ b/knowyourfood/views/layouts/auth.php
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+ Bootstrap demo
+
+
+
+
+
+ session->getFlash('success')): ?>
+
+ session->getFlash('success');
+ ?>
+
+
+ {{content}}
+
+
+
+
+
\ No newline at end of file
diff --git a/knowyourfood/views/layouts/main.php b/knowyourfood/views/layouts/main.php
new file mode 100644
index 0000000..ea1273d
--- /dev/null
+++ b/knowyourfood/views/layouts/main.php
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+ Bootstrap demo
+
+
+
+
+
+
+
+
+
+ {{content}}
+
+
+
+
+
\ No newline at end of file
diff --git a/knowyourfood/views/login.php b/knowyourfood/views/login.php
new file mode 100644
index 0000000..9166582
--- /dev/null
+++ b/knowyourfood/views/login.php
@@ -0,0 +1,16 @@
+Login
+
+field($model, 'email');
+echo $form->field($model, 'password')->passwordField();
+
+echo $form->button();
+
+Form::end()
+?>
+
diff --git a/knowyourfood/views/profile.php b/knowyourfood/views/profile.php
new file mode 100644
index 0000000..e241fdb
--- /dev/null
+++ b/knowyourfood/views/profile.php
@@ -0,0 +1 @@
+Profile
\ No newline at end of file
diff --git a/knowyourfood/views/register.php b/knowyourfood/views/register.php
new file mode 100644
index 0000000..d63fcf7
--- /dev/null
+++ b/knowyourfood/views/register.php
@@ -0,0 +1,17 @@
+Create An Account
+field($model, 'firstname');
+echo $form->field($model, 'lastname');
+echo $form->field($model, 'email');
+echo $form->field($model, 'password')->passwordField();
+
+echo $form->button();
+
+Form::end()
+?>
+