posting to same page good practice? - php

I have been doing some reading about many different things lately to improve my coding quality.
I am wondering if it is a good practice to post form to the same page often I used this type of snippet in my current applications.
public function addAction(){
$form = new Application_Form_Add();
$this->view->form = $form;
if(!$this->_request->isPost() && $form->isValid($this->_request->getParams())){
$mapper = new Application_Model_ModelMapper();
$model = new Application_Model_Model($form->getValues());
if(!$mapper->save($model)){
$this->view->messages('an error occurred etc ... ');
return;
}
$this->_helper->redirector->gotoRoute(array('id' => $model->id), 'model_view');
}
}
so my add action presents the form on GET request and process it on POST request.
I came around this article of Matthew Weier O'Phinney, I think everyone can agree he is one of the PHP gurus of the moment. In his example, he make two differents action one to show the form, one to process it. So if the form doesn't validate he plays with $this->render to re render the form view.
Is it a bad practice to submit form to same page and if yes why?

For the purpose of code readability and maintainability, two different controller actions - despite them associated with the same form - are better separated as two functions/scripts.
Imagine what it would be like if all CRUD operations were combined in a single function/script. That will be messy.

I don't think it's bad.
No matter we do this with same page and different page.
Both ways are correct at their places.
using singe page is a sort and sweet way and using 2 pages gives our code a managed way.
In my opinion both are equall.

In my oppinion I prefer to use one action for it. This keeps all the stuff together. O'Phinney's controller could loo like this:
addAction (uses saveAction to save)
editAction (uses saveAction to save)
saveAction (does not render itself)
Having one method for all controller save/edit logic is the only reason (assumption!) to make it and extra action. Cool, keeps everything in one place. But: this required both, edit and add, to have exactly the same logic. As soon as there is any if/else like
public function saveAction()
{
if($action == 'edit)
{
// edit logic
} else if($action == 'add')
{
// add logic
}
}
to have a different logic depending on the action, this totally exploits the idea of one action. So if you know that the logic is always the same and is very unlikly to change, this is the way to save you lot's of coding work :).
On the other hand, if your add/edit logic are a bit different, I'd keep all logic together that belongs together:
addAction (prints form and saves on POST)
editAction (prints form and saves on POST)
This might look like code-duplication (and maybe is), but then, my edit/add actions have about 3-6 lines of code. But as soon as the logic of either changes, you really know the place.
So this is a personally oppinion, I'd stick with seperated actions as soon as stuff becomes more complex.
(As a note: to logic I'm refering to controller logic, all data-logic should be in the model anyway)

Related

Is it bad practice to use the same method for SAVE and UPDATE?

I'm using laravel but it's not important, when you create a controller with laravel command line tool, it puts 4 default function in there for create and update.
create and store for save
edit and update for well update!
This is what laravel suggest for Shop controller.
class ShopController extends Controller
{
public function create()
{
// return create view
}
public function store(Request $request)
{
// save a shop
}
public function edit($id)
{
// find a shop , return edit view
}
public function update(Request $request, $id)
{
// find the shop with id , update the shop
}
}
But I like to use the same methods for showing view and store/update my row and avoid writing lots of extra code.
class ShopController extends Controller
{
public function create($id = 0)
{
return view('shop-create' , ['edit'=> Shop::find($id)]);
}
public function store(Request $request , $id = 0 )
{
$whitelist = [
'title'=>'required',
'phone'=>'present|numeric' ,
'address'=>'present' ,
];
$this->validate($request, $whitelist );
$shop = Shop::findOrNew($id) ;
// find a shop with given id or create a new shop instance
foreach($whitelist as $k=>$v)
$shop->$k = $request[$k];
$shop->save();
}
}
Naturally I go with what I like (second option), but since laravel suggest the first way, just out of curiosity is there any reason why I shouldn't do it like this? Is this considered bad practice in any way?
Nothing wrong, but you code will be harder to understand, IMHO.
e.g.:
What does this method do? It's called create, but it also edits?
The view is called shop-create but it also edits?
Passing a 0 parameter as default for id and trying to find it every time is unnecessary.
public function create($id = 0)
{
return view('shop-create' , ['edit'=> Shop::find($id)]);
}
Although you're thinking that you are simplifying your code, you are turning it more complicated since you are breaking the Single Responsibility principle from SOLID.
It's easier to understand if you have something like the Laravel suggestion.
Also you keep a very common pattern that any Laravel developer will understand, so you can hire someone to take care of your code and do not worry if he will understand.
There is nothing wrong with doing it your way. The "laravel" way you mention is when you create a Restful resource controller and is simply one way to tackle it.
I guess those controller methods were picked because they line up nicely to a "restful" type of controller. If you were to be building a true rest api, then how you do it becomes far more strict from a standards point of view (not imposed by laravel, but line up better to the laravel way).
If you aren't creating a public facing api, or something that is going to be consumed by external entities, then I say design your controllers that work best for you and your team
This is how i usually do it, this way you can still have different validation by using the requests and it's still clear (imo) what the functions do.
public function store(AdminPartnerRequest $request)
{
return $this->handleCreateOrUpdate($request);
}
public function update(AdminPartnerRequest $request, $id)
{
return $this->handleCreateOrUpdate($request,true, $id);
}
private function handleCreateOrUpdate($request, $edit = false, $id = null)
{
if ($edit){
$partner = Partner::find($id);
} else{
$partner = new Partner();
}
$partner->name = $request->input('name');
$partner->picture = $request->input('image');
$partner->save();
return \Redirect::route('admin.partners.index');
}
Using same function for save() and update() is good idea but at the same time it will increase complexity .. One point is If in future you want to change anything you need to change it only at one place.
But at the same time you need to take some extra care.
As your function should be more dynamic.
1) Multiple records manipulation : you may require to update more than one raws at the same time so your function should be enough flexible to insert/update single/multiple values by the same function. Meaning , single query should be fired for multiple records in both the cases.
2) Validation if value already exist : When you are going to check some validation ...
in insert case you only need to check if the value is exist in db or not
when in update case you need to check with exclusion of current id
e.g.
for insert case
$this->validate($request, [
'email' => 'required|string|email|unique:tablename,email'
]);
for update case
$this->validate($request, [
'email' => 'required|string|email|unique:tablename,email,'.$id.',id'
]);
And at last very small point but need to be considered ..
3) Success message : At the time of insertion message should be "added successfully" and at updation time Record "updated successfully"
Small project, do whatever you want. Large with other developers, follow the conventions.
Coding conventions are a set of guidelines for a specific programming language that recommend programming style, practices, and methods for each aspect of a program written in that language. These conventions usually cover file organization, indentation, comments, declarations, statements, white space, naming conventions, programming practices, programming principles, programming rules of thumb, architectural best practices, etc. These are guidelines for software structural quality. Software programmers are highly recommended to follow these guidelines to help improve the readability of their source code and make software maintenance easier. Coding conventions are only applicable to the human maintainers and peer reviewers of a software project. Conventions may be formalized in a documented set of rules that an entire team or company follows, or may be as informal as the habitual coding practices of an individual. Coding conventions are not enforced by compilers. -- https://en.wikipedia.org/wiki/Coding_conventions
I used this method in a last project of mine, we called the store() and update() function manage() instead and had a getManage() which would use the same view for creating and editing. I liked this method a lot yet came across a few things worth noting. Sadly the cons outway the pros if you ever have to face those issues :(
Pros:
Smaller code - No longer do you have duplicate lines of code in your store() and update() function.
Faster to re-use with basic models - ctrl+c ctrl+v ctrl+f ctrl+r if you know what I mean.
Easier to add/change input values - An extra value would not mean having to change store() and update() to make sure they both utilize the extra input.
One function to rule them all - As long as you are not doing anything special, you can even define one function for everything. Need to change something? You've got one function, no worries.
Cons:
Code is harder to understand for others (or an older you) - If someone is new to this method or hasn't used it in a while, understanding what happens within your function is a little harder than having two separate ones.
Validation is a nuisance - As stated in this answer validation may be different for create and update. Meaning you may sometimes have to write two validations which will eventually lead to messy code and we don't want that!
Value insertion wasn't as cool as I thought - If you want to use the same predefined array to create or update then you may run into the problem of wanting to insert values on create yet never want to update them. This eventually led to either ugly if statements or two predefined arrays.
Eventually it's up to what you're going to make and what you want to do. If you have a basic website which will manage blog posts and pages then have no worries going for a shared store() and update() function. Yet if you're creating a huge CMS with many models, relations and different create and update input values (which may mean different validation) then I'd go with what Laravel recommends. It would be much easier to maintain in the long run and you won't have to deal with headaches, hacky fixes and unclean code.
Whatever you do, don't do both in different controllers! That would be confusing.
By the way, if you're wondering what kind of project I had - it was a huge CMS. So even though it was very useful and easy in some cases, it was sadly not worth it.
Nothing wrong, but in that case you have to maintain proper comments that specify that your function perform add / edit and for that you are using some variable like $id or some thing else. If it is available than you can update the record otherwise insert it.

PHP folder structure for AJAX calls and form actions

I am trying to develope good code organization habits and work exclusively with OOP in php but I can't seem to wrap my head around something.
Here is a simplified description of what I am working with:
I have all my class files in a folder '/resources/Classes'
I have all my html and javascript in '/public_html' & '/public_html/script respectively'
My question is concerning files that are the actions of forms or AJAX requests. For example 'formAction.php' and 'ajaxURL.php'. These files are not Classes and also do not contain any html or other such GUI.
I have been putting them in a folder 'resources/actions' but my gut tells me something about this is not fully OOP.
Is my usage of these files incorrect if I am trying for complete OOP? if so how can I approach this differently.
Here is an actual file from my project as a concrete example:
//file: getBalance.php
<?php
/**
* This script gets the balance of an account from the server
*/
if (!isset($Database)) {
$Database = require_once "../clear_finance_pkg.php";
}
/** #var User $User */
$User = $Database->getUserByID("1");//TODO: user should be set dynamically
$User->setAccounts($Database->getAccountsByUser($User));
if (isset($arg1)) {
$accountID = $arg1;
foreach ($User->getAccounts() as $Account) {
if ($Account->getId() == $accountID) {
$RbcChequing = RbcAccount::accountToRbcAccount($Account, "Chequing");
echo '$' . Money::toDollars($RbcChequing->getBalance());
break;
}
}
} else throw new Exception('Account ID is not set. Could not get balance');
It's difficult to say if your code is complete OOP, but i think it isn't. It looks like you are on the right track, because you are using classes, objects and methods. That's the basic of OOP. No longer large if/else statements and a lot of variables that doesn't make sense, but objects and methods without code-duplication.
I think your question in more related to the seperation of logic and view. First of all. In general it's ok to make a file for a function, but in a large application you will loose the overview. What you are doing know is combine view-related and logic-related things in one file, but actually that's not what you want. The ideal situation is full seperation of logic and view so you can create multiple seperate views based on the same logic.
My advice is to take a look at the MVC-pattern. Take a look at this link. It will help you to get a basic understanding of the MVC-pattern. Notice that you won't longer need to have a file for each function. And you have a seperation of your logic and view elements because you can use the same model in multiple views (although this is maybe not the best example).

insert/delete query design of website

I wonder what would be the professional way to handle insert/delete requests of a website?
Right now, what I have is I inserted two <input type = "hidden"/> on each form where one hidden's value correspond to a function it needs and the other is the parameter of this function. So when the form submits, I have a post.php file that handles ALL insert/delete requests that simply invokes the value of the hiddens via call_user_func() in PHP. Like so:
<input name = "arg" value = "{$id}" type = "hidden"/>
<input name = "call" value = "delete_member" type = "hidden"/>
call_user_func($_POST['call'], $_POST['arg']);
I'm having doubts on how sensible this solution is because I found out that the hiddens aren't actually hidden in the source on the client-side.
My first solution was to basically have a lot of conditionals checking for which function to invoke but I really hated that a lot so I changed it with this solution.
I wonder what are the better ways I can do this, or maybe how the professionals do it? Handling insert/delete queries.
I would consider this a very bad way to call actions from the client side.
For one this data is put into the HTML which will always be viewable and editable by the client. As such this means you cannot trust the data you receive from the client and as such you cannot trust the function they are calling.
Another point to re-inforce my previous idea. You say you run validation to make sure it is a function and all that, but you have a problem. Closures return true on these functions (since they are functions and methods and they exist). So a user can put a anon function as the value of your hiden field and actually run whatever they want on your server.
As others say I would recommend looking into MVC. Look into how Yii/CodeIgniter/Zend/Lithium/Kohana/etc do this and how they route.
An example of how routing for actions such as deletion is done by my favourite framework, Yii:
class UserController extends CController{
public function actionDelete($id = null){
if($id===null){ return false; }
}
}
Then the form/link calls /user/delete?id=2 which makes index.php route to the userController and use the actionDelete function inside the user controller, running it's code. Of course this is a very simplified version and it gets a lot more complex to stop vulnerabilities.
You may also wish to look into CSRF validation.
The most common way is to just call a function that takes care of one form at the time like this example for submitting a blog message:
blog.php
if(isset($_POST['submit'])) {
save_message();
} else {
display_form();
}
function display_form()
{
?>
<form action="blog.php"> etc etc....
<?php
}
function save_message()
{
//security checks and inserts etc
$_SESSION['message'] = 'Form saved succesfully';
header('location: blog_overview.php');
}
This is according to me a practish, but you might want to checkout frameworks like Codeigniter and Kohana since the above code is functional (and to me outdated). Read some tutorials about OOP (Object Oriented Programming) and MVC (Model View Controller). It might seem alot of work, but if you really want it to do it right it is worth the time and effort.

PHP MVC design - multiple actions to same url/controller

In a MVC pattern, what's the best way to handle when a single view could have multiple actions of the same type (e.g POST)?
Say for instance in a TODO list application. You might allow a user to create multiple lists. Each list could have multiple items. So a user navigates to site.com/list/1 which shows them all the items on the 1st list (1 is a GET parameter). There are then 2 forms (POST) on this page to allow a user to:
Create a new item
Delete an existing item
Should the bootstrap create a "listcontroller", inspect the POST variables and then call the appropriate method similar to :
$lc = new ListController();
if(strtolower($request->verb) === 'post'):
if(isset($_POST['title'])) :
$data = $lc->newItem($_POST);
$load->view('newitem.php', $data);
else if(isset($_POST['delete']) && isset($_POST['id'])):
$data = $lc->deleteItem($_POST);
$load-view('deleteitem.php', $data);
endif;// End if post title
else:
//GET request here so show view for single list
endif; //
Or is it better to just do something like
$lc = new ListController();
if(isset($_POST)):
//controller handles logic about what function to call
$data = $lc->PostAction($_POST);
// $data could also potentially hold correct view name based on post
$load->view();
else:
//again just show single list
endif;
I'm just struggling how best to have a controller potentially handle multiple different actions, as there's potentially quite a few nested if/else or case statements to handle different scenarios. I know these would have to sit somewhere, but where is cleanest?
I know that there are many frameworks out there, but I'm going through the whole "want to understand best practice" behind it phase. Or is this totally the wrong way to do it? Should the controllers actually be structured differently?
To begin with, I actually really like, how you are dealing with implementation of MVC. None of that rails-like parody, where view is managed inside the controller.
Here is what I think is the root of your problem: you are still using a "dumb view" approach.
View is not supposed to be a synonym for "template". Instead it should be a full object, which has knowledge-of and ability-to deal with multiple templates. Also, in most of MVC-inspired design patterns, the view instances are able to request information from model layer.
In your code the issue can be traced back to view's factory ( the $load->view() method ), which only gets what controller sends it. Instead controller should only change the name of the view, and maybe send something that would change the state of view.
The best solution for you would be to create full-blown view implementation. Such that view itself could request data from model layer and , based on data it received, decide which template(s) to use and whether to require additional information from model layer.
I think you're somewhat on the right track with the latter approach. However, you should not hard code the calling of actions in your bootstrap. The bootstrap should interpret the URL and call the action methods dynamically through the use of a function like call_user_func_array.
Also, I would suggest that you leave the rendering of views up to the action code so the action logic is self sufficient and flexible. That would allow the action to analyse the input for correctness and render errors or views appropriately. Also, you've got the method 'deleteItem' on your controller, but that should really be the work of a model. Perhaps you should read up some more on MVC and try to work with an existing framework to understand the concepts better before you try to implement your own framework (I would suggest the Yii framework for that).
Here's an example of how I think your logic should be implemented in a good MVC framework.
class ListController extends BaseController
{
public function CreateAction($title){
if(ctype_alnum($title))
{
$list = new List();
$list->Title = $title;
if($list->insert())
{
$this->render_view('list/create_successful');
}
else
{
$this->render_view('list/create_failed');
}
}
else
{
$this->render_view('list/invalid_title');
}
}
public function DeleteAction($id){
$list = List::model()->getById($id);
if($list == null)
{
$this->render_view('list/errors/list_not_found');
}
elseif($list->delete())
{
$this->render_view('list/delete_successful');
}
else
{
$this->render_view('list/delete_failed');
}
}
}
here is a great tutorial on how to write your own MVC framework

jumping controllers in code igniter

I am wanting to have a form of dynamic routing.
Basically I want to catch the 404 (done through routes.php 404_override).
This is easy enough.
But then what I want to do is run through a series of checks.
e.g pay no attention to the fact the is_xxx functions are not coming from anywhere
$what = $this->uri->segment(1);
if(is_vanity_name($what)){
//now I want to route this to the profile controller and call the display function like so
//display('vanity', $what);
}
elseif(is_region_name($what)){
if(($deal = $this->uri->segment(2)) !== false){
//now I want to route to the deals controller can call the display function like so
//display($deal, $what);
}
else {
//now I want to route to the deals controller and call the daily function like so
//daily($what);
}
}
elseif(is_deal_name($what)){
//now I want to route to the deals controller and call the display function like so
//display($what);
}
else{
$this->load->view('errors/404');
}
And thats a pretty basic example!
So my question is,
How would I go about re-routing to the other controllers once the decision has been made?
Broadly speaking, its kind of messy doing this with CodeIgniter. Coming from java land the RequestDispatcher.forward() takes care of these sorts of things, but in PHP space its usually a redirect(): there typically isn't the server side infrastructure to (effectively) pass requests from one PHP file to another without the client-side round trip.
Looking through Google's eyes: http://codeigniter.com/forums/viewthread/55212/P15/ is a long discussion with a CI helper that claims to let you do this, http://codeigniter.com/wiki/Wick/ is a library that appears to actually do it.
Let me know if either of those work out: you might be better off refactoring those out, but that does get tedious after awhile so I can understand the desire to just pass the handling off to the other controller (why bother round-tripping if you don't have to).

Categories