How to prevent duplication of code - magento

We're currently developing an E-commerce site. We have a public and admin module.
Sometimes we offer the same functionality in both modules like viewing of products or creating of orders. But there are also some functionalities that is present in either public or admin like adding of products (which is in admin).
Our problem is that common functionalities lead to duplication of logic. We need to implement it in both modules.
One way of solving the problem is to make use of layers. So what we did was move the common logic into the Model. However, the controller is still duplicating codes like the one shown below:
public function invoice() {
$this->Invoice->create();
$this->Invoice->setCustomer($this->getCurrentUser);
$invoice_items = // get list of items from post
$this->Invoice->setItems($invoice_items);
$this->Invoice->save();
}
My question is, is it wise to create a webservice that will encapsulate this logic and you just have to call it from the admin and public modules..
How does Magento implement the public and admin panels. And how does it manage its logic..

I would recommend you not to do that. From your question, it is not exactly clear what sort of 'logic' are you referring to, but it does not seem too complex from your example. In general, business logic should be coded within the Model, controller, or Helper portions of the code. It can even reside in a separate extension as long as you set dependencies properly in the main xml file of the extension.
It seems that you may benefit from placing your logic in a helper class. The default helper file resides under /app/code/community/company/extension-name/Helper/Data.php. Then you can call the helper method anywhere in the backend (Block, Module, or controllers) by using this piece of code:
Mage::helper('extension-name')->getLogic()
Or you can call the same helper method from the view (phtml files) like this:
$this->helper('extension-name')->getLogic()

Related

How to handle conditional rendering of views related to same controller's action?

I am developing a simple CRMish application. Let's say I can create tasks and clients. Both can be created independently, but they can also be created in a process. I have a views called create.blade.php for these two actions.
When you are creating a task for example, at some point you have a button choose a customer / create a customer which opens a modal dialog (so you can pick a customer and assign it to a task in one step :)). And here it starts to get muddy. I want my form part from create.blade.php to be rendered in modal dialog and to do so I need to fetch this hitting my create action, which normally returns full form that extends master.blade.php.
How would you handle this kind of design problem? For now it would be a little, innocent switch or if before return view() in my create action but I know that it will look like spaghetti carbonara at some point.
My ideas are as follows:
ifs/switch as long as it's readable and it's only about returning
different views (but you know it will include logic, different
variables etc. at some point..)
move ifs/switch logic to some request class and call return
view($request->getView()) so my controller will be a little bit
cleaner and follow SRP
create different classes for "ajax" requests, and "normal" requests.
same as above but because the logic of fetching some data used in
form etc. are common for both of the scenarios I can create a base
abstract class of TaskController and than extend this for "normal"
request and "ajax" request scenario. This is most advanced idea, but
I think i follow SRP as well as I remove code duplication cause
fetching common data will be placed in abstract class
Do you have any other ideas of how to handle this?
I have ended up with a little conditional in my create.blade.php view.
#extends((( Request::ajax()) ? 'layouts.modal' : 'layouts.master' ))
According to #Kristo I wont overengineer, and stick with this simple & readable solution.
UPDATE
I have created a little extension, as I decided that I will not load my modals via Ajax but simply inject them on compile time. Here is the code :)
https://github.com/3amprogrammer/modal-blade-extension

Input validation in MVC

I need a little help regarding design of MVC .
Most of the tutorials of MVC and CODEIGNITER are doing input validation in controller. Is it a good practice ?Suppose we implement REST or SOAP API then we are going to have different controllers, and for all those controllers I need to replicate my code. Later if any of the validation rule is changed, it will get rippled into all controllers. Shouldn't all the validation should be inside Model instead of Controller ?
One more thing I would like to ask. As I am trying to keep my functions as cohesive as possible, I am getting one to one relation between functions of model and controller. Is it ok or I am doing things wrong ?
Regarding doing input validation in Controller
Ans. Yes, that is the generally accepted practice in most MVCs. However, during the past few years, due to the advent of AJAX frameworks and more adoption of JavaScript, many UI validations get done in UI itself(called client-side validations). These are generally displayed as javascript alert boxes and do not allow user to go ahead unless he fixes these errors. So, I would say Controllers/View helpers are de-facto places where validations are done but you should consider client-side validations wherever feasible. It also saves you trips to the server.
If you expose the same as functionality as SOAP/REST
Ans. Now-a-days you can annotate the same controller methods to make them work as web service endpoints. So, your controllers can service both web-based requests and also SOAP/REST requests.
But one note of caution - your form-beans/backing beans should be very well designed. I have seen code where hibernate model objects are used as form-backing objects. This makes it tricky when you generate a WSDL out of the form-backing objects as hibernate model objects may have many linked entities and one ends up with very complex xml structures in the request/response.
But still, if you design your backing-beans as fine-grained, i.e. not having complex objects, then you should be comfortably placed in using your existing controller/controller methods as web service endpoints for both SOAP/REST.
Regarding the validations being inside Model layer
Ans. You can use this thumb rule to determine where to place which validations -
Business validations should happen in models/services
complex client validations, which are not feasible in client-side, should happen in controllers/view helpers
UI validations (formatting/empty checks) should happen via client-side/javascript validations
Regarding one to one relation between functions of controller and model/service
Ans. Its fine. Just remember to have one controller method talk to its respective model method. And if multiple models are needed to service a request, then that model method should act as an aggregator of information from multiple models i.e. the controller should contact its main model and the main model should contact other models.
Is it a good practice? In my experience yes.
One thing to keep in mind is that any given controller can display an number of different pages. For example, consider a "Dashboard" which could have multiple tasks each of which requires its own page.
A rough pseudo-codeish "Dashboard" controller might look like this:
class Dashboard extends CI_Controller {
public function __construct(){
parent :: __construct();
$this->load->helper(array('form', 'url'));
$this->load->library('form_validation');
$this->load->model('somemodel_model');
}
public function index(){
//displays a task selection page with links to various tasks
}
public function admins(){
//some kind of interface to display and edit admin level users
}
public function users(){
//CRUD for dashboard users
}
}
With this controller the task selection page is opened with baseurl/dashboard, adminstrator's page with baseurl/dashboard/admins and user CRUD with baseurl/dashboard/users. Because each of these share the same Class, code needed by all/many of these pages (like validation) can be implemented in the constructor and/or with private methods. You probably already know all this. Keep in mind that AJAX responders can also reside in a controller using the same technique.
In regards to keeping the validation rules DRY and easing the work required for changes to rules CI can store sets of rules in a config file for easy reuse in multiple situations. Read about it.

Generating Navigation for different user types, MVC, PHP

I have this idea of generating an array of user-links that will depend on user-roles.
The user can be a student or an admin.
What I have in mind is use a foreach loop to generate a list of links that is only available for certain users.
My problem is, I created a helper class called Navigation, but I am so certain that I MUST NOT hard-code the links in there, instead I want that helper class to just read an object sent from somewhere, and then will return the desired navigation array to a page.
Follow up questions, where do you think should i keep the links that will only be available for students, for admins. Should i just keep them in a text-file?
or if it is possible to create a controller that passes an array of links, for example
a method in nav_controller class -> studentLinks(){} that will send an array of links to the helper class, the the helper class will then send it to the view..
Sorry if I'm quite crazy at explaining. Do you have any related resources?
From your description it seems that you are building some education-related system. It would make sense to create implementation in such way, that you can later expand the project. Seems reasonable to expect addition of "lectors" as a role later.
Then again .. I am not sure how extensive your knowledge about MVC design pattern is.
That said, in this situation I would consider two ways to solve this:
View requests current user's status from model layer and, based on the response, requests additional data. Then view uses either admin or user templates and creates the response.
You can either hardcode the specific navigation items in the templates, from which you build the response, or the lit of available navigation items can be a part of the additional information that you requested from model layer.
The downside for this method is, that every time you need, when you need to add another group, you will have to rewrite some (if not all) view classes.
Wrap the structures from model layer in a containment object (the basis of implementation available in this post), which would let you restrict, what data is returned.
When using this approach, the views aways request all the available information from model layer, but some of it will return null, in which case the template would not be applied. To implement this, the list of available navigation items would have to be provided by model layer.
P.S. As you might have noticed from this description, view is not a template and model is not a class.
It really depends on what you're already using and the scale of your project. If you're using a db - stick it there. If you're using xml/json/yaml/whatever - store it in a file with corresponding format. If you have neither - hardcode it. What I mean - avoid using multiple technologies to store data. Also, if the links won't be updated frequently and the users won't be able to customize them I'd hardcode them. There's no point in creating something very complex for the sake of dynamics if the app will be mostly static.
Note that this question doesn't quite fit in stackoverflow. programmers.stackexchange.com would probably be a better fit

MVC - Codeigniter

Where should intermediate code be placed? (something that ins't just storing/retrieving data from DB nor processing requests/views)
For example,
Say I have Listings and I create CRUD functions in the model. These Listings may require more complex tasks such as pausing and resuming, which may require some time calculations, error setting, etc. Should these be placed in the model or should I wrap a simple model in a library and use that as a middleman for the model?
At the moment I'm thinking of using Drivers/Libraries and keeping models rather simple, except for some dynamic SELECT filters. I'm getting a bit confused though, since I'm guessing I'd probably have to recheck variables, dependencies, etc in the model after doing it in the library, yes?
I'd most likely either squish everything together in the model and check once or separate and check twice?
The general rule of thumb is:
1) Perform all business logic in the models.
2) Perform actions like a traffic cop would in controllers. (directing users to new views based on results of activities.)
3) Perform only presentational logic in views.
Anything else that you would like to do that would be considered, "intermediary", could reside in a Library or Helper.
It should be noted though that if you write a Library, don't forget to get an instance of the current CI object in your class so that you have it to use with your internal class methods.
class Your_lib {
$CI =& get_instance();
...
}
Hope that helps.

Codeigniter Inter Controller Communication

I am new to MVC, CodeIginter. Instead of getting things easy, it needs lot of code to be written for a simple application. These are might be happening becouse I am new. So I have few confusions about this thing. Any kind of help is appreciated.
1) Methods are written in one controller can not be accessed in another controller classes. I have to write a new function for the same functionality.
2) To create website administration panel (back-end) in none mvc panel, we usually create it in a new folder. Is this thing possible in CodeIgniter? If not what about the admin (back-end)??
Let's try to clear some of your doubts about this.
1) Calling a controller's method from another controller is not possible, and it's whtouth meaning by the way.
A controller is supposed to get an action from the URL (which is routed by CI to the right controller for the task) and, based on that, decide which Model and which model's method needs be called to elaborate the data requested.
The model, then, hands back the result of this elaboration to the controller, which , in turns, decides to which view pass this results.
The view, eventually, is structured to get those datas and display them.
SO, as you can see, calling a controllers' method from another controller is nonsense, it would be like going to a page and finding another one instead; if you want to pass to another controller the request...well, there's the redirect for that.
If you find out you have the same functionalities in several moment, think twice:
What is a funcionality? Do you mean somehtin like "display posts" in controller "archive" and "display posts" in controller "news" ? they're hardly the same functionality; they can maybe share views, or models, but that's it.
For functions that doesn't relate to URLs, but involve some further elaboration (which might be wrong to do in Models) and are nonetheless called in a controller, you have library instead. Think at the "form_validation" library, which is called in a controller's method, but has its own peculiar (and encapsulated) functionalies. Ora a "session" library, or an "authentication" library
2) To create an admin panel the easiest thing is: create an "admin" controller (which is accesible then to www.mysite.com/index.php/admin), and put all the administration actions there, in its methods: create_page(), edit_page(), manage_users(), whatever.
In order to avoid people accessing it freely you need to build an authentication system, which, in its simplest and barabone strucutre, might be a check of wheter a session is set or not (maybe a check done at __construct() time).
But you can find nice Auth libraries out there already made, such as Ion Auth or Tank Auth (the 2 most popular to my knowledge)
Hope things are a bit clearer now. See also Interstellar_Coder's comment at this answer if you're interested in the modular HMVC approach.
1) Methods are written in one controller can not be accessed in another controller classes. I have to write a new function for the same functionality.
What's the functionality about? Perhaps you should write a library/helper instead, controller's logic should be limited to request flow or something else but not too complicated. For that, put the functionality in the model, or if more general, in library/helper.
2) To create website administration panel (back-end) in none mvc panel, we usually create it in a new folder. Is this thing possible in CodeIgniter? If not what about the admin (back-end)??
I don't get it, could you elaborate more?

Resources