data input abstraction layer? - php

I would like to have a custom function to insert/edit/delete records from a database without
having to write the single queries for each page.
I have thought to proceed like this:
//page.php:
$datainput = new DataInputAbstraction();
$datainput->setTableName = 'portal';
$datainput->setAllowedFields = array('name'=>'defaultvalue','text'=>'','desc'=>'');
$datainput->run();
// DataInputAbstraction.class.php:
class DataInputAbstraction{
//> attr
public function run(){
if (isset($_POST['action']) && $_POST['action']=='insert') {
$filteredData = array_intersect_key($this->allowedFields,$_POST);
//> Do a mysql query to insert $filteredData to $this->table
}
//> Do other stuff if $_POST['action'] == 'edit' | 'del'
}
}
basically the method run() performs the right action based on $_POST['action'].
Filters unwanted variables present with doing an intersect_key with the attribute allowedFileds, after that it builds the query to
INSERT INTO $this->tableName (array_keys($field)) VALUES (array_values($field)) (pseudocode)
Do you think this is a good way to proceed? There are better way or does php offers a similar built-in functionality?
Thanks

In my opinion, if you don't want to use something that is already out there (RedBean is a really nice choice BTW), then you would be good to proceed about this.
I always prefer as much abstraction as possible because it keeps you from making hard decisions about what service to use. For example, you will create a data abstraction layer to handle all your data transactions that way if you change database providers later on the only thing you have to recode is your data abstraction class.
So, I think it's a good idea. My only recommendation would be to make sure you adhere to DRY principals and keep your abstraction layer very modular. The code that uses the abstraction layer shouldn't know anything about how it works, just that it provides the data needed.
Hope that helps.

it will never work in real as you have to set up different field sets for insert and update.
However, the idea itself is good enough and in the form of
$datainput = new DataInputAbstraction();
$datainput->setTableName = 'portal';
if ($action=='insert'){
$datainput->setAllowedFields = array('name','text','desc','timestamp');
} elseif ($action=='update'){
$datainput->setAllowedFields = array('name','text','desc');
$datainput->setWhereConditions = array('id' => $_POST['id']);
}
$datainput->run($action);
would be okay.
However, I myself prefer plain SQL over some abstractions

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.

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.

Registering a new user in the Model layer. Am I doing it right?

I have been reading up on DDD a lot over the last few days and could not find one solid example of how someone would go about simply registering a user on their site so after lots of reading I have stuck this together and I would like your feedback on it because I am sure it is far from perfect, it might even be completely wrong but here it goes:
RegisterController
$userMapper = $this->dataMapperFactory->build('user');
if($userMapper->fetchByUsername($username) !== NULL) {
// Error: The chosen username already exists
}
else {
if($userMapper->fetchByEmail($email) !== NULL) {
// Error: The email address already exists
}
else {
$userDO = $this->domainObjectFactory->build('user');
// Set the properties of the $userDO object here with the ones
// from the registration form
// Insert the new user into the database
$userMapper->save($userDO);
}
}
I have done all the form validation with my own FormValidation class so when I add the properties to the $userDO object they are all 100% ready to be inserted into the database (correct length, type, format, ranges etc) so how does the code look to you?
I think I am on the right track and I would really appreciate any tips on how to improve my code.
Also, the way I am checking if the username they chose has already been taken, is there a better way to do that? Instead of having to create an object each time to check? Like the old way I used to do it with a simple:
SELECt COUNT(*) FROM users WHERE username = 'john'
Thanks.
Some theory-related "blah":
As you might be aware, the core concept of MVC and MVC-inspired design patterns is the SoC. It dictates that you divide these patterns in to major layers: presentation layer and domain model layer.
In this case it is significant, because you current structure of controller contains application logic (the interaction domain logic entities and storage abstractions), whereas a controller should be only responsible for altering state of model layer (and sometimes - the current view) based on user input.
You end up violating bot the above mentioned SoC and also SRP.
Note: in context of web based MVC variations the "user" is a web browser, not the person sitting behind it.
Instead you should encapsulate the application logic in services (as #Gordon mentioned). In a fully realized model layer the different services become something like a public-ish API through which the presentation layer interacts with model.
Though, unlink Gordon, I would recommend your service to be a bit broader. In case of user registration, I would make it a part of CommunityService or maybe MembershipService. A structure that handles all the aspects of the user account management as far as the model layer is concerned.
The code bits:
One way for using in controller would look something like:
public function postUser( $request )
{
$community = $this->serviceFactory->build('Community');
$community->addUser( $request->getParameter('username'),
$request->getParameter('password'),
$request->getParameter('repeated_password'),
$request->getParameter('email') );
}
While this is a valid way, you might already notice an possible problem. Even when user registration need only the minimum of data, the amount of parameters that you end up passing to the service makes it hard to use.
Passing the $request on to service is not a valid improvement. You would just end up violating Law of Demeter. Instead i would recommend something like:
$keys = ['username', 'password', 'repeated_password', 'email'];
$community->addUser( $request->getParameters( $keys ) );
Where the getParameters() method is implemented similar to:
public function getParameters( $keys )
{
$response = [];
foreach( $keys as $parameter )
{
$response[ $parameter ] = $this->getParameter( $parameter );
}
return $response;
}
Domain logic and validation
You mentioned, that some FormValidation class, that you are using to make sure, that your instance of User domain object receives proper values. Actually the data validation is one of the domain object's responsibilities. You still might use a separate validation class, to avoid code duplication, but that would be a dependency, which is injected by domain object's factory to share between instances.
Note: in my personal experience, the duplication for validation is quite rare for anything but the null-checks. Each of complicated validation rule-sets are targeted at fields of one specific domain object. That, in my opinion, makes a validation class quite redundant ... unless you expect to share same validation class between multiple projects.
The code-flow usually is such that, when you need to store the data from domain object, you check if it has not acquired an error state, and if there is an error, you actually dump it in session, for a retrieval after redirect.
if ( $user->isValid() )
{
$sqlMapper->store( $user );
}
else
{
$sessionMapper->storeUser();
}
In this use-case pre-validated input ends up actually being harmful.

Escape SQL queries in PHP PostgreSQL

I have a website with lots of PHP files (really a lot...), which use the pg_query and pg_exec functions which do not
escape the apostrophe in Postgre SQL queries.
However, for security reasons and the ability to store names with
apostrophe in my database I want to add an escaping mechanism for my database input. A possible solution is to go
through every PHP file and change the pg_query and pg_exec to use pg_query_params but it is both time consuming
and error prone. A good idea would be to somehow override the pg_query and pg_exec to wrapper functions that would
do the escaping without having to change any PHP file but in this case I guess I will have to change PHP function
definitions and recompile it which is not very ideal.
So, the question is open and any ideas that would
allow to do what I want with minimum time consumption are very welcome.
You post no code but I guess you have this:
$name = "O'Brian";
$result = pg_query($conn, "SELECT id FROM customer WHERE name='{$name}'");
... and you'd need to have this:
$name = "O'Brian";
$result = pg_query_params($conn, 'SELECT id FROM customer WHERE name=$1', array($name));
... but you think the task will consume an unreasonable amount of time.
While it's certainly complex, what alternatives do you have? You cannot override pg_query() but it'd be extremely simple to search and replace it for my_pg_query(). And now what? Your custom function will just see strings:
SELECT id FROM customer WHERE name='O'Brian'
SELECT id FROM customer WHERE name='foo' OR '1'='1'
Even if you manage to implement a bug-free SQL parser:
It won't work reliably with invalid SQL.
It won't be able to determine whether the query is the product of intentional SQL injection.
Just take it easy and fix queries one by one. It'll take time but possibly not as much as you think. Your app will be increasingly better as you progress.
This is a perfect example of when a database layer and associated API will save you loads of time. A good solution would be to make a DB class as a singleton, which you can instantiate from anywhere in your app. A simple set of wrapper functions will allow you to make all queries to the DB go through one point, so you can then alter the way they work very easily. You can also change from one DB to another, or from one DB vendor to another without touching the rest of the app.
The problem you are having with escaping is properly solved by using the PDO interface, instead of functions like pg_query(), which makes escaping unnecessary. Seeing as you'll have to alter everywhere in your app that uses the DB, you may as well refactor to use this pattern at the same time as it'll be the same amount of work.
class db_wrapper {
// Singleton stuff
private $instance;
private function __construct() {
// Connect to DB and store connection somewhere
}
public static function get_db() {
if (isset($instance)) {
return $instance;
}
return $instance = new db_wrapper();
}
// Public API
public function query($sql, array $vars) {
// Use PDO to connect to database and execute query
}
}
// Other parts of your app look like this:
function do_something() {
$db = db_wrapper::get_db();
$sql = "SELECT * FROM table1 WHERE column = :name";
$params = array('name' => 'valuename');
$result = $db->query($sql, $params);
// Use $result for something.
}

Standard form elements, where to place the code in MVC architecture

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();

Categories