Hello to you, habrayuzer!Today I want to present to your court a certain amount of bydlokoda, which I proudly call “my own framework”. Under the cat, you will see a large number of bicycles with square wheels, ridiculous comments on the code, a fairly fair amount of absolutely meaningless text, and many other similar horrors. Whom it didn’t scare - click on the button “Read more”.
At the moment, the framework has undergone some changes, so not all examples from the article can work, and the framework structure will be somewhat different.')
Small preface
At the moment I am studying in a college near Moscow in my third year in the specialty "Software of computing equipment and automated systems". In the second semester of the third year, we were told something like “Now you are ready”, and we have a new subject - computer network software, or, in other words, we started to learn HTML. A little earlier, one of my classmates began to study HTML, CSS and PHP and achieved some success in this - he made his online store. Once I asked him to show me the source, and was not particularly surprised - except for a certain number of inclusions, all of PHP consisted in expanding files (the basket and all the other gadgets that made up the “shop part” were on Ecommtools com pct).
Seeing this, I just could not remain silent and began to rub him in about MVC, about the base and all that jazz. Naturally, he understood almost nothing of my words (I, as you can see, explain not very well). But just a couple of weeks turned up the above-mentioned subject. Our teacher taught him before, and I agreed with him without any problems that we would be studying with a fellow student on our own. As a result, for a certain number of pairs, the site was rewritten from scratch by my own hands, and my fellow student, besides the new site, received an impressive store of knowledge (I hope useful).
I threw out the source codes for ourselves (we worked on its laptop) and at home I picked further, added functionality, refactored, reworked something again. As a result, I got some kind of framework, which quite successfully runs several projects. Now I decided to open my creation to the people, so that he would decide to throw me web programming or develop my brainchild further. And you never know, suddenly someone come in handy.
Framework Features
1.
Low weight. Well, very small. In unpacked form, it takes about 34 kilobytes (If you delete the standard greeting text and the logo image)
2.
Lack of OOP. I don’t know if it’s an advantage or vice versa, but in theory OOP applications eat much more resources than applications written in a procedural style. (What kind of objects could we talk about when the person to whom this was demonstrated first of all did not fully understand the basics)
3.
MVC. Well, here I think nothing to explain.
4.
Routing. Routing (in my opinion) is very easy to use, but at the same time quite flexible in configuration, although it needs some work. The default routing is Controller / Action / Param-1 / Value-1 / Param-2 / Value-2.
5.
JSON and XML. In order to get an answer in one of these formats, you just need to add at the end of the address ".json" or ".xml", respectively. That is, if at the address "/ goods / view / id / 3" you receive information about the product, then at the address "/goods/view/id/3.json" you can get it in JSON format.
6.
Functional. There is little functionality out of the box, as the community is only 1 person (me). So far, there is an inferior soap distribution script and quite working user authorization using sessions.
7.
Backtrace. Present. Disabled if the application is not in debug mode.
8.
DB. Only MySQL is supported. This is a minus, but at the moment not critical.
9.
ORM. It cannot be here, since OOP is absent in the framework in principle. But there is some sort of binding over the database.
10.
ACL. It is absent at the moment, but in the plans for the development of the framework (and it will only develop if you receive at least a few positive reviews) comes first.
11.
DEBUG mode. Present, affects the output of some errors, the output of the backtrace, the used configs.
Framework structure
Scheme
| - app /
| - config /
| - debug /
| - * .php
| - * .php
| - controllers /
| - * /
| - * Action.php
| - models /
| - * .php
| - views /
| - custom /
| - * .phtml
| - layout /
| - default.phtml
| - scripts /
| - * /
| - * .phtml
| - library /
| - functions /
| - default.php
| - * .php
| - init /
| - configs.php
| - init.php
| - predispatch.php
| - models /
| - basemodel.php
| - router /
| - router.php
| - include.php
| - files /
| - *
| - index.php
| - .htaccess
Consider everything in order
Let's start, perhaps, from the bottom, that is, with the
.htaccess file. Here are its contents:
RewriteEngine on RewriteCond %{REQUEST_URI} !/files RewriteRule .*$ index.php [L] AddDefaultCharset UTF-8
That is, any request other than starting with "/ files" will be redirected to index.php. In fact, this is not the only and far from the best version of a revwrite, but I have already got used to working with it and have decided not to change it yet. Well, the default encoding: UTF-8. Nothing more interesting, we will not see here.
Let's
go to
index.php . Here are its contents:
Here, I think, nothing needs to be explained, since all the actions are commented.
Folder
files . As you may remember, only this folder can be accessed “directly,” that is, bypassing
index.php . Accordingly, it is precisely in it that such resources as style sheets, JavaScript files, images, and so on are added.
Next, consider the
app folder. This, as the name implies, is the folder of the application itself. It contains application configuration (
config folder), controllers (
controllers folder) and actions of these controllers, models (
models folder) and views (
views folder).
The controller is a folder containing PHP files - actions. The folder name must be in camelCase. The name of the action file should also be in camelCase, but with the postfix "Action" at the end.
That is, a controller with the name
“goods” and actions
“index” ,
“show” ,
“new” ,
“edit” and
“delete” in the file system would look like this:
| - controllers /
| - goods /
| - indexAction.php
| - showAction.php
| - newAction.php
| - editAction.php
| - deleteAction.php
Optionally, any controller can contain a
_init.php file. The contents of this file will be executed before any action is launched in this controller.
Now about models (folder
“models” ). In my understanding, the model should return data that is already ready for use, which will no longer have to be additionally processed in the controller. That is, for example, you need to bring in the block 5 latest news. You can make a request directly from the controller, but in my understanding it would be more correct to reduce the code to this:
loadModel('news'); $_view['last_news'] = getLastNews(5);
Here, the
getLastNews()
method is declared in the
“news” model and returns an array of data that is left just to be formatted and output in the view.
The model itself is a collection of methods combined into one file.
Let's move on to the views - the folder
"views" . It contains 3 subdirectories:
custom ,
layout ,
scripts . All views have the extension
.phtml .
The folder
"layout" stores all the layouts of the application. There is nothing special to explain here. To output content to layout, the
content()
method is used.
The
scripts folder stores actions for the action. The structure is as follows:
scripts / <controller name> / <action name> .phtml .
Well, in the folder
"custom" are all the other views that are not suitable for the first two folders. For example, there may be sidebar blocks, a separate header, and so on.
Finally, the
“config” folder. It contains a
debug subdirectory where configs can be duplicated. If the constant
APP_DEBUG is true, the application will try to find the requested config in the
config / debug folder, and only if there is no
config there, will it connect it from the
config folder. If the application is
not in
debug mode, the
debug folder will be ignored.
All configs are PHP files that return an array, that is, their contents are something like this:
return array(
Folder
"library" . In essence, this is the framework itself. Therefore, I will not consider it in detail (ashamed). I will touch on only a few details.
Folder
"functions" . If you need to expand the functionality of the framework, then you are here. PHP files from this folder are loaded using the
loadFunction($fnc)
method. Autoload not yet, but in the near future will be. Separately, you should pay attention to the file
«default.php» . It contains all the basic functionality of the framework and connects when the application starts.
In the folder
“init” we are interested in the file
“init.php” . It is executed each time the application is started, and dynamic configuration should be performed there.
In the folder
“models” pay attention to the file
“basemodel.php” . This is the very binding for MySQL, about which I wrote above.
Working with the framework
Let's try to create a small application on this framework. Let it be a catalog of books you read.
Creating and setting up a project
Downloading the framework from one of the links:
github.com/SazereS/NoNameFramework.git yamesh.sk/d/ZAnE6Yq_4kgBe troloload.ru/f/5979_nonameframework.zip dl.dropboxusercontent.com/u/85783372/NoNoUnpack the framework into the site folder. Our application will use the database, so we immediately create it in the way that suits you.
Go to
app / config and open the
mysql.php file. We replace the default values with our own. I did this:
Next, open
library / init / init.php and check what would be the line
initDb();
was uncommented.
At this initial setting can be considered complete.
Creating a CRUD Application
First we need a table in the database. Let it be called
books and consists of columns
id, title, author, comment, mark . To do this, execute this query to the database we created:
CREATE TABLE `books` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `title` VARCHAR(80) NOT NULL, `author` VARCHAR(40) NOT NULL, `comment` TEXT NOT NULL, `mark` INT NOT NULL, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=MyISAM;
We also need a model. To do this, create a file in the
models folder
books.php .
Create a
books controller. To do this, in the
app / controllers folder, create the
books folder.
CRUD - an abbreviation of Create Read Update Delete (Create, Read, Update, Delete). It is these actions that our controller will produce. Let's create for each of these actions a corresponding action. Let the names of these actions be
new ,
view ,
edit, and
delete . In addition, we need an action to display a list of all books. We will call it
"index" . To do this, create five files in the
books folder:
indexAction.php, newAction.php, viewAction.php, editAction.php and deleteAction.php.Some of the actions need
view files. We will create them as needed. Let's start with the
new action. To do this, in the
views / scripts folder, create a subfolder of
books (by the name of the controller) and in it the file
new.phtml (by the name of the action). Temporarily insert the following text into it:
books/new
. Now we will launch your web server and go to the address “http: // <YOUR SITE ADDRESS> / books / new”. There we should see the text
books / new .
Let's go back to our action. Open the file
newAction.php and add the following code there:
<?php
Notice the $ _view variable. It is with the help of her controller communicates with the presentation. All values passed to it will be available from both views and layouts.
In addition, we are interested in the function
newBook()
. In fact, this function does not yet exist. Let's create it. To do this, open our model (
books.php ) and paste the following code into it:
<?php function newBook($array) {
On this work with the model and the action is completed, go to the twist. We insert the following code there:
<form method="post"> <label> : </label> <br /> <input type="text" name="title" value="<?=$_view['form']['title'] ?>" /> <br /> <label>: </label> <br /> <input type="text" name="author" value="<?=$_view['form']['author'] ?>" /> <br /> <label> : </label> <br /> <textarea name="comment"><?=$_view['form']['comment'] ?></textarea> <br /> <label> ( 1 10): </label> <br /> <input type="text" name="mark" value="<?=$_view['form']['mark'] ?>" /> <br /> <button type="submit"></button> </form>
Now you can refresh the page in the browser and try to add data through the form. Data is added, but after the redirect, a message appears about the missing view. Let's create it (the file will be called
index.phtml ).
Now go to the action
index . Insert the code there:
<?php
As you can see, we again used the nonexistent function
getAllBooks()
. We add these lines to our model:
function getAllBooks() {
Go to the view and paste it there:
<?php if($_view['books']) foreach ($_view['books'] as $v) { ?> #<?=$v['id'] ?>: <a href="<?=baseUrl('books/view/id/'.$v['id']) ?>"><?=$v['title'] ?></a><br /> <?php } ?>
Here we are faced with a new for us function
baseUrl()
. It is needed to create correct links. In this case, you can do without it by making a link from the root of the site, but it eliminates unnecessary trouble, especially those with a site located at an address like
localhost / framework / test .
With this action you can finish. Moving on to the next action in the logical chain of action -
view . Immediately I will give here all the code, since by analogy everything is clear.
viewAction.php:
<?php loadModel('books');
Supplement for the model:
function getBook($id) {
Presentation (do not forget to create it):
<strong>: </strong> <?=$_view['book']['title'] ?><br /> <strong>: </strong> <?=$_view['book']['author'] ?><br /> <strong>: </strong><br /> <?=$_view['book']['comment'] ?><br /> <strong>: </strong> <?=$_view['book']['mark'] ?> 10<br /> <a href="<?=baseUrl('books/edit/id/'.$_view['book']['id']) ?>"></a><br /> <a href="<?=baseUrl('books/delete/id/'.$_view['book']['id']) ?>"></a><br />
Now
editActioneditAction.php:
loadModel('books');
Please note that we are not creating a view for this action, since we use the form we already have from
new.phtmlAdd a function to the model:
function updateBook($id, $values) {
And finally, the last action -
delete .
deleteAction.php:
loadModel('books'); deleteBook(getParam('id')); redirect('books');
Function for model:
function deleteBook($id) {
This action does not need a presentation in principle, since it redirects you to the index action in any case.
Now you can slightly improve the resulting code. As you can see, each time, at the beginning of the action, we performed the same operation -
loadModel('books')
. Let's take it out separately. To do this, in the folder of our controller we will create the
_init.php file and place this line there, and delete it from the controllers. Try to link to make sure the project is working.
Now let's link to the creation of a new record and to the list of all records. To do this, open the file
app / views / layout / default.phtml . The
content()
procedure displays the contents of the view to layout. Add the following lines of code right above it:
<a href="<?=baseUrl('books') ?>"> </a><br /> <a href="<?=baseUrl('books/new') ?>"> </a><br />
Now links to the list and the form of addition will be on all pages of the application.
Routing
Let's define how ideally the address of each action should look. I suggest this option:
'books' => '',
'books / new' -> 'book / new',
'books / view / id / {id}' -> 'book / {id}',
'books / edit / id / {id}' -> 'book / {id} / edit',
'books / delete / id / {id}' -> 'book / {id} / delete',
For what it would work? open the file
config / router.php and bring the array to the following form:
return array(
Now, the
book / 1 address will open information about the book from ID 1. The rest is by analogy.
A little more about the route syntax
The key of the associative array is the route pattern, and the value is the real address of the action with all the parameters. Dynamic parts are enclosed in braces. Keep in mind that each route block can be either completely static or completely dynamic, that is, such a record -
'user/{id}' => 'users/profile/id/{id}'
- will be correct, and the record
'id{id}' => 'users/profile/id/{id}'
is incorrect, that is, at the moment it’s impossible to achieve links like
yoursite.com/id33523 , although I’m going to fix it soon.
Routes are filtered by data type (string - string, str; integer - int, integer; fractional number - float, real) and the maximum length of the transmitted value. To add a filter, after the name of the parameter specify the filters through the vertical line. Examples:
Conclusion
In fact, these are not all the features of this framework, but are tired of writing =). I hope that at least someone will use my creation, otherwise why am I crucified here?
Download links
GitHub:
github.com/SazereS/NoNameFramework.gitYandex.Disk:
yadi.sk/d/ZAnE6Yq_4kgBeDropbox:
dl.dropboxusercontent.com/u/85783372/NoNameFramework.zipTroloload:
troloload.ru/f/5979_nonameframework.zipGREAT REQUEST! Poke your mistakes in your nose and feel free to point out weak spots. Even statements like “Give up programming is not yours” will be gratefully accepted if supported by arguments. Thank you in advance!