I'm in the creation of my own CMS. I'm doing this with the help of an MVC framework. I think a CMS should be build with a set of standard elements. Like, buttons, textfields and div containers where all the form elements reside in etc.
For instance, when i want to create a basic page then i want to do something like this in a view:
$cmsForm->beginTab('tab name');
$cmsForm->textfield('name', 'default value');
$cmsForm->textfield('email', '');
$cmsForm->textarea('info', '');
$cmsForm->submit('Save');
$cmsForm->endTab();
The problem is, is that i'm not sure where to put these methods. I obviously can't put these methods inside a controller. But perhaps a model is a good place? On the other hand, the model layer is used for storing/retrieving data from a persisten layer, not for returning HTML...
What would be a good place in an MVC architexture for this kind of thing?
This type of code belongs in your view layer. Remember, there's no rule that says your view layer can only be templates.
There's no rule that says what you have to do.
If I was you, I'd write my own class and implement it in framework, because it would be easier to re-factor later in case you need it. Also you won't change the logic of framework accidentally (everything may happen).
On the other hand, the model layer is used for storing/retrieving data from a persisten layer, not for returning HTML
Actually model layer is for business logic.
This clearly is code related to presentation logic, and thus should be in the View. Thought i think, that instead of such strange generator script, you would be better off by writing a template, which view then handles.
Also, your API is horrible. Haven't you even heard about SOLID principles.
If would be much better (but still misguided, IMHO )to have something like:
$foo = new HTML\Form();
$name = new HTML\Input('name');
$name->setValue('default value');
$name->setRules(array('required'));
$foo->addField( $name );
$email = new HTML\Input('email');
$email->setRules(array('required', 'email'));
$foo->addField( $email )
// other fields added
$template = new Template('/path/to/template.something');
$template->bind('form', $foo);
$output = $template->render();
Related
Using MVC I have something like this:
class Controller
{
//returns View
function indexAction()
{
$data = $this->getData($this->id);
$view = new ViewModel();
$view->setVariable('data' => $data);
//used to render HTML template + data above later on
return $view;
}
//gets data from DB
//currently also does business-proprietary computation on data
function getData($id)
{
//repository/dao pattern
$data = $this->repository->getData($id);
//Business Logic "derivation"
foreach ($data as $datum)
{
//that does not go into "Controller
//that does not go into "Repository"
//but where does it go? - that's my question
$derivedData[] = (new Business())->doLogic($datum);
}
return $derivedData;
}
}
Recap
I used Controller to get my data out of DB using Repository pattern, then placed received data into view. But business-related computations are left stranded.
Question
Where do I place my business logic computations that act on the data gotten from repository? The derived data which is to return to Controller later, to be placed into View?
My personal choices of architecture are usually to:
Have small controllers as thin as I can, doing only session and general right checking
Services that are handling all business logic, one (one classe yes) per potential feature I need
Services are querying repositories, and eventually manipulate the data in and out, but usually no Controller, nor view will do a ->save() anywhere.
This means that those services are usually designed to be independent from the database and easier to be tested because they only take care of one and only one task.
In your example, the whole function getData will be a service that I would call GetCarDataById. This assuming that you manipulate Cars, I don't like to leave data wandering alone.
EDIT: to make it clear, this kind of approach is not MVC to some definition, most people interpret MVC as putting all code either in controller, either in repositories (model). To others view, MVC doesn't mean that you have other classes, what I call services, and actually most of my code lives here.
The MVC pattern is clear for me.
From wikipedia:
The model directly manages the data, logic and rules of the
application. A view can be any output representation of information,
such as a chart or a diagram. Multiple views of the same information
are possible, such as a bar chart for management and a tabular view
for accountants. The third part, the controller, accepts input and
converts it to commands for the model or view.
Answering your question. The modifications goes in the model domain.
We are developing an application in Symfony (2.7) that deals with third party entities and usually needs to transform (or fill) objects from one subsystem to another.
Take this example where we need to fill $destinationObject with data stored in $sourceObject:
$sourceObject;
$destinationObject = new DestinationObject();
$destinationObject->setProperty01($sourceObject->getProperty01());
$destinationObject->setProperty02($sourceObject->getProperty02());
$destinationObject->setProperty03($sourceObject->getProperty03());
$destinationObject->setProperty04($sourceObject->getPropertyWithDifferentName());
$intermediateValue = explode('/',$sourceObject->getProperty04());
$destinationObject->setProperty05($intermediateValue[0]);
$destinationObject->setProperty06($intermediateValue[1]);
Manual method (or no method) leads to duplicated code, copy&paste practices, etc.
So my question is:
Where is the propper place to implement this kind of "transformations"?
My ideas so far:
Doing it as a model method like $destinationObject->loadFromSourceObject($sourceObject) is a bad idea (entity coupling)
I don't like the idea of building an utility class full of static methods
...
EDIT: Also, there's a common situation where in $destinationObject we need to load data from both $sourceObjectFromClassA and $sourceObjectFromClassB, so SourceObjectToDestinationObjectTransformer understood as a method returning a new created DestinationObject is not a valid option. I mean, something like this may be needed (bad code coming warning, just for exemplification purpose):
$destinationObject = new DestinationObject();
$destinationObject->loadFromSourceClassA($sourceObjectFromClassA);
$destinationObject->loadFromSourceClassB($sourceObjectFromClassB);
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).
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
I'm using CodeIgniter, and will likely use their template library as I want to keep things extremely simple to use. The content for the template variables will come from the database, but I want the business admins to know what content areas are available. Basically the names of the parameters when they choose a specific template. For instance, Joomla uses an extra XML file that defines each area, whereas Wordpress uses comments within a page template to inform the system that the PHP file is a template. I like the Joomla approach because you don't have to parse the PHP file to find the areas, but I like the Wordpress approach because you don't have an extra XML file associated with every template. Are there other approaches that I'm missing?
I think the nicest way would be to add a small hack to the template parser class. The code looks quite readable and clean in system/libraries/Parser.php. You could insert a hook in that class that can be used to keep track of the variables. I don't know, if it works, but here's a snippet:
class CI_Parser {
var $varCallback;
function setVarCallback($callbackFunction) {
$this->varCallback = $callbackFunction;
}
...
function _parse_single(...) {
$callback = $this->varCallback;
$callback($key);
}
...
//Somewhere in your code
function storeVarName($variableName) {
// Persist the variable name wherever you want here
}
$this->parser->setVarCallback('storeVarName');
You could do this directly in the controller:
// in the controller
print_r($data);
$this->load->view("main", $data);
Or a little more rudimentary, but you could pass to the template a PHP array of variables (or an object):
// in the controller
$data = array();
$data["namespace"] = array(
"title" => "My website",
"posts" => array("hi", "something else")
);
$this->load->view("main", $data);
And then in the view, have a flag to print_r the namespace to show all the vars available, so that business admins know exactly what to use.
// in the view
if(isset($namespace["showAllVars"])) print_r($namespace);
One option would be to call token_get_all on the PHP file (only when your business admins are loading it up), and parse the output of that.
The best approach, in my opinion, is to keep the variable definitions in another place (such as a database table, or a separate file). This will help with testing (i.e., a programmer can't just remove a tag and it's gone) and making sure things are still working as you move on with the application development in time.
Another advantage is that your application logic will be independent from the templating engine.
On a side note, if you expect a lot of traffic, you may consider using smarty instead. We have done extensive testing with most of the templating engines around and smarty is the fastest.