Symfony Good practice : How to embed several forms for a single entity, handled by different controllers - ajax

I'm working on an application with Symfony 2 and I'm quite new with this framework.
I would like to create a page that represent an user profile on which users can update their personal information, set up an profile picture and a cover picture.
I've written the code for the User class and the template. For both profile and cover picture i'm using ajax with formdata to send images to server.
The other fields (username, email, etc.) are also sent with ajax, but all three parts (profile picture, cover picture, textual fields) of the form have their own submit button.
My problem is about creating controllers and forms.
Should I create a controller for rendering the profile page and then one controller for handling the form ?
Should I create a single form for all fields on the page or create three separated forms that would be handled separately ?
Should I use formbuilder to create form(s) and in the case of there are more than a single controller, how to retrieve the form created in the first controller in the others to proceed validation
Or maybe am I wrong from the beginning ... ?
I can provide my current code, but I don't think it can be useful since my User class and my template are very basic and I'm stuck on writing the rest of the code ; and I prefer knowing the "good" way of doing it before writing too much trash code.

You can have many form and validate them in one controller:
public function updateAction(Request $request)
{
$form_one = $this->get('form.factory')
->createNamedBuilder('form_one', 'form')
->add('user_picture', 'file')
->add('submit', 'submit')
->getForm()
->handleRequest($request);
// Next form ...
if ($form_one->isValid())
{
// Save user picture
$data = 'user picture saved';
}
// Other forms validation
return new JsonResponse(data);
}
Make sure to create the same forms in user profile controller view.

Should I use formbuilder to create form(s) and in the case of there
are more than a single controller, how to retrieve the form created in
the first controller in the others to proceed validation
You could make formType, like in this example, there is RegistrationType.
Then use formType in different controllers.
Then you could validate form from entity(or whatever doctrine,propel or whatever you are using) using entity validators
You could also check generator bundle, specially Generating a New Form Type Class Based on a Doctrine Entity

Symfony best practices say to use custom form type classes for forms
link
I always use seperate controller actions for seperate forms. Code becomes more organized and is easier to debug. And I have had issues/bugs with multiple forms in same controller.

Related

Laravel: form method != save method?

I am new to Laravel coming from CakePHP where the form and save method for a form is one and the same function name. I saw in many Laravel tutorials that the from method (that displays the form) is different than the method to save form (that actually saves data). Why using 2 different method names?
For example what's wrong with:
pub function xyz(Request $request)
{
if($results->isMethod('post')){
... then save and return redirect
}
... the code for showing the form in case there is no POST.
then having 2 routes one for GET and one for POST on the same url?
It is because people like to filter out things at route level not in controller, Also it helps developer to apply middleware grouping for each route separately. so that they can apply roles and permission etc. easily at route level.
It will looks horrible if mix all things in controller.
Think about middleware and groups in your code.
It is because you don't wanna mix a lot of logic in the same method . The case you have simple is the simple scenario . But there will be case where you wanna pass initial data in the create form . You have to write logic for that also in the same method and while you store the data you need to do the validation and calculate other business logic . If you combine all those things in one method it will mix all the things in one method and code difficult to read

Convention for a controller that generates a view from several models

In Sails.js, a route is set up against a controller method which can render a view. For the most part, this is straightforward, i.e. you could set up a GET /users route that points to UserController.find (which is usually set up automatically anyway).
However, say the home page of a blog renders the 10 most recent posts in the main section and a column with a list of authors and categories. The controller method has to fetch posts, authors, and categories before rendering the view and sending it back to the client. Clearly, a method like this doesn't really belong in PostController, AuthorController, or CategoryController.
What's the best thing to do in this situation? Create a controller for rendering views that rely on data from multiple models? Is there a good name for such a controller?
Thanks!
What I would do (this is purely opinion-based) is creating a PageController and create an action for each page you'd want.
For your home page example you can create a home action, get whatever you need and then render it with res.ok() (if everything is fine).
Another option would be to use Sails as a pure API and use HTTP requests (Ajax) or sockets to get your data in JSON. If you want to do so, I'd advise you to use a front end framework such as Angular, Ember, React...
By the way you could also create actions rendering HTML in your existing controllers and create a route to hit them through Ajax requests and just print them in your page. I'd prefer the 2nd solution because it takes full advantage of the Blueprint API (you don't need new controller or action whatsoever).
As Yann pointed out, this answer has to be a little opinionated. It seems that you are using the views system and not building a single page application. For the home page, I would go for an IndexController.js file with a home(req, res) action.
// api/controllers/IndexController.js
module.exports = {
home: function (req, res) {
// Retrieve all the information you need
// Take care about managing the asynchronous calls before rendering the view
return res.view('homepage');
}
};
Declare the route
// config/routes.js
module.exports.routes = {
'get /': 'IndexController.home'
}
Create the view in views/homepage.ejs.

Send a POST ajax to add products to quotation

My background is more server-side than front-end. So I may be lacking in some basic front-end knowledge.
I have a endpoint called
/quotations/:id/products
which if you do a POST action, this means you want to add products to the specified quotation where :id represents the quotation id.
In my schema, quotations and products have a many-to-many relationship.
The endpoint also expects the data is sent in the form of products[].
Meaning to say, if I want to add products with id 2, 7, and 154 to the quotation 3
I am POSTING
<input name="products[]" value="2" />
<input name="products[]" value="7" />
<input name="products[]" value="154" />
to the url /quotations/3/products
My question is how do I create the Model and View using Backbone for this setup?
I bought Addy Osmani's book on Developing Backbone.js Applications. So I have setup my backbone similar to his example.
There is only an example of a straight forward add model.
Hopefully I get an answer that follows the convention that Osmani sets out for adding children to a parent type of behavior.
Osmani also mentioned about Backbone Relational.
I am not sure if I should use this or even how. I have read the documentation, but I am not sure how to fit this into the way Osmani has structured his Backbone example apps.
UPDATE:
If it is a success, I want the page to redirect to another page called /success.
If it is a failure, I want the page to display a failure message somewhere. Assume there is a <div id="message"></div> for me to update.
In other words, for failure, the page stays as a single page app.
For success, the page goes to another page.
As for server-side code for returning JSON replies etc, I can do this without any problems. Assume I use PHP.
I faced a similar problem recently, I can't tell your for certain this is the best way to do it but it's the way i've found to work reliably. I tried BackboneRelational but was having troubles with it.
This assumes you will need to create the Quote object & ProductQuotation in 1 step.
Set up a view for New Quote
On initialization of this view:
A) Create a new empty Quote model
B) Create a new collection for ProductQuotes
C) Create a new ProductQuote view for each ProductQuote you're adding
D) Subscribe the Quote view to a custom Backbones event binding (Backbone JS: can one view trigger updates in other views?), i.e.
Backbone.pubSub.on('quote_new-product-save', this.AddProduct, this)
This view will now call AddProduct any time you trigger this event.
On initializing each ProductQuote view create a new Product model
Wire this view up for your user to fill in any applicable information & when they are done set this information to that views Product model & trigger the "quote_new-product-save" event mentioned above and pass it that product model.
Back in the Quote view, AddProduct will automatically be called as it was binded to this event. You should wire this to receive the new Product model & add it to the ProductQuotes collection.
So now you have your Product model data set to your ProductQuotes collection but this is still not directly linked to the current Quote (which still hasn't been saved) so set the 'order_items' attribute on your model to all models in your ProductQuote collection i.e.
this.model.set('product_quotes', this.collection.models)
Now your unsaved Quote model will have all members of your ProductQuotes collection set as an attribute.
Now you'll need to call save on the Quote model & send the data to the server. Things to keep in mind here is that your urlRoot is set properly & that the data being sent to the server is being properly formatted. I recommend reading Saving nested objects with Rails, backbone.js, and accepts_nested_attributes_for about overriding the toJSON method in your Quote model.

Symfony2 and filter, right strategy

I'm asking what is the best strategy for filtering with Symfony2.
I want to filter a table of entities (hotels). This filter should allow me to :
choose hotels with or whitout email, with or without web site etc.
choose hotels based on state and/or city (relation OneToMany)
choose what information I want to display on the table with checkboxs (for example display "email adress" on the hotel table, but do not display "tel" or "web site").
First I think to build the filter form on the HotelController. When the filter is submitted, I had a FlashBag for every $_POST sended, redirect to the same page, and if there are FlashBag I send cookies to the $reponse. Then I display the table filtered with data who are on the cookie.
But I dont't really like this, cause I had a very big indexAction() on the HotelController, and I think it'as not really clean to change $_POST to FlasBag to Cookie, is it ? I do this redirection, cause by refreshing the page, data are not posted again.
I'm also asking a question, to prevent a too big IndexAction() method, can I put some code to another method, for exemple a method PostToFlashBag() and another FlashBagToCookie(), or every method on a Controller has to end with the word "Action" and must be accessible with the router ?
Then, I think to another thing : had an entity "Filter", with every row I need. For exemple "WithEmail", "DisplayTel" etc.. Then I can build a FilterType easily, and update the Filter entitie, to redirect to the same page (again, to prevent reposting data if the user refreshes the page). Finally, I can display the table with the object Filter, with a method on the HotelRepository.
That seems great, but I'm a little worry because the filter entity will only have one entry, and I have to find the Filter(1). Due to MVC, is it correct to have a model with only one entry ?
What strategy would you choose (maybe another one) ? I'm interesting to learn good practice with MVC and Symfony2 devloppemnt.
Having a dedicated model class - let's call it Filter - that will receive the values input by the user, is definitely the way to go.
More over, use the Symfony2 form on this input, so you can have validation, and be sure that the withEmailis trully a boolean, etc. From you Filter, build you SQL/Doctrine query and return what your controller have to return, be it a view, or raw datas.
You can have any method you want in a controller. After all, controllers in Symfony2 are plain old PHP objects. They only have to implement ContainerAwareInterface. Usually they inherits Controller, but this inheritance only brings some proxy methods, like getDoctrine or render.
The only convention is that methods which are used as route must end with Action

Codeigniter - reusing controllers?

I am trying to code my first codeigniter project. I have a login controller which basically filters the data inputed and calls a model function that checks if the user is found in the database.
What I am trying to do is reuse this controller on the index page. So basically I want to be able to do user login on the index page or on the normal controller page (index.php/login/) without code duplication.
I'm sure there is an easy way to do this, but I'm not sure what the best solution is. Make it a library?
Thanks!
For this I would simply make the form in your view post to the login controller.
As a more generic way to share code and logic throughout your application, take a look at this article:
CodeIgniter Base Classes: Keeping it DRY
You basically give each of your controllers a "type". Being logged in could be a criteria of one of your base controllers, which saves you trying to directly access any of your controllers which is bad mojo.
You can try creating a form on the index page and submit it to index.php/login/. This way you won't need two entry points.
Just do the same as you have done for the login View, specify the same action attribute of the form to the index View, and it will be sent to the same login controller with no need to create the two login controllers. You might want to append a query string in the action attribute of the form to distinguish from which View the request has come.

Resources