This article describes the Symfony form and page implementation tips. Share to everyone for your reference. Specific as follows:
Symfony development is simple, but the number of features is still scarce. Now it's time to do some askeet site-to-user interaction. And the root of the HTML interaction--except the link--is the form.
Our goal here is to allow users to log in and page through the list of issues on the homepage. This is very fast for development and allows us to recall the previous content.
Landing form
The user exists in the test data, but there is no way for the program to validate it. 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 the Code code as follows:
<?php echo link_to (' Sign in ', ' User/login ')?>
The current layout places these links behind the Web Debugging toolbar. To see these links, click the ' Sf ' icon to collapse the Debug toolbar and you can see it.
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 the Code code as follows: $ symfony init-module frontend user
This framework contains a default index action with a indexsuccess.php template. Remove them, because we don't need them.
Create User/login Action
Copy the 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 can then be used to store the module in a hidden area, so that the purpose of the form can be redirected to the original referer after a successful login.
The statement return sfview::success passes the result of the action execution 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 for an action is called actionnamesuccess.php.
Before we start more work on the action, let's take a look at the module.
Creating a loginsuccess.php Module
Many human-computer interactions on the web use forms, and Symfony organizes the creation and management of forms by providing a form helper collection.
Under the askeet/apps/frontend/modules/user/templates/directory, create the following loginsuccess.php module:
Copy the Code code as follows: <?php echo form_tag (' User/login ')?>
Nickname:
<?php Echo Input_tag (' nickname ', $sf _params->get (' nickname '))?>
Password
<?php echo input_password_tag (' password ')?>
<?php echo input_hidden_tag (' Referer ', $sf _request->getattribute (' Referer '))?>
<?php echo Submit_tag (' sign in ')?>
This module is the first time we have used a form helper. These symfony functions help us to 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 atag, and automatically adds an ID attribute based on the first parameter passed, and the default value is obtained by the second parameter. We can find more information about the form helper and the HTML code generated by the symfony in the relevant chapters of the book.
The essence here is that this action is invoked when the form is submitted. So let's go back and look at this action.
Process form Submission
Replace the login action we just wrote with the following code:
Copy CodeThe code is 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 that was called. If this action is not called in post mode (because it is requested by a link): And this is what we discussed in the previous scenario. If the request is in the post mode, then the table will be monotonic with this action and the corresponding processing.
This action gets the value of the nickname field from the request parameter, and queries the user table to see if it exists in the database.
In the future, a password control will assign credentials to the user. But for now, this action only stores the user ID and the nickname attribute in a session attribute. Finally, this action redirects to the original Referer field hidden in the form, which is passed as a request parameter. If the field is empty, the default value is used.
Here we need to note the difference between the two types of attribute sets 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 ()) is saved throughout the lifetime of the user session and can be accessed by other actions in the future. If we want to know more about the properties, we can look at the symfony of the argument-save section.
assigning permissions
Users can log into the Askeet site is a good thing, but users are not only because of the fun and landing. To issue a new question, to express interest in a particular issue, to evaluate a comment that requires landing. Other actions will be open to non-logged users.
To set a user to be authenticated, we need to call the->setauthenticated () method of the Sfuser object. This object also provides a certificate mechanism (->addcredential ()) to restrict access by 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 the Code code as follows: $this->getcontext ()->getuser ()->setauthenticated (true);
$this->getcontext ()->getuser ()->addcredential (' Subscriber ');
When nickname is identified, not only is the user data stored in the session attribute, but the user is also assigned access to the restricted portions of the site. Tomorrow we will see how to Restrict program access for authenticated users.
Add User/logout Action
There is one last trick about the->setattribute () method: The last parameter (subscriber in the example above) defines the namespace in which the attribute is stored. A namespace not only allows a name to be assigned to a property that exists in another namespace, but can also be used to quickly remove all of these properties using a single command:
Copy the Code Code as follows: Public function executelogout ()
{
$this->getuser ()->setauthenticated (false);
$this->getuser ()->clearcredentials ();
$this->getuser ()->getattributeholder ()->removenamespace (' Subscriber ');
$this->redirect (' @homepage ');
}
Using namespaces saves us the hassle of removing these attributes: It's just a line of statements.
Update layout
The current layout even if the user has logged in still displays a ' login ' link. Let's fix this. In the askeet/apps/frontend/templates/layout.php file, modify the code that we modified at the beginning of today's Guide:
Copy the Code code as follows: <?php if ($sf _user->isauthenticated ()):?>
<?php echo link_to (' Sign out ', ' user/logout ')?>
<?php Echo link_to ($sf _user->getattribute (' nickname ', ' ', ' Subscriber '). ' Profile ', ' user/profile ')?>
<?php Else:?>
<?php echo link_to (' sign in/register ', ' user/login ')?>
<?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 ' login ' at the top of the window changes to ' sign out ', then everything we do is correct. Finally, try logging out to see if the ' Login ' link appears again.
Problem organization
As thousands of symfony enthusiasts visit the Askeet site, the problems that appear on the home page become much more problematic. In order to avoid the slow request speed, the question column's random paging becomes the problem that must be solved.
Symfony provides an object for this purpose: Sfpropelpager. He encapsulates the request to the data so that only the records displayed on the current page are queried. For example, if a page is initialized with only 10 questions per page, the request to the data will only be limited to 10 results, and the offset will be set to match on the page.
modifying question/list actions
In the previous exercise, we saw the display action of the problem module:
Copy the 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 questions according to the number of interests:
Copy the 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, it will return a result of 3 to 5. When the value of the page request parameter changes to 1, the page defaults back to the result of 1 through 2. We can learn more about Sfpropelpager objects and their methods in the page chapters of the Symfony book.
Use a default parameter
It is a good idea to put constants in the configuration file that we use. For example, the results of each page (in this example, 2) can be replaced by a parameter in our custom program configuration. Use the following code to change the Sfpropelpager line above:
Copy the 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 more information about custom configuration and naming custom parameter rules in the configuration section of Symfony.
Modify the listsuccess.php template
In the listsuccess.php template, put the following line of code:
Copy the Code code as follows: <?php foreach ($questions as $question):?>
Replaced by
Copy the Code code as follows: <?php foreach ($question _pager->getresults () as $question):?>
This allows the page to display a list of results stored in the page.
Add a Page view
Another thing to do in this template: Page view. Now, the template does only show the first two issues, but we should add the 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: The
copy Code code is as follows:
<?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= '. $
<?php echo ($page! = $question _pager->getcurrentmaxlink ())? '-': ',
<?php endforeach;.
<?php echo link_to (' > ', ' question/list?page= '. $question _page R->getnextpage ()),
<?php echo link_to ('» ', ' question/list?page= '. $question _pager->getlastpage ())?
<?php endif;
This code takes advantage of the various methods of the Sfpropelpager object, and->havetopaginate (), which returns true only if the number of results requested 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 () when the test as the first parameter is false, otherwise it outputs a non-linked text and uses a simple wrapper.
Have we tested this page yet? We should do the testing. Until we use our own eyes to verify that this change is over. To test, open the test data file that you created on the third day and add some questions for the page browse that you want to display. Rerun the Import data batch file, and then request the home page again.
Add a routing rule for a child page
By default, the page rules are as follows:
Http://askeet/frontend_dev.php/question/list/page/XX
Now we 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 the 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 the 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 the 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 the 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 title retrieval problem that the propel object is stripped from should belong to this module. So use the following code to change the Question/show action code:
Copy the 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 the 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 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 contents of listsuccess.php with the following simple code:
Copy the Code code as follows:
Popular question
<?php echo include_partial (' list ', array (' question_pager ' = $question _pager))?>
It is hoped that this article will be helpful to everyone's symfony framework design.