CodeIgniter MVC data manipulation best approach - php

I'm developing a website in CodeIgniter. It's kind of basic, except it has some enormous forms (150 fields) some dynamically created/locked/predefined/removed etc..
I'm having trouble doing the transition between the form and the database, which of course is very complicated. What I mean is that the submit of the form inserts more than one line in some tables and some data is not even saved. (some radio buttons etc..)
I have created a very large object with as many properties as possible named after the form input names in order to fill with the $_POST data using:
foreach ($largeObj as $key=>$value)
{
if (isset($_POST[$key])){
$largeObj[$key]=$value; //mind the data escaping
}
}
Of course this only works for half the inputs, for the others I need to do something like this:
$largeObj['tanks']=Array();
for ($i=0;$i<$_POST['nbrTanks'];$i++){
$tank=new Tank();
// some if's in order to set some properties
$largeObj['tanks'][]=$tank;
}
Then I do all the calculations and prepare my DTO's to insert in each table the corresponding data. Btw I used PHPDAO to map the database tables as they were a bit too large to write the entire CRUD operations.
Is there a better approach? something annotation-driven or a more efficient way because I also need to fill the entire forms with the data from my DB. Any suggestions are welcome.

If you have a list of the inputs that go to either method, you can do something like this:
##Array of items to be checked with `isset()`
$array_isset = array('field1', 'field2', 'field3');
foreach ($array_isset as $line) {
#.... same thing you did before
}
$array_tank = array('field4', 'field5', 'field6');
foreach ($array_tank as $line) {
$tank = new Tank()
}
If I understand your question, the above method would allow you to sort the fields by the operations that need to be performed on them.
That being said, I've had multiple projects where I've had to deal with large amounts of information. What I found, every single time, was that the best approach is to find a way to put the raw data in to the database, and perform your calculations at a later date.
This also makes it easy, because in CodeIgniter, you can just do this:
$array = $this->input->post(NULL, True);
$this->db->insert('table', $array);
If your form fields match up with your database column names.
If you have a list of data, then you can store the data as a comma-separted list like this:
$array = array('value1', 'value2', 'value3');
$insert_string = implode(',', $array);
And explode it when you select it.
This may not work in your situation, but it does have value in certain situations.
Good luck with your application; I hope I helped!

Related

Is there a way to reduce multiple comparison with similar parameters?

I am using php as backend of a website. I made a form of around 50 questions and I have to store it in a table every single time I answer something different.
So my first newbie thought was to compare the $request->Question1 with the $table->Question1 and if this is different, I create a new record on the History table.
But it took my to an endless and nothing good looking comparison lines, repeating some of the code like:
if ($table->Question1 != $request->Question1)
{
$Question = new HistoryTable();
$Question ->reason = 'Change Answer';
$Question ->column_affected = 'Question1';
$Question ->old_value = $table->Question1;
$Question ->new_value = $request->Question1;
$Question ->created_at = Carbon::now();
$Question ->save();
}
Is there a way it could be reduced ? I was thinking in using a form, but I have to mention I have columns/values as Question23_1 and Question23_2 ... but they are the same name as in table
Thanks in advance!
Well, some might suggest a different database-table architecture – one that does not involve these "repeating groups." But there might be other compelling reasons to have done what you did.
Maybe you could retrieve the record, instead of as a "PHP object," as an array ("hash" ...) indexed by field-name. Then you could use interpolation of strings such as "Question$x_$y" ... substituting the values of $x and $y to obtain the name of the field whose value you are now interested in ...

php include array vs mysql query: good idea?

I have an 2D array with a few sub-arrays (about 30, and sub-arrays have 10 elements).
I need to get quite frequently basic data from the array , I have a function that return the contents of it (or partial) all around my scripts. The function looks like:
function get_my_data($index = false){
$sub0 = array(
'something' => 'something',
'something else' => 'else',
...
);
$sub1 = array(
'something' => 'something different',
'something else' => 'else different',
...
);
...
$sub30 = array(
'something' => 'something 30 times different',
'something else' => 'else 30 times different',
...
);
$data = array($sub0,$sub1,$sub2,...,$sub30);
if($index !== false)
return $data[$index];
else
return $data;
?>
And then I call to it using include:
<?php
include 'my_data.php';
$id = $_GET['id'];
$mydata = get_my_data($id);
...
?>
I've done this because when I was starting this project, I didn't imagined I would have more that 10 sub-arrays, and I neither that I would need to have it dynamic. In fact, now I have to add a dynamic column (an index to sub-arrays) and it is not a great idea to use array declaration in this case. I immediately thought to use database, transferring data would not difficult, but if I do that, then I need to change my function get_my_data and insert a query in it, so, for it's called many times, I would have a lot of queries, pretty much every script of my website have one of it. I think performance would be worst (cause mysql is already largely used in my website). The dynamic data would change not too frequently (client do that).
The ideas I have to solve this problem are:
save all data in database and get it through mysql queries,
leave on php side and use files to manage dynamic data,
leave the static part on php side, add a logical connector (such 'id' index in sub-arrays) and id column in mysql database, and get the dynamic data on mysql
I don't want to lose much performance, do yo have any advice or suggestions?
Putting data like this in code is the worst possible plan. Not only do you create a whole bunch of junk and then throw out almost all of it, but if any of this changes it's a nightmare to maintain. Editing source code, checking it into version control, and deploying it is a lot of work to make a simple change to some data.
At the very least store this in a data format like JSON, YAML or XML so you can read it in on-demand and change a data-only file as necessary.
Ideally you put this in a database and query against it when necessary. Databases are designed to store, update, and preserve data like this.
You can also store JSON in the database, MySQL 5.7 even has a native column type for it, which makes this sort of thing even easier.

Laravel 4/PHP: Dynamic where clauses if a variable is not null

Is there a way to create a dynamic sql query so that certain where clauses only run if a variable isn't null?
So say a user can select various options to filter results and they can chose not to select a an option from certain dropdowns if they don't need to. That would result in certain variables being null.
I'd like to do it in a way that wouldn't result in writing if statements to cater for every eventuality.
Don't mind suggestions in PHP or Laravel specific answers.
Thanks!
I'd prefer the if statements, but you can look into the Coalesce operator: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_coalesce
Create a client-side jQuery function
One of the things you could do is write a bit if jQuery that goes through all your input client-side and only submits the input where the value is not empty/null. The jquery code could be used for all your forms or input data. So you simply never get the passed parameters that have null values coming into your server-side controller (and eventually into your dynamic query). You can find solutions in this stackoverflow question here for this. Personally, I just have all my input in a class and cycle through it to remove the empty values. See my simple Fiddle here. You can even create special conditions for special types of inputs, that way your script covers for all types of null/empty/etc if you wanted.
OR
Create a helper function in PHP/Laravel
You could also do this server-side. You could write a helper function that loops through all your input coming in and removes the empty inputs. It could also build the WHERE clause at the same time for you (either raw, or you could pass your query object into the helper and it could add each ->where as it loops through the input and returns the query object back to you).
$query = DB::table('my_table')->select('abc', 'xyz');
// This could be your helper. Pass in your query and input...
dynamicWhereHelper($query, Input::all());
$rows = $query->get();
and in your dynamicWhereHelper:
function dynamicWhereHelper($query, $input = array())
{
// Assuming you named each of your inputs the same as your database fields
foreach ($input as $key => $value){
if(!empty($value)){
$query->where($key, $value);
}
}
}
NOTE: A safer approach would be to additionally pass an array of acceptable input names in order to verify that no random $key is passed into the WHERE. You can define this array once per page you build, and it could be used to both build your form and then later used in the helper: dynamicWhereHelper($query, Input::all(), $acceptableInputs);

How to bulk insert with RedBeanPhp?

I was hoping for an example on how to bulk insert new "beans" in readbeanphp without looping over each instance.
It shows an example creating and saving a beans here: http://redbeanphp.com/manual/create_a_bean
It makes mention of storeAll($beans) method, but I am unsure exactly how I am suppose to format the data in $beans.
I have tried googling for this and can not find anything related to bulk inserts. Maybe I have searched for the wrong terms.
I am new to this ORM, any help with would appreciated, thanks!
You are definitely right on track. Create a new bean using $bean=R::dispense('bean'); or multiple beans as an array $beans=R::dispense('bean',5);
Then you populate the beans with data:
$bean->title='Hello World!';
//or with an array
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World! Bean 1';
//etc
Then store the bean(s):
R::store($bean);
//or
R::storeAll($beans);
All the beans must be the same type if you have multiples as far as I know, so you can do something like:
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
I could be wrong about that though. The main thing is that this is all a typical ORM, but redbean also supports regular SQL if you need to use it. Hope that helps!
Some real data behind this approach.
FIRST APPROACH.
foreach item found
$bean = R::dispense('bean');
$bean->title = "hello";
R::store("bean");
time taken for 5660 rows = 43s on my mac
SECOND APPROACH.
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
For 5660 rows, 46s. The storeAll is where all the time is. So its taking ages to store these beans.
THIRD APPROACH
$beans=R::dispense('bean',5560);
for loop
$bean[$i]->title = "hello world";
end for
R::storeAll($beans);
For 5660 rows 45s.
Result. None of these approaches are any quicker. : (
RedBean Transactions didn't seem to make this any quicker either
From the creator of RedBean https://stackoverflow.com/a/18811996/445492 Bulk Insert is not supported, use pure sql.
FOURTH APPROACH
for loop
R::exec("insert into bean(title) values (1,'hello world')");
end for
for 5660 rows 7.3s <----- WOW
(please note: I am actually doing some stuff prior so all these results are -4.3 seconds.)
Hence every bean needs to be created first and the method to create a bean is dispense
$bean = R::dispense('customers');
$bean->name = "John";
R::store($bean);
$bean->name = "Walter"
R::store($bean);
the code above creates only one bean even after storing it. Still $bean refers to the same object, so for each record you have to create a new been by using dispense method.
Luckily we have storeAll method that stores all the beans but it requires an array of beans. So we create a bean in each iteration and push it to the array and then at the end of loop we just pass that array to storeAll function.
//create empty array
$beans = array();
//for each customer post create a new bean as a row/record
foreach ($post as $customer) {
$bean = R::dispense('customers');
//assign column values
$bean->firstName = $customer['first_name'];
$bean->lastName = $customer['last_name'];
//push row to array
$beans[] = $bean;
}
//store the whole array of beans at once
R::storeAll($beans);
In the approaches 1, 2 and 3 suggested by John Ballinger, one way to optimize the run time is to put all the insertions performed by storeAll($beans) inside one database transaction. This could be done as follows: replace the line "R::storeAll($beans)" by the following three lines:
R::begin();
R::storeAll($beans);
R::commit();
This approach reduces dramatically the run time when the array $beans is large, AND is not necessary to use SQL "explicitly".

Store a PHP array in a single SQL cell

I wish to store the ingredients if an item as an array or similar data type in my SQL Database and cannot able to find satisfactory information on the subject
In PHP, the information will get stored as ingredient["$id"]=true or false, where $id represents an ingredient
So for plain bread (please note this is mostly still pseudo code as the data entry side has not yet been started)
//code that creates array this bit is still theory and will be manually emulated in the db for the time being
$id=1;
while (isset ($_POST["ingredient part of form".$ID])){
if ($_POST["ingredient".$id]==checked){
$p["ingredient"][$id]=true;
}
else{
$p["ingredient"][$id]=false
}
$id++;
}
//the code that gets the values back for the ingredient name we will use a separate array ingredient_n[$id]
echo p[$prod_id]["item"].': '
$id=1
while (isset ($ingredient[$id])){
if ($p[$prod_id]["ingredient"][$id]==true)
if ($id!=1){
echo ', ';
}
echo $ingredient_n[$id];
}
}
echo '.';
This should produce something like
'PLAIN BREAD: WHEAT FLOUR, WATER, SALT, YEAST.'
I looked in to ENUM and SET but that would make adding new ingredients harder
Judging by the topic (Store a PHP array in a single SQL cell) you should serialize this. There are standardized methods for that
$array["a"] = "Hello";
$array["b"] = "World";
$array["c"] = "!";
$str = serialize($array);
// The contents of $str
// a:3:{s:1:"a";s:5:"Hello";s:1:"b";s:5:"World";s:1:"c";s:1:"!";}
To reverse use unserialize
$unserializedString = unserialize($str);
You can use this for both arrays and objects.
http://php.net/manual/en/function.serialize.php
I wish to store the ingredients if an item as an array or similar data type in my SQL db an cannot find satisfactory information on the subject
If serialising data is the answer to a database-oriented question, chances are that you're asking the wrong question. Normalise your database, and you'll probably insert the ingredients into a separate table, using a JOIN to retrieve them. This makes your database easier to use, more searchable and more maintainable.
That said; there are cases where storing a serialised string is actually the most viable solution, but this one doesn't seem to be that case.

Categories