This article describes the Symfony form and page implementation techniques. Share to everyone for your reference. Specifically as follows:
Symfony development is concise, but the number of functions is still scarce. Now is the time to do some askeet site interaction with the user. And the fundamental of HTML interaction--except for links--is the form.
Our goal here is to allow users to log in and flip through the list of issues on the home page. This is quick for development and allows us to recall the previous content.
Landing form
There are users in the test data, but there is no way for the program to authenticate. Below we will add a login form to each page of the program. Open the global layout file askeet/apps/frontend/templates/layout.php, and add the following line of code before the connection to about:
Copy Code code as follows:
<li><?php echo link_to (' Sign in ', ' User/login ')?></li>
The current layout places these links after the Web Debugging toolbar. To see these links, click the ' Sf ' icon to collapse the debug toolbar to see.
Now you need to create the user module. And the question module was generated the next day, and this time we just called Symfony to create the module framework, and we'll write the code ourselves.
Copy Code code as follows:
$ symfony init-module frontend user
This frame contains a default index action and a indexsuccess.php template. Remove them, because we don't need them.
Create User/login Action
Copy Code code as follows:
In the user/actions/action.class.php file, add the following login action:
Public Function Executelogin ()
{
$this->getrequest ()->setattribute (' Referer ', $this->getrequest ()->getreferer ());
return sfview::success;
}
This action saves the referer in the request attribute. This property is then stored in a hidden area for the module, so that the purpose action of the form can be redirected to the original referer after the successful landing.
The statement return sfview::success passes the action execution results to the loginsuccess.php module. This statement is implemented in an action that does not contain a return statement, which is why the default module of an action is called actionnamesuccess.php.
Before we start doing more work on the action, let's take a look at the module.
Creating loginsuccess.php Modules
Many human-computer interactions on the web use forms, while Symfony organizes forms creation and management by providing a form helper collection.
In the askeet/apps/frontend/modules/user/templates/directory, create the following loginsuccess.php module:
Copy Code code as follows:
<?php echo form_tag (' User/login ')?>
<fieldset>
<div class= "Form-row" >
<label for= "nickname" >nickname:</label>
<?php Echo Input_tag (' nickname ', $sf _params->get (' nickname '))?>
</div>
<div class= "Form-row" >
<label for= "Password" >password:</label>
<?php echo input_password_tag (' password ')?>
</div>
</fieldset>
<?php echo input_hidden_tag (' Referer ', $sf _request->getattribute (' Referer '))?>
<?php echo Submit_tag (' sign in ')?>
</form>
This module is the first time we use the form helper. These symfony functions can help us automate the writing of form labels. Form_tag () Opens a From this tab, uses post as the default action, and points to the action passed as a parameter. The Input_tag () helper produces a <input> tag and automatically adds an ID attribute based on the first parameter passed, and the default value is obtained by the second argument. We can find out more about the form helper and the HTML code they produce in the relevant chapters of the Symfony book.
The essence here is that this action is called when the form is submitted. So let's go back and take a look at this action.
Process form Submission
Replace the login action we just wrote with the following code:
Copy Code code as follows:
Public Function Executelogin ()
{
if ($this->getrequest ()->getmethod ()!= sfrequest::P ost)
{
Display the form
$this->getrequest ()->setattribute (' Referer ', $this->getrequest ()->getreferer ());
}
Else
{
Handle the form submission
$nickname = $this->getrequestparameter (' nickname ');
$c = new Criteria ();
$c->add (Userpeer::nickname, $nickname);
$user = Userpeer::d oselectone ($c);
Nickname exists?
if ($user)
{
Password is OK?
if (true)
{
$this->getuser ()->setauthenticated (true);
$this->getuser ()->addcredential (' Subscriber ');
$this->getuser ()->setattribute (' subscriber_id ', $user->getid (), ' Subscriber ');
$this->getuser ()->setattribute (' nickname ', $user->getnickname (), ' Subscriber ');
Redirect to last page
return $this->redirect ($this->getrequestparameter (' referer ', ' @homepage '));
}
}
}
}
The login action can also be used to display the login form and process it. Accordingly, he must know the environment in which it was invoked. If this action is not invoked in post mode (because it is requested by a link): And that is exactly what we discussed earlier. If the request is in post mode, then the table will be monotone with this action and processed accordingly.
This action gets the value of the nickname field from the request parameter, and queries the user table to see if there is one in the database.
A future password control will assign credentials to the user. But now, what this action does is to store the user ID and the nickname attribute in a session attribute. Finally, this action is redirected to the original Referer field hidden in the form, which is passed as a request parameter. If this field is empty, the default value is used.
Here we need to note the difference between the two types of attribute collections in this example: Request attributes ($this->getrequest ()->setattribute ()) is saved for the template. And as long as the answer is sent to Referer, it will be forgotten. Session attributes ($this->getuser ()->setattribute ()) are saved throughout the lifetime of the user's sessions, and they can be accessed by other actions in the future. If we want to learn more about attributes, we can look at the Symfony section of the argument-store.
assigning permissions
Users can log into the Askeet site is a good thing, but the user is not only because of fun and landing. Issue a new question, express interest in a particular issue, and evaluate a comment that requires landing. Other actions will be open to users who are not logged in.
To set a user to be authenticated, we need to invoke the->setauthenticated () method of the Sfuser object. This object also provides a certificate mechanism (->addcredential ()) to restrict access through configuration. This is explained in detail in the User certificate section of the Symfony book.
This is the purpose of the following two lines:
Copy Code code as follows:
$this->getcontext ()->getuser ()->setauthenticated (true);
$this->getcontext ()->getuser ()->addcredential (' Subscriber ');
When nickname is recognized, not only is the user data stored in the session attribute, but also the user is assigned access to the site's restricted section. Tomorrow we'll see how to limit the access to programs that authenticate users.
Add User/logout Action
One last tip about the->setattribute () method is that the last parameter (subscriber in the example above) defines the namespace in which the attribute is stored. A namespace not only allows a name that exists in another namespace to be assigned to an attribute, but can quickly remove all of these attributes using a command:
Copy Code code as follows:
Public Function Executelogout ()
{
$this->getuser ()->setauthenticated (false);
$this->getuser ()->clearcredentials ();
$this->getuser ()->getattributeholder ()->removenamespace (' Subscriber ');
$this->redirect (' @homepage ');
}
Using namespaces eliminates the hassle of removing one of these attributes: This is just a line of statements.
Update layout
The current layout even if the user has logged in still shows a ' login ' link. Let's fix that. In the askeet/apps/frontend/templates/layout.php file, modify the code we modified at the beginning of today's Guide:
Copy Code code as follows:
<?php if ($sf _user->isauthenticated ()):?>
<li><?php echo link_to (' Sign out ', ' user/logout ')?></li>
<li><?php Echo link_to ($sf _user->getattribute (' nickname ', ', ', ' Subscriber '). ' Profile ', ' user/profile '? ></li>
<?php Else:?>
<li><?php echo link_to (' sign in/register ', ' user/login ')?></li>
<?php endif?>
Now is the time to test, we can display any page of the program, click on the ' Login ' link, enter an available nickname (' Anonymous ' for example) and verify. If the ' login ' at the top of the window becomes ' sign out ', everything we do is correct. Finally, try logging off to see if the ' Login ' link appears again.
Problem organization
As thousands of symfony enthusiasts visit the Askeet Web site, the problems that appear on the home page will become more problematic. In order to avoid slow request speed, the random page of problem list becomes the problem that must be solved.
Symfony provides an object for this purpose: Sfpropelpager. He encapsulates the request to the data, thus querying only the records displayed by the current page. For example, if a page is initialized with only 10 questions per page, the request to the data is limited to 10 results and the offset is set to match on the page.
Modify Question/list Action
In the previous exercise, we saw the display action of the problem module:
Copy Code code as follows:
Public Function Executelist ()
{
$this->questions = questionpeer::d oselect (New Criteria ());
}
We will modify this action to pass a sfpropelpager to the template instead of passing an array. At the same time, we will sort the problem according to the quantity of interest:
Copy Code code as follows:
Public Function Executelist ()
{
$pager = new Sfpropelpager (' Question ', 2);
$c = new Criteria ();
$c->adddescendingorderbycolumn (questionpeer::interested_users);
$pager->setcriteria ($c);
$pager->setpage ($this->getrequestparameter (' page ', 1));
$pager->setpeermethod (' Doselectjoinuser ');
$pager->init ();
$this->question_pager = $pager;
}
The initialization of the Sfpropelpager object indicates which object class he contains and the maximum number of objects that can be placed on a page (in this case, 2). The->setpage () method uses a request parameter to set the current page. For example, if the value of this page parameter is 2,sfpropelpager, a result of 3 to 5 will be returned. The page request parameter's value changes to 1, and the page defaults to 1 to 2 results. We can learn more about Sfpropelpager objects and their methods in the page chapters of the Symfony book.
Use a default parameter
It's a good idea to put constants in the configuration file that we use. For example, the results of each page (in this case, 2) can be replaced by a parameter in our custom program configuration. Use the following code to change the Sfpropelpager line above:
Copy Code code as follows:
..
$pager = new Sfpropelpager (' Question ', sfconfig::get (' App_pager_homepage_max '));
The pager keyword here is used as a namespace, which is why it appears in the name of the parameter. We can find out more about custom configuration and naming custom parameter rules in the configuration section of the Symfony book.
Modify the listsuccess.php template
In the listsuccess.php template, the following line of code:
Copy Code code as follows:
<?php foreach ($questions as $question):?>
Replaced by
Copy Code code as follows:
<?php foreach ($question _pager->getresults () as $question):?>
The page displays a list of the results stored in the page.
Add Page view
There is another thing to do in this template: page browsing. Now, the template does only show the first two issues, but we should add functionality to the next page, and back to the previous page. To complete adding these features, we need to add the following code behind the template:
Copy Code code as follows:
<div id= "Question_pager" >
<?php if ($question _pager->havetopaginate ()):?>
<?php echo link_to (' «', ' question/list?page=1 ')?>
<?php Echo link_to (' < ', ' question/list?page= '. $question _pager->getpreviouspage ())?>
<?php foreach ($question _pager->getlinks () as $page):?>
<?php echo link_to_unless ($page = = $question _pager->getpage (), $page, ' question/list?page= '. $page)?>
<?php Echo ($page!= $question _pager->getcurrentmaxlink ())? '-': '?>
<?php Endforeach;?>
<?php echo link_to (' > ', ' question/list?page= '. $question _pager->getnextpage ())?>
<?php echo link_to ('» ', ' question/list?page= '. $question _pager->getlastpage ())?>
<?php endif;?>
</div>
This code utilizes various methods of the Sfpropelpager object, and->havetopaginate (), which returns true only if the number of requests exceeds the page size, and->getpreviouspage (),-> Getnextpage (),->getlastpage () have obvious meanings; the->getlinks () function provides an array of page numbers, and the->getcurrentmaxlink () function returns the last page number.
This example also shows a symfony link helper: link_to_unless () outputs a regular link_to () if the test for the first parameter is false, or it outputs a text that is not linked and uses a simple <span> wrapper.
Have we tested this page yet? We should carry out the test. Until we use our own eyes to verify that this modification is finished. To test, open the test data file that you created on the third day, and add some questions for the page browsing that you want to display. Rerun the Import data batch file, and then request the home page again.
To add a routing rule to a child page
By default, the page rules are as follows:
Http://askeet/frontend_dev.php/question/list/page/XX
We now use routing rules to make these pages easier to understand:
Http://askeet/frontend_dev.php/index/XX
Open the Apps/frontend/config/routing.yml file and add the following at the top:
Copy Code code as follows:
Popular_questions:
URL:/index/:p age
Param: {module:question, action:list}
and add additional routing rules for the landing page:
Copy Code code as follows:
Login
URL:/login
Param: {module:user, Action:login}
Refactoring
Model
The Question/list action executes the code associated with the model, which is why we want to move the code into the module. Replace the Question/list action with the following code:
Copy Code code as follows:
Public Function Executelist ()
{
$this->question_pager = Questionpeer::gethomepagepager ($this->getrequestparameter (' page ', 1));
}
and add the following method to the Questionpeer.php class in Lib/model:
Copy Code code as follows:
public static function Gethomepagepager ($page)
{
$pager = new Sfpropelpager (' Question ', sfconfig::get (' App_pager_homepage_max '));
$c = new Criteria ();
$c->adddescendingorderbycolumn (self::interested_users);
$pager->setcriteria ($c);
$pager->setpage ($page);
$pager->setpeermethod (' Doselectjoinuser ');
$pager->init ();
return $pager;
}
The same idea applies to the Question/show action we wrote yesterday: the use of the Propel object to retrieve the problem from its stripped title should belong to this module. So use the following code to change the Question/show action code:
Copy Code code as follows:
Public Function Executeshow ()
{
$this->question = Questionpeer::getquestionfromtitle ($this->getrequestparameter (' Stripped_title '));
$this->forward404unless ($this->question);
}
Add the following code to the questionpeer.php file:
Copy Code code as follows:
public static function Getquestionfromtitle ($title)
{
$c = new Criteria ();
$c->add (Questionpeer::stripped_title, $title);
Return self::d oselectone ($c);
}
Template
The list of issues that are displayed in question/templates/listsuccess.php will be used in some places in the future. So we put the template code that shows the problem list in a _list.php fragment and replace the listsuccess.php with the following simple code:
Copy Code code as follows:
<?php echo include_partial (' list ', array (' Question_pager ' => $question _pager))?>
I hope this article will be helpful to everyone's Symfony framework program design.