PHP Software design pattern based on static classes - php

I've noticed a common pattern in some recently popular PHP libraries such as Laravel for example, where the API is heavily based on static classes and methods. A typical example of how this sort of API looks:
Logger::note('Handle routes for the welcome area of the site.');
Route::match('/welcome/:id', function ($id) {
$name = Model::from('users')->get('name')->where('id', $id);
$body = Template::body('templates/wecome.tpl', array('name' => $name));
HTTP::respond(200, $body);
}
The code seems nicely readable, and the 5 different static classes are autoloaded by Composer, so at first glance this seems like an attractive pattern to use. My question, for those more experienced in designing APIs, is does this seem like a good approach as things scale up?
For one example, I can immediately see some clunkiness on the horizon, if for example I should want multiple logs to be kept. In a non-static pattern I could do this:
$debugLog = new Logger('logs/debug.log');
$errorLog = new Logger('logs/errors.log');
Route::match('/welcome/:id', function ($id) {
$debugLog->note('Handle routes for the welcome area of the site.');
$name = Model::from('users')->get('name')->where('id', $id);
if (empty($name)) {
$errorLog->warn('Name is empty!');
}
}
But this gets difficult to share across many different methods and files.
#file1.php
Route::match('/welcome/:id', function ($id) {
$debugLog = new Logger('logs/debug.log');
$debugLog->note('Handle routes for the welcome area of the site.');
//etc
}
#file2.php
Route::match('/news', function ($id) {
$debugLog = new Logger('logs/debug.log');
$debugLog->note('Handle routes for the news area of the site.');
if ($error) {
$errorLog = new Logger('logs/errors.log');
$errorLog->warn('There is some problem: '.$error);
}
}
Now I am forced to repeat myself in order to instantiate the non-static class all over the place, which clutters up the code at least and arguably makes it harder to maintain.
But, on the other hand, it looks like the every-class-a-static approach doesn't scale easily either. Suppose I want to have multiple logs using the static API; I could try some singletons and factories...
Logger::get('debug')->note('Handle routes for the welcome area of the site.');
Logger::get('errors')->note('Danger!');
But this seems like it is just shifting the API from method names into string arguments (which could be misspelled, etc). And what if I want two different 'debug' loggers?
Either way I lean, static-based on the one side, or instance-based on the other, it seems like I run into limitations as the usage of the pattern grows.
Any advice on the best approach, given that I don't want to have to fill my application with repeated instantiation code, and yet I also want flexibility to grow with more kinds of classes, based on the existing ones?

These static classes in Laravel are actually glorified service locators.
"Syntactic sugar" they call "Facade" (not a good name but that is how Taylor calls them, do not confuse it with http://en.wikipedia.org/wiki/Facade_pattern)
Route::get('/', 'HomeController#showWelcome');
can be written as
$app['router']->get('/', 'HomeController#showWelcome');
read more: http://taylorotwell.com/response-dont-use-facades/

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.

Which pattern to use and how to use it when I have Controller, Business Logic, and Repository?

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.

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).

Handling mysql queries in php mvc

I'm working on an application written in PHP. I decided to follow the MVC architecture.
However, as the code gets bigger and bigger, I realized that some code gets duplicated in some cases. Also, I'm still confused whether I should use static functions when quering the database or not.
Let's take an example on how I do it :
class User {
private id;
private name;
private age;
}
Now, inside this class I will write methods that operate on a single user instance (CRUD operations). On the other hand, I added general static functions to deal with multiple users like :
public static function getUsers()
The main problem that I'm facing is that I have to access fields through the results when I need to loop through users in my views. for example :
$users = User::getUsers();
// View
foreach($users as $user) {
echo $user['firstname'];
echo $user['lastname'];
}
I decided to do this because I didn't feel it's necessary to create a single user instance for all the users just to do some simple data processing like displaying their informations. But, what if I change the table fields names ? I have to go through all the code and change those fields, and this is what bothers me.
So my question is, how do you deal with database queries like that, and is it fine to use static functions when querying the database. And finally, where is it logical to store those "displaying" functions like the one I talked about ?
Your approach seems fine, howerver I would still use caching like memcached to cache values and then you can remove static.
public function getUsers() {
$users = $cacheObj->get('all_users');
if ($users === false) {
//use your query to grab users and set it to cache
$users = "FROM QUERY";
$cacheObj->set('all_users', $users);
}
return $users;
}
(M)odel (V)iew (C)ontroller is a great choice choice, but my advice is look at using a framework. The con is they can have a step learning curve, pro is it does a lot of heavy lifting. But if you want to proceed on your own fair play, it can be tough to do it yourself.
Location wise you have a choice because the model is not clearly define:
You'll hear the term "business logic" used, basically Model has everything baring views and the controllers. The controllers should be lean only moving data then returning it to the view.
You model houses DB interaction, data conversions, timezone changes, general day to day functions.
Moudle
/User
/Model
/DB or (Entities and Mapper)
/Utils
I use Zend and it uses table gateways for standard CRUD to avoid repetition.
Where you have the getUsers() method you just pass a array to it, and it becomes really reusable and you'd just have different arrays in various controller actions and it builds the queries for you from the array info.
Example:
$data = array ('id' => 26)
$userMapper->getUsers($data);
to get user 26
enter code here
$data = array ('active' => 1, 'name' => 'Darren')
$userMapper->getUsers($data);`
to get active users named Darren
I hope this help.

What's the best way to transition to MVC coding?

It's been around 5 months since I picked up a PHP book and started coding in PHP. At first, I created all my sites without any organizational plan or MVC. I soon found out that was a pain..
Then I started to read on stackoverflow on how to separate php and html and that's what I have been doing ever since.
Ex:
profile.php <--this file is HTML,css. I just echo the functions here.
profile_functions.php <--this file is mostly PHP. has the functions.
This is how I have been separating all my coding so far and now I feel I should move on and start MVC. But the problem is, I never used classes before and suck with them. And since MVC (such as cakephp and codeigniter) is all classes, that can't be good.
My question: Is there any good books/sites/articles that teaches you how to code in MVC? I am looking for beginner beginner books :)
I just started reading the codeigniter manuel and I think I am going to use that.
EDIT: Is it possible to have a MVC organization structure to your coding without using cake, codeigniter, etc? Basically just separate say profile.php into 3 different files(the view, controller, model)
to answer your question
Is it possible to have a MVC
organization structure to your coding
without using cake, codeigniter, etc?
Basically just separate say
profile.php into 3 different files(the
view, controller, model)
absolutely...
first file profile.php ( the view, what gets hit by the browser )
<?php
include( 'controllers/UsersController.php' );
$controller = new UsersController();
$controller->profile();
$pageData = $controller->data;
?>
the controller
<?php
include 'models/UsersModel.php';
class UsersController{
public $data;
public $model;
public function __construct(){
$this->model = new UserModel();
}
public function profile(){
$this->data = $this->model->findUser();
}
}
the model
<?php
class UsersModel{
public function __constuct(){
// connect to your db or whatever you need to do
}
public function findUser(){
return mysql_query( "SELECT * FROM users WHERE users.id = 2 LIMIT 1" );
}
}
MVC is just a design pattern. It's not really something you can "code in".
If you like to code in PHP, here is an article regarding MVC in PHP. It has an overview explaining the design pattern, and then an example follows.
How I learned was by going through this tutorial:
http://www.symfony-project.org/jobeet/1_4/Doctrine/en/
The primary focus is to learn the Symfony Framework, but by default, you will be exposed to and learn good MVC principles.
It's not PHP, but see if you can get a copy of Tate's Bitter Java. It will discuss the organizational side of things (how and why the organizational code improves stuff).
I'm a bit hesitant to recommend one of the great Java books for PHP programming, but this book is one of the few that starts with code written without an organizational plan and improves it into a MVC like structure without the use of 3rd party libraries. This way it teaches you what the organization is about from a practical point of view. Hopefully once you understand the pattern, it won't be too difficult to translate the ideas into PHP.
Another alternative is to grab one of the dozens of PHP frameworks and recode to the framework. Doing so will get your results much faster, but the drawback is that you'll likely understand those results in greater detail, and there is a small chance your code will not behave the same after you rewrite it from scratch. We all like to think the new stuff will do everything the old stuff did, but often we forget something (or it behaves differently).
MVC is a "generic" design pattern that is not particular to any language. More of a coding philosophy. On the most basic level it's just separating data from business logic from presentation. Below is a simple example of a "templating" system using MVC. You would be able to swap out any of the parts without breaking anything, and the data is not tied to the formatting/display. This is sample code, not efficient.
Model, get the data:
function getName($id) {
$name = array('_first_'=>'Joe', '_last_'=>'Smith', '_mi_'=>'C');
return $name
}
Controller, processes it:
$name = getName(1);
$name['_fullname_'] = $name['_first_'].' '.$name['_mi_'].'. '.$name['_last_'];
outputView($name);
View, output the content:
// Example html file: <b>Hello _fullname_, how are you</b>
function outputView($view, $data) {
switch ($view) {
case 'xml':
$out = file_get_contents('view.xml');
case 'html':
$out = file_get_contents('view.html');
case 'json':
$out = file_get_contents('view.json');
}
$search_for = array_keys($data);
$replace_with = $data;
echo str_replace($search_for, $replace_with, $out);
}

Categories