📜 ⬆️ ⬇️

The first symfony project, part 1

So, let's start? Let's write some small but complete project. Scroll to this exactly 1 hour. Suggest a title. Book Shop? If there are no other ideas, then we will write a blog :)

It is assumed that Apache is installed and running on your local machine, as well as PHP at least 5.1.3.

Install symfony


To start quickly, use the sandbox version of Symphony. This is a version that is simply installed, and allows you to immediately start developing using the default project settings. There is another option - to install the Symphony of the bare distribution. In this case, a number of simple actions will be required to deploy the project and some of its configuration. In our case, let's take the path of least resistance. Therefore, download sf_sandbox_1_2.tgz or sf_sandbox_1_2.zip and unpack the contents into the root of the project folder. Under Linux, it is recommended to leave the rights to the files that are initially located inside the tar-archive (use the –p key of the tar command). As usual, if something does not work, read the readme file. As a result, we get approximately the following folder structure:

 www /
   sf_sandbox /
     apps /
       frontend /
     cache /
     config /
     data /
     doc /
     lib /
     log /
     plugins /
     test /
     web /
       css /
       images /
       js /

')
Here you can see that the project (project) called sf_sandbox contains an application (application) called frontend . We write in the browser

  http: //localhost/sf_sandbox/web/index.php/ 


and make sure everything works: a page should appear



Also, of course, you can install the Symphony in an arbitrary folder and configure virtual hosts on a web server. Read more about this in the chapters on symfony installation and the symfony directory structure of the full-text Symphony Reference.

Create a data model


Blog, comrades, are posts that can be commented on. Accordingly, we need tables in the database where posts and comments will be stored. Since we work in the framework environment, we use its built-in tools to create a model. Make the schema.yml file and put it in the sf_sandbox / config / folder. We write the following to this file:

 propel:
   blog_post:
     id: ~
     title: {type: varchar (255), required: true}
     excerpt: {type: longvarchar}
     body: {type: longvarchar}
     created_at: ~
   blog_comment:
     id: ~
     blog_post_id: ~
     author: {type: varchar (255)}
     email: {type: varchar (255)}
     body: {type: longvarchar}
     created_at: ~


This is a configuration file, and we made it in accordance with the syntax of YAML. It is very simple, and allows you to make XML-like structures using indents. But it is much more readable than the same XML. Just remember one thing: you should use spaces, not tabs, for indentation, otherwise the file parser will stumble. You can read more about YAML in the configuration chapter .

The above diagram (what is written in the schema.yml file is called the data schema) describes the structure of the two tables that we need in our project. The whole point is that based on this scheme, the blog_post and blog_comment classes will be automatically created. But more on that later. Save the file, and in the command line write the following:

 $ php symfony propel: build-model


Before you execute this command, make sure that the current folder is the root folder of the project (this is where the symfony file is located, which we will constantly run with parameters).

So, after executing this command, several files with classes will be created in the sf_sandbox / lib / model / folder. These are classes that reflect the structure of database tables on PHP objects (such reflection is called ORM). “Reflects” in this case means that it will be possible to read / add / change / delete entries in the table by calling some methods of the class corresponding to this table. That is, we call the class method - we write the data to the table. Call another method - delete records (all, or on a specific condition). And all this without writing SQL queries! Just call the methods. There are several implementations of ORM. By default, Symphony works with Propel. These classes are part of the model of our application (read more in the model chapter).

Files are good, but we need tables in the database! Well, we will convert files into tables by means of the Symphony. By default, the sandbox version of the Symphony is configured so that it works with SQLite, that is, no database initialization is required. Now you need to make sure that SQLite works as expected (for this we look at php.ini and read PHP documentation ).

By default, the sf_sandbox project uses a database called sandbox.db , located in the sf_sandbox / data / folder.
If you want to use MySQL (do you really want to use MySQL? :)), then you just need to ask Symphony about it:

 $ php symfony configure: database "mysql: dbname = symfony_project; host = localhost" root mypassword


Naturally, you need to make sure that the symfony_project database exists and is accessible to the root user with the password mypassword .
Now open sf_sandbox / config / databases.yml and replace 'phptype' with 'mysql', and write the name of the database there (figure out where, I think).
If you still decide to stop at SQLite, then you will need to change some rights on * nix-systems:

 $ chmod 777 data data / sandbox.db


Now run

 $ php symfony propel: build-sql


As a result, the file lib.model.schema.sql will be created in the sf_sandbox / data / sql / folder. This file contains the SQL query that you can execute to create the tables we need. To fulfill this request, run

 $ php symfony propel: insert-sql


Don't get scared if a warning pops up. It should be so. The propel: insert-sql command deletes the tables before it is created, and of course should warn you that it will save them now.

Since we need the ability to create and edit posts on our blog, we will need several forms. Let's make them from the scheme in a couple of seconds:

 $ php symfony propel: build-forms


This command will create class files in the sf_sandbox / lib / form / folder. These classes are used to generate forms for adding and editing elements (posts and comments in our project).

Forget everything I wrote before. Everything is done with one command: propel: build-all :)

Making an application


Simplify everything to the limit. We assume that all we need to do with posts and comments is to add (Create), receive (Retrive), update (Update) and delete (Delete). For brevity, these four operations are called CRUD.

Since we are new to the Symphony, we need to quickly get some result, then to conjure it. The easiest way to achieve results is to use the CRUD form generator, which looks at the data scheme and creates the necessary files. Run

 $ php symfony propel: generate-module --non-verbose-templates --with-show frontend post BlogPost
 $ php symfony propel: generate-module --non-verbose-templates frontend comment BlogComment
 $ php symfony cache: clear


When we run propel: generate-module , we must use the --non-verbose-templates key. If you want to know what it is for, run the command with the help key:

 $ php symfony help propel: generate-module


So, we get two modules (post and comment) that will manage objects that are implemented by the BlogPost and BlogComment classes . The module in the Symphony is presented in the form of one or several pages of similar purpose. Our new modules are stored in the sf_sandbox / apps / frontend / modules / folder, and they can even be viewed at:

 http: //localhost/sf_sandbox/web/frontend_dev.php/post
 http: //localhost/sf_sandbox/web/frontend_dev.php/comment


If you try to add a post right now, then an ambush awaits you. Symphony does not know (yet) how to display the post (object!) In the list. For this you need to show her how it is done. To do this, correct the BlogPost class (file lib / model / BlogPost.php ): add the __toString () method to it:

 class BlogPost extends BaseBlogPost
 {
   public function __toString ()
   {
     return $ this-> getTitle ();
   }
 }


This method tells PHP (and therefore Symphonies) how to convert an object into a string. Now you can display posts (objects!) List (lines!)
Now a few CSS decorations ( sf_sandbox / web / css / main.css file ):

 body td
 {
   font-family: Arial, Verdana, sans-serif;
   font-size: 12px;
 }

 td {margin: 4px;  padding: 4px;  }


And voila! You can add posts!



You can read about generators in the chapter generators , and about the structure (project, application, module) we read in the structure chapter.

From the links above (links to modules) we see that the name of the executable script, which in the Symphony is called the front controller (front controller), was changed from index.php to frontend_dev.php . These two scripts run the same application (frontend) in different environments. Using the frontend_dev.php script, we launch our application in the development environment, where you can try to play with all sorts of programmer things like debug, logs, etc. A characteristic feature of the fact that we are working in the development environment is a socket in the upper right corner of the page, as well as a configuration subsystem on-the-fly. For this reason, this script runs a bit slower than index.php , which is the front controller of the working environment optimized for speed. If you want to see what happens in the working environment, replace in the links above frontend_dev.php / with index.php / and do not forget to clear the cache (did I say that every development should clean the cache when developing?):

 $ php symfony cache: clear


 http: //localhost/sf_sandbox/web/index.php/


We read more in chapter environments .

Editing the main template


It is clear that in order to switch between two modules, we need some kind of site navigation. We will draw it in the main template.
Edit the main template file sf_sandbox / apps / frontend / templates / layout.php and replace everything inside
  <body> 
to the following:

 <div id = "container" style = "width: 700px; margin: 0 auto; border: 1px solid gray; padding: 10px">
   <div id = "navigation" style = "display: inline; float: right">
     <ul>
       <li> <? php echo link_to ('List of posts', 'post / index')?> </ li>
       <li> <? php echo link_to ('List of comments', 'comment / index')?> </ li>
     </ ul>
   </ div>
   <div id = "title">
     <h1> <? php echo link_to ('My first symfony project', '@homepage')?> </ h1>
   </ div>
 
   <div id = "content" style = "clear: right">
     <? php echo $ sf_data-> getRaw ('sf_content')?>
   </ div>
 </ div>


Since we have only 1 hour to develop, we will not pay attention to the appearance and we will not do well: we will write the styles directly in HTML.
What is the result?



Since we're here, let's replace the page title. Edit the view configuration file (view) of the application (here View is V from the MVC abbreviation): ( sf_sandbox / apps / frontend / config / view.yml , look for the line where the title property is written and change it to something that your fantasy. Here we see a few lines, commented out by the # symbol. If desired, they can be uncommented.

 default:
   http_metas:
     content-type: text / html

   metas:
     title: The best blog ever
     #description: symfony project
     #keywords: symfony, project
     #language: en
     robots: index, follow


The main page should also be replaced with its own. To do this, we will edit the default module, which is stored in the framework, and not in the folder of your application. It can be rewritten (override) with its own module, which we call main :

 $ php symfony generate: module frontend main


By default, the action (action) index shows some greeting words. To remove this garbage, open sf_sandbox / apps / frontend / modules / main / actions / actions.class.php and clear everything contained in the executeIndex () method:

 / **
  * Executes index action
  *
  * @param sfRequest $ request A request object
  * /
 public function executeIndex ($ request)
 {
 }


Edit the sf_sandbox / apps / frontend / modules / main / templates / indexSuccess.php file to make a more meaningful greeting:

 <h1> Welcome to my new blog </ h1>
 <p> You are the <? php echo rand (1000,5000);  ?> th visitor today. </ p>


Now we have to tell the Symphony what action to launch when the main page is requested. To do this, edit the sf_sandbox / apps / frontend / config / routing.yml file and change the rules for the homepage as follows:

 homepage:
   url: /
   param: {module: main, action: index}


Check what we conjured:

 http: //localhost/sf_sandbox/web/frontend_dev.php/




Well, it already looks like a self-made site. You can even create a test post and attach a test comment to it.
The topic is opened here: views templates .

Passing data from the action to the template


Well, with a certain skill, everything that we have done up to this point takes very little time. Now we will make the comment module dependent on the post module; in other words, we need to output comments under the post.
First we need to make comments available for display in the post output template. In the Symphony, when it is necessary to do something under certain conditions, this is done by means of actions (for example, comments are made under the condition that the page is opened). Open the sf_sandbox / apps / frontend / modules / post / actions / actions.class.php file and rewrite the executeShow () method:

 public function executeShow ($ request)
 {
   $ this-> blog_post = BlogPostPeer :: retrieveByPk ($ request-> getParameter ('id'));
   $ this-> forward404Unless ($ this-> blog_post);
 
   $ c = new Criteria ();
   $ c-> add (BlogCommentPeer :: BLOG_POST_ID, $ request-> getParameter ('id'));
   $ c-> addAscendingOrderByColumn (BlogCommentPeer :: CREATED_AT);
   $ this-> comments = BlogCommentPeer :: doSelect ($ c);
 }


The Criteria and -Peer objects are part of the ORM Propel . These four lines of code will implement the link at the SQL level between blog_comment comments and blog_post posts. It remains to correct the post template file: sf_sandbox / apps / frontend / modules / post / templates / showSuccess.php , add the following lines to the end:

 // ...
 <? php use_helper ('Text', 'Date')?>
 
 <hr />
 <? php if ($ comments):?>
   <p> <? php echo count ($ comments)?> comments to this post. </ p>
   <? php foreach ($ comments as $ comment):?>
     <p> <em> posted by <? php echo $ comment-> getAuthor ()?> on <? php echo format_date ($ comment-> getCreatedAt ())?> </ em> </ p>
     <div class = "comment" style = "margin-bottom: 10px;">
       <? php echo simple_format_text ($ comment-> getBody ())?>
     </ div>
   <? php endforeach;  ?>
 <? php endif;  ?>


On this page, we used a wonderful thing called the helpers - this is the PHP code that inserts a certain often used part of the finished HTML page onto the page. Create a comment on your first post and check that it was rendered under the post:

 http: //localhost/sf_sandbox/web/frontend_dev.php/post/show? id = 1




So the page should look like, if done correctly.
We read in more detail in the chapter naming conventions .

Insert into the database records associated with another table.


All this is cool, but so far it is impossible to write a comment so that it is automatically attached to the post we are commenting on. To do this, you now need to go to the comment editing page and select the post to which it is attached, using the drop-down list. Well, something like this:



It would be much better if the comment was attached to the post as something simpler. Well, let's do it! Edit the sf_sandbox / apps / frontend / modules / post / templates / showSuccess.php template file and add the lines to it:

 <? php echo link_to ('Add a comment', 'comment / edit? post_id ='. $ blog_post-> getId ())?>


The link_to () helper creates a hyperlink to the edit action of the comment module, and now comments are attached to the post immediately after writing. At the same time, the choice of a post in the drop-down list on the comment editing page does not disappear anywhere and is still available. I think it would be nice to replace this selector with a hidden-field containing the post ID.
Forms in the Symphony are controlled by classes. Therefore, to correct the form, you need to correct the class, in this case it is the BlogCommentForm class, it lies in the sf_sandbox / lib / form / folder:

 class BlogCommentForm extends BaseBlogCommentForm
 {
   / **
    * Configure method, called when the form is instantiated
    * /
   public function configure ()
   {
     $ this-> widgetSchema ['blog_post_id'] = new sfWidgetFormInputHidden ();
   }
 }


Forms in the Symphony read here Forms Book .

Now we have the fact that the new comment is automatically attached to the post to which it was written:



Now that we have already taught the system to add comments, I would like it to be added to the page of the post that he commented after adding a comment. To do this, you need to fix the processForm method. We are looking for the following code sf_sandbox / apps / frontend / modules / comment / actions / actions.class.php :

 if ($ request-> isMethod ('post'))
 {
   $ this-> form-> bind ($ request-> getParameter ('blog_comment'));
   if ($ this-> form-> isValid ())
   {
     $ blog_comment = $ this-> form-> save ();
 
     $ this-> redirect ('comment / edit? id ='. $ blog_comment-> getId ());
   }
 }


And change the redirect to the following:

 $ this-> redirect ('post / show? id ='. $ blog_comment-> getBlogPostId ());


There are two things you should pay attention to: first, to save changes to an object, you just need to call the save () method in the form object class (the form class is associated with the Propel data model, and therefore it knows how to convert data from Forms in a form suitable for preservation in a DB). Secondly, we make a redirect immediately after saving, so if the user, after saving the form, presses F5 in the browser, the form will not be sent again, and accordingly, the object will not be re-saved. This is a very useful practice!
Well, the introduction is over. Where is the blog ?? We already have a blog. Only he is completely raw.

See in the following series:


Part two

Dear habravchane, is it worth it to translate the second part of the lesson? Or is it monkey labor?

Source: https://habr.com/ru/post/51921/


All Articles