├── .htaccess
├── CHANGELOG.md
├── README.md
├── _tutorial
├── donate-with-flattr.png
├── donate-with-paypal.png
├── tutorial-part-01.png
├── tutorial-part-02.png
├── tutorial-part-03.png
├── tutorial-part-04.png
└── tutorial-part-05.png
├── application
├── .htaccess
├── _install
│ ├── 01-create-database.sql
│ ├── 02-create-table-song.sql
│ └── 03-insert-demo-data-into-table-song.sql
├── config
│ └── config.php
├── controller
│ ├── home.php
│ └── songs.php
├── libs
│ ├── application.php
│ └── controller.php
├── models
│ ├── songsmodel.php
│ └── statsmodel.php
└── views
│ ├── _templates
│ └── base.twig
│ ├── home
│ ├── example_one.twig
│ ├── example_two.twig
│ └── index.twig
│ └── songs
│ └── index.twig
├── composer.json
├── index.php
└── public
├── css
└── style.css
├── img
└── demo-image.png
├── js
└── application.js
└── scss
├── modules
└── _colors.scss
└── style.scss
/.htaccess:
--------------------------------------------------------------------------------
1 | # Necessary to prevent problems when using a controller named "index" and having a root index.php
2 | # more here: http://httpd.apache.org/docs/2.2/content-negotiation.html
3 | Options -MultiViews
4 |
5 | # Activates URL rewriting (like myproject.com/controller/action/1/2/3)
6 | RewriteEngine On
7 |
8 | # Disallows others to look directly into /public/ folder
9 | Options -Indexes
10 |
11 | # When using the script within a sub-folder, put this path here, like /mysubfolder/
12 | # If your app is in the root of your web folder, then leave it commented out
13 | RewriteBase /php-mvc-advanced/
14 |
15 | # General rewrite rules
16 | RewriteCond %{REQUEST_FILENAME} !-d
17 | RewriteCond %{REQUEST_FILENAME} !-f
18 | RewriteCond %{REQUEST_FILENAME} !-l
19 |
20 | RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
21 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | CHANGE LOG
2 | ==========
3 |
4 | **January 4th 2014**
5 | - fixed htaccess issue when there's a controller named "index" and a base index.php (which collide)
6 |
7 | **December 29th 2013**
8 | - fixed case-sensitive model file loading (thanks "grrnikos")
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP-MVC-ADVANCED
2 |
3 | *Note: This is the same like [panique/php-mvc](https://github.com/panique/php-mvc), but with additional features.*
4 | *This repo is in development, more to come...*
5 |
6 | ### New in the advanced version:
7 |
8 | 1. Twig
9 | 2. SASS-compiler in PHP ! The SASS compiling is optional, you can delete the scss folder and just use classic .css, too.
10 | I've used https://github.com/panique/laravel-sass here.
11 |
12 | An extremely simple and easy to understand MVC skeleton application, reduced to the max.
13 | Everything is **as simple as possible**, as **manually as possible** and as readable as possible.
14 | This project is - by intention - NOT a full framework, it's a bare-bone structure, written in
15 | purely native PHP ! The php-mvc skeleton tries to be the extremely slimmed down opposite of big frameworks
16 | like Zend2, Symfony or Laravel.
17 |
18 | [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=P5YLUK4MW3LDG)
19 |
20 | [](https://flattr.com/submit/auto?user_id=panique&url=https%3A%2F%2Fgithub.com%2Fpanique%2Fphp-mvc-advanced)
21 |
22 | ## Why does this project exist ?
23 |
24 | One of the biggest question in the PHP world is "How do I build an application ?".
25 | It's hard to find a good base, a good file structure and useful information on that, but at the same time
26 | there are masses of frameworks that might be really good, but really hard to understand, hard to use and extremely
27 | complex. This project tries to be some kind of naked skeleton bare-bone for quick application building,
28 | especially for the not-so-advanced coder.
29 |
30 | ### Goals of this project:
31 |
32 | - give people a clean base MVC structure to build a modern PHP application with
33 | - teach people the basics of the Model-View-Controller architecture
34 | - encourage people to code according to PSR 1/2 coding guidelines
35 | - promote the usage of PDO
36 | - promote the usage of external libraries via Composer
37 | - promote development with max. error reporting
38 | - promote to comment code
39 | - promote the usage of OOP code
40 | - using only native PHP code, so people don't have to learn a framework
41 |
42 | ## Support forum
43 |
44 | If you are stuck with something even AFTER reading and following the install tutorials and the quick-manual, then feel
45 | free to ask in the [official forum](http://forum.php-mvc.net/). Note that this forum is fresh and new, more content
46 | will come over time.
47 |
48 | ## Installation
49 |
50 | 1. First, install Composer ([How to install Composer on Ubuntu, Debian or Windows 7/8](http://www.dev-metal.com/install-update-composer-windows-7-ubuntu-debian-centos/)).
51 | That's some kind of PHP standard now and there's no reason to work without Composer. If you think "I don't need/want
52 | Composer" then you are doing something seriously wrong!
53 |
54 | 2. Copy this repo into a public accessible folder on your server.
55 | Common techniques are a) downloading and extracting the .zip / .tgz by hand, b) cloning the repo with git (into var/www)
56 |
57 | ```
58 | git clone https://github.com/panique/php-mvc-advanced.git /var/www
59 | ```
60 |
61 | or c) getting the repo via Composer (here we copy into var/www)
62 |
63 | ```
64 | composer create-project panique/php-mvc-advanced /var/www dev-master
65 | ```
66 |
67 | 3. Install mod_rewrite, for example by following this guideline:
68 | [How to install mod_rewrite in Ubuntu](http://www.dev-metal.com/enable-mod_rewrite-ubuntu-12-04-lts/)
69 |
70 | 4. Run the SQL statements in the *application/_install* folder.
71 |
72 | 5. Change the .htaccess file from
73 | ```
74 | RewriteBase /php-mvc-advanced/
75 | ```
76 | to where you put this project, relative to the web root folder (usually /var/www). So when you put this project into
77 | the web root, like directly in /var/www, then the line should look like or can be commented out:
78 | ```
79 | RewriteBase /
80 | ```
81 | If you have put the project into a sub-folder, then put the name of the sub-folder here:
82 | ```
83 | RewriteBase /sub-folder/
84 | ```
85 |
86 | 6. Edit the *application/config/config.php*, change this line
87 | ```php
88 | define('URL', 'http://127.0.0.1/php-mvc-advanced/');
89 | ```
90 | to where your project is. Real domain, IP or 127.0.0.1 when developing locally. Make sure you put the sub-folder
91 | in here (when installing in a sub-folder) too, also don't forget the trailing slash !
92 |
93 | 7. Edit the *application/config/config.php*, change these lines
94 | ```php
95 | define('DB_TYPE', 'mysql');
96 | define('DB_HOST', '127.0.0.1');
97 | define('DB_NAME', 'php-mvc');
98 | define('DB_USER', 'root');
99 | define('DB_PASS', 'mysql');
100 | ```
101 | to your database credentials. If you don't have an empty database, create one. Only change the type `mysql` if you
102 | know what you are doing.
103 |
104 | 8. Run `composer install` on the command line while being in the root of your project.
105 |
106 | ## A quickstart tutorial
107 |
108 | You can also find these tutorial pictures in the *_tutorial* folder.
109 | **Note:** **These files are not up-to-date, as Twig and SASS support are not mentioned here. I'll update the tutorial
110 | when there's time.**
111 |
112 | 
113 | 
114 | 
115 | 
116 | 
117 |
118 | ## You like what you see ?
119 |
120 | Then please also have a look on ...
121 |
122 | #### My other project php-login
123 |
124 | A collection of 4 similar login scripts for PHP, from a super-simple one-file
125 | script with a SQLite one-file to a highly professional MVC frameworks solution. All scripts use the most advanced
126 | hashing algorithms possible in PHP, exactly like the PHP core developers want you to use them.
127 |
128 | https://github.com/panique/php-login (full MVC framework)
129 |
130 | https://github.com/panique/php-login-minimal (minimal)
131 |
132 | https://github.com/panique/php-login-advanced (advanced)
133 |
134 | https://github.com/panique/php-login-one-file (one-file)
135 |
136 | #### My PHP and frontend blog
137 |
138 | Lots of non-boring development stuff and tutorials there.
139 |
140 | http://www.dev-metal.com
141 |
142 | ## Useful information
143 |
144 | 1. SQLite does not have a rowCount() method (!). Keep that in mind in case you use SQLite.
145 |
146 | 2. Don't use the same name for class and method, as this might trigger an (unintended) *__construct* of the class.
147 | This is really weird behaviour, but documented here: [php.net - Constructors and Destructors](http://php.net/manual/en/language.oop5.decon.php).
148 |
149 | ## Add external libraries via Composer
150 |
151 | To add external libraries/tools/whatever into your project in an extremely clean way, simply add a line with the
152 | repo name and version to the composer.json! Take a look on these tutorials if you want to get into Composer:
153 | [How to install (and update) Composer on Windows 7 or Ubuntu / Debian](http://www.dev-metal.com/install-update-composer-windows-7-ubuntu-debian-centos/)
154 | and [Getting started with Composer](http://www.dev-metal.com/getting-started-composer/).
155 |
156 | ## License
157 |
158 | This project is licensed under the MIT License.
159 | This means you can use and modify it for free in private or commercial projects.
160 |
161 | ## Contribute
162 |
163 | Please commit into the develop branch (which holds the in-development version), not into master branch
164 | (which holds the tested and stable version).
165 |
166 | ## Support / Donate
167 |
168 | If you think this script is useful and saves you a lot of work, then think about supporting the project:
169 |
170 | 1. Donate via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=P5YLUK4MW3LDG), [GitTip](https://www.gittip.com/Panique/) or [Flattr](https://flattr.com/submit/auto?user_id=panique&url=https%3A%2F%2Fgithub.com%2Fpanique%2Fphp-mvc-advanced).
171 | 2. Rent your next server at [A2 Hosting](http://www.a2hosting.com/4471.html) or [DigitalOcean](https://www.digitalocean.com/?refcode=40d978532a20).
172 | 3. Contribute to this project. Feel free to improve this project with your skills.
173 | 4. Spread the word: Tell others about this project.
174 |
175 | ## Linked music tracks in the demo application
176 |
177 | The linked tracks in this naked application are just some of my personal favourites of the last few months.
178 | I think it's always a good idea to fill boring nerd-code stuff with quality culture.
179 |
--------------------------------------------------------------------------------
/_tutorial/donate-with-flattr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SourceCode/php-mvc-advanced/ce4b0cf48f7be5ec60823a1c59ed62e99cb38933/_tutorial/donate-with-flattr.png
--------------------------------------------------------------------------------
/_tutorial/donate-with-paypal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SourceCode/php-mvc-advanced/ce4b0cf48f7be5ec60823a1c59ed62e99cb38933/_tutorial/donate-with-paypal.png
--------------------------------------------------------------------------------
/_tutorial/tutorial-part-01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SourceCode/php-mvc-advanced/ce4b0cf48f7be5ec60823a1c59ed62e99cb38933/_tutorial/tutorial-part-01.png
--------------------------------------------------------------------------------
/_tutorial/tutorial-part-02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SourceCode/php-mvc-advanced/ce4b0cf48f7be5ec60823a1c59ed62e99cb38933/_tutorial/tutorial-part-02.png
--------------------------------------------------------------------------------
/_tutorial/tutorial-part-03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SourceCode/php-mvc-advanced/ce4b0cf48f7be5ec60823a1c59ed62e99cb38933/_tutorial/tutorial-part-03.png
--------------------------------------------------------------------------------
/_tutorial/tutorial-part-04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SourceCode/php-mvc-advanced/ce4b0cf48f7be5ec60823a1c59ed62e99cb38933/_tutorial/tutorial-part-04.png
--------------------------------------------------------------------------------
/_tutorial/tutorial-part-05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SourceCode/php-mvc-advanced/ce4b0cf48f7be5ec60823a1c59ed62e99cb38933/_tutorial/tutorial-part-05.png
--------------------------------------------------------------------------------
/application/.htaccess:
--------------------------------------------------------------------------------
1 |
';
89 | // echo 'Action: ' . $this->url_action . '
';
90 | // echo 'Parameter 1: ' . $this->url_parameter_1 . '
';
91 | // echo 'Parameter 2: ' . $this->url_parameter_2 . '
';
92 | // echo 'Parameter 3: ' . $this->url_parameter_3 . '
';
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/application/libs/controller.php:
--------------------------------------------------------------------------------
1 | openDatabaseConnection();
20 | }
21 |
22 | /**
23 | * Open the database connection with the credentials from application/config/config.php
24 | */
25 | private function openDatabaseConnection()
26 | {
27 | // set the (optional) options of the PDO connection. in this case, we set the fetch mode to
28 | // "objects", which means all results will be objects, like this: $result->user_name !
29 | // For example, fetch mode FETCH_ASSOC would return results like this: $result["user_name] !
30 | // @see http://www.php.net/manual/en/pdostatement.fetch.php
31 | $options = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING);
32 |
33 | // generate a database connection, using the PDO connector
34 | // @see http://net.tutsplus.com/tutorials/php/why-you-should-be-using-phps-pdo-for-database-access/
35 | $this->db = new PDO(DB_TYPE . ':host=' . DB_HOST . ';dbname=' . DB_NAME, DB_USER, DB_PASS, $options);
36 | }
37 |
38 | /**
39 | * Load the model with the given name.
40 | * loadModel("SongModel") would include models/songmodel.php and create the object in the controller, like this:
41 | * $songs_model = $this->loadModel('SongsModel');
42 | * Note that the model class name is written in "CamelCase", the model's filename is the same in lowercase letters
43 | * @param string $model_name The name of the model
44 | * @return object model
45 | */
46 | public function loadModel($model_name)
47 | {
48 | require 'application/models/' . strtolower($model_name) . '.php';
49 | // return new model (and pass the database connection to the model)
50 | return new $model_name($this->db);
51 | }
52 |
53 | public function render($view, $data_array = array())
54 | {
55 | // load Twig, the template engine
56 | // @see http://twig.sensiolabs.org
57 | $twig_loader = new Twig_Loader_Filesystem(PATH_VIEWS);
58 | $twig = new Twig_Environment($twig_loader);
59 |
60 | // render a view while passing the to-be-rendered data
61 | echo $twig->render($view . PATH_VIEW_FILE_TYPE, $data_array);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/application/models/songsmodel.php:
--------------------------------------------------------------------------------
1 | db = $db;
12 | } catch (PDOException $e) {
13 | exit('Database connection could not be established.');
14 | }
15 | }
16 |
17 | /**
18 | * Get all songs from database
19 | */
20 | public function getAllSongs()
21 | {
22 | $sql = "SELECT id, artist, track, link FROM song";
23 | $query = $this->db->prepare($sql);
24 | $query->execute();
25 |
26 | // fetchAll() is the PDO method that gets all result rows, here in object-style because we defined this in
27 | // libs/controller.php! If you prefer to get an associative array as the result, then do
28 | // $query->fetchAll(PDO::FETCH_ASSOC); or change libs/controller.php's PDO options to
29 | // $options = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ...
30 | return $query->fetchAll();
31 | }
32 |
33 | /**
34 | * Add a song to database
35 | * @param string $artist Artist
36 | * @param string $track Track
37 | * @param string $link Link
38 | */
39 | public function addSong($artist, $track, $link)
40 | {
41 | // clean the input from javascript code for example
42 | $artist = strip_tags($artist);
43 | $track = strip_tags($track);
44 | $link = strip_tags($link);
45 |
46 | $sql = "INSERT INTO song (artist, track, link) VALUES (:artist, :track, :link)";
47 | $query = $this->db->prepare($sql);
48 | $query->execute(array(':artist' => $artist, ':track' => $track, ':link' => $link));
49 | }
50 |
51 | /**
52 | * Delete a song in the database
53 | * Please note: this is just an example! In a real application you would not simply let everybody
54 | * add/update/delete stuff!
55 | * @param int $song_id Id of song
56 | */
57 | public function deleteSong($song_id)
58 | {
59 | $sql = "DELETE FROM song WHERE id = :song_id";
60 | $query = $this->db->prepare($sql);
61 | $query->execute(array(':song_id' => $song_id));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/application/models/statsmodel.php:
--------------------------------------------------------------------------------
1 | db = $db;
12 | } catch (PDOException $e) {
13 | exit('Database connection could not be established.');
14 | }
15 | }
16 |
17 | /**
18 | * Get simple "stats". This is just a simple demo to show
19 | * how to use more than one model in a controller (see application/controller/songs.php for more)
20 | */
21 | public function getAmountOfSongs()
22 | {
23 | $sql = "SELECT COUNT(id) AS amount_of_songs FROM song";
24 | $query = $this->db->prepare($sql);
25 | $query->execute();
26 |
27 | // fetchAll() is the PDO method that gets all result rows
28 | return $query->fetch()->amount_of_songs;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/application/views/_templates/base.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
In a real application this could be a normal page.
6 |In a real application this could be a normal page.
6 |In a real application this could be the homepage.
6 |Id | 29 |Artist | 30 |Track | 31 |Link | 32 |DELETE | 33 |
{{ song.id }} | 39 |{{ song.artist }} | 40 |{{ song.track }} | 41 |42 | {% if song.link %} 43 | {{ song.link }} 44 | {% endif %} 45 | | 46 |47 | x 48 | | 49 |