Dynamically create new columns in laravel - mysql

I'm trying to allow admins to create new columns in a sql table from a form that has a fields for the column title, column type and target table. I'm sure I'm not doing this in the most elegant way possible but I'm trying to use the framework rather than have everyone beat me up for directly querying the database. I've created the following controller that almost completely works, however, when I try to use $new_column rather a hard coded string I get an undefined variable exception.
//Capture variables from view
$type = Input::get('type');
$table_name = Input::get('table');
$proposed_name = Input::get('name');
//Convert proposed name into useable column name
$new_column = strtolower(str_replace(' ', '_', (preg_replace('/[^a-zA-Z0-9_ -%][().][\/]/s', '', $proposed_name))));
if($type == 'string')
{Schema::table($table_name, function($table){$table->string($new_column);});}
elseif($type == 'date')
{Schema::table($table_name, function($table){$table->date($new_column);});}
...
//Flash Success
$message = 'Variable "' . $proposed_name . '"" has been successfully created.';
Session::flash('flash_success', $message);
return Redirect::action('VariableManagerController#getIndex');
Is there a way to make this work through the Larval framework or should I just do a raw query to the database?
For the record this will be utilizing a try catch block but that would only further confuse the code above.

$alldata=Input::all();
$table_name = Input::get('table');
Schema::table($table_name, function($table) use ($alldata)
{
$colname=$alldata['name'];
$coltype=$alldata['type'];
$table->$coltype($colname);});
}

Related

Laravel 5 replicate() handle columns that have unique attribute

I am using laravel's replicate() method of a Model to generate a copy of exiting instance. It works fine if there are no columns that are to be unique
In my case there are some columns that are to be unique so I use this
$pr = Products::find(\Input::get('id'))->replicate();
$pr['product_code'] = $pr->product_code . '_'.$pr['id'];
$pr['name'] = $pr->name . '_'.$pr['id'];
$pr->save();
This will make sure that if a product is replicated once it will handle the unique column problem. But if the product is replicated again it will cause the problem again.
How I can I solve this issue
I would set in database product_code and name as nullables and then do something like this:
$product = Products::find(\Input::get('id'));
$newProduct = $product->replicate(['product_code', 'name']);
$newProduct->save();
$newProduct->product_code = $product->product_code.'_'.$newProduct->id;
$newProduct->name = $product->name.'_'.$newProduct->id;
$newProduct->save();
Of course you could wrap this into a function in case you do it in multiple places.
Recently ran into this issue, most efficient and effective was just to use unix time stamp. Here is another example to give you a better idea of what is going on without having to null fields and such.
$page = Page::find($id);
$duplicatePage = $page->replicate();
$duplicatePage->name = 'Copy of ' . $page->name;
$duplicatePage->slug = $page->slug . '-' . time();
$duplicatePage->save();
following #Marcin NabiaƂek's answer I solved the issue with small enhancements
$product = Products::find(\Input::get('id'));
$newProduct = $product->replicate();
$newProduct->save();
$newProduct->product_code = str_replace("_".$product->id,"",$product->product_code).'_'.$newProduct->id;
$newProduct->name = str_replace("_".$product->id,"",$product->name).'_'.$newProduct->id;
$newProduct->save();
This will remove the old _id from the name and product code for an entry which already has _id at the end and then add the new _id.

json encode error when adding a new column in sql

I have a query:
"SELECT Time, Date, Name, Email FROM table"
It converts the results to json to be passed via ajax, the problem is I want a new column in the sql, so I add it to the query:
"SELECT Time, Date, Name, Email, Address FROM table"
now the json encode does not work, I have tried changing data types and using UTF-8 however this did not work, none of the others are using UTF-8 but still work anyway, Thanks.
This is my code to encode to json which does work until I add the new collumn from sql
if ($result = $mysqli->query($query)) {
$tempArray = array();
while($row = $result->fetch_object()) {
$tempArray = $row;
array_push($myArray, $tempArray);
}
echo json_encode($myArray);
}
Solved
The problem was the last column i was trying to get was called "Show" for some reason sql does not like this, i renamed this column to "lol" (temporary) and it works!

Codeigniter -> 2 variables inside a controller

I am trying to set up a filter on my website. Here, I am trying to pass (2) variables (neighborhood and business category). My problem is when only (1) of them is true and the other is false or one variable does not exist. I am trying to pull this data from my URL
mydomain.com/controller/function/neighbrohood/biz-category
which translates
mydomain.com/ny/find/$neighborhood/$biz_filter
When I have both variables then there is no problem.
How do I resolve the page with only 1 of the 2 variables there?
Here is my model:
public function search($neighborhood = null, $biz_filter = null) {
$neighborhood = $this->uri->segment(3);
$biz_filter = $this->uri->segment(4);
// SELECT
$this->db->select('*');
// MAIN TABLE TO GRAB DATA
$this->db->from('biz');
// TABLES TO JOIN
$this->db->join('city', 'city.city_id = biz.biz_cityID');
$this->db->join('zip', 'zip.zip_id = biz.biz_zipID', 'zip.zip_cityID = city.city_id');
$this->db->join('state', 'state.state_id = city.city_stateID');
$this->db->join('neighborhood', 'biz.biz_neighborhoodID = neighborhood.neighborhood_id');
$this->db->join('biz_filter', 'biz_filter.bizfilter_bizID = biz.biz_id');
$this->db->join('biz_category', 'biz_filter.bizfilter_bizcategoryID = biz_category.bizcategory_id');
// RETURN VARIABLES
$this->db->where('neighborhood.neighborhood_slug', $neighborhood);
$this->db->where('biz_category.bizcategory_slug', $biz_filter);
// ORDER OF THE RESULTS
$this->db->order_by('biz_name asc');
// RUN QUERY
$query = $this->db->get();
// IF MORE THAN 0 ROWS ELSE DISPLAY 404 ERROR PAGE
if($query->num_rows() > 0){
return $query;
} else {
show_404('page');
}
}
Example. Say I am looking for a Restaurant in Little Italy:
URL = mydomain.com/ny/find/little-italy/restuarants
This part, I can resolve the query correctly and display the data. The issue is when there is no neighborhood or no category, I cannot figure out how to resolve the data.
I am new to codeigniter and a self-taught programmer, trying to figure this out as I go. Any help would be much appreciated.
Thank you in advance.
first of all it is optional to get the variables from the uri
$neighborhood = $this->uri->segment(3);
$biz_filter = $this->uri->segment(4);
You already have that from your function parameter.
You can check the condition where your $neighborhood or $biz_filter is available or not then you can use condition in your query.
Something like this
if($neighborhood) { // query for neighborhood } elseif($biz_filter) {}
Thanks
First of all you should get the variable values from your controller not your model, you should then pass such values to your controller from your model, its bad coding practice to allow your view interact with the model.
Also, if you want a value of "-" set for the variable. You should set "-" as the return value right from the parameters being passed to the controller.
What you should do is go to your controller and give it the two parameters, set default values for both and also go to your model and make it receive two parameters also, pass the parameters to the model when calling from the controller. Then get back if there are any more errors.

Updating user profile efficiently

Something just came to mind and I'd like to bounce it off:
Say you have a user profile, with 10 fields that the user can edit, and not all of them are required. When issuing update commands, is it more efficient to either:
A) Collect all of the fields, filled in or not, and issue one all encompassing update statement to the server's DB
or
B) Use client side validation to check to see which fields have been filled out or changed, and have a selection of SQL methods that only send and update these fields
or
C) Create groupings, like "updateRequiredFields(...) and updateExtraFields(...)", which would issue one smaller transfer if the changes only belong in one group, however two transfers if both are edited
General consensus? Clearly option B is the far more verbose approach, I'm just wondering if it's worth coding it all out or if it'll actually make a noticeable impact on the server (think "scaled for big data").
You could do something like this on your DB update function:
public function updateFields(array $fields) {
$updateQuery = array();
foreach($fields as $fieldKey => $fieldValue) {
//if $fieldValue is false, leave it unchanged
if ($fieldValue !== false) {
//NOTE: make sure you escape this or use PDO
$updateQuery[] = $fieldKey . '=' . $fieldValue;
}
}
$query = 'UPDATE UserInfo SET ' . implode(",", $updateQuery) . ' WHERE ...';
}
You just need to build $fields array based on what was modified on client side and then pass in with either new value or with false if no change.

Perl Mysql - How to search for specific data based on one "main" match?

User Form Input - City
User Form Input - Venue
User Form Input - Cover
User Form Input - Time
User Form Input - Date
User Form Input - Number1
User Form Input - Number2
(if any are blank they are coverted to '*' on the way in. But could be whatever works.)
my $grabgig = $hookup->prepare(qq{SELECT `VenueNumber`,`Venue`,`CoverCharge`,`SetLength`,`City`,`Owner`,`Date`,`Time`,`Image1`,`Number`
FROM `gigs`
WHERE VenueNumber > ? AND `City` = ? AND `Venue` = ? AND `CoverCharge` = ?
AND Date = ? AND `Number` > ? AND `Number` < ?
AND `Time` LIKE ? LIMIT ?,?});
##########################################
$grabgig->execute('100',$city,$venue,$cover,'*',$number1,$number2,?,'0','6')
or die "Did not execute";
That is a basic example above.
I want to be able to return results based on the City Input.
If more input is present, then narrow down results accordingly.
But the query returns nothing if fields are empty (*).
I tried wildcards and so on then, I experimented with LIKE and NOT LIKE.
This seemingly simple search is driving me nuts.
Can someone help this newbie?
OK, I'm pretty unsure what you mean, BUT, my best undererstanding of what you're trying to do is to query like you do now BUT if a particular field is not populated in the form, to avoid adding that field to the where clause; as opposed to current query which instead does and myField="*".
Correct?
If that's so, you need to build your query, and replacement list, in pieces:
my $sql = qq{SELECT MY_FIELD_LIST_TOO_LAZY_TO_TYPE FROM `gigs` WHERE 2=2};
my #replacement_values = (); # These go into execute() instead of "?"s
if ($city ne "*") {
$sql .= qq[AND city = ?];
push #replacement_values, $city;
}
if ($number1 ne "*") {
$sql .= qq[AND number > ?];
push #replacement_values, $number1;
}
# ... more values processed the same way
my $grabgig = $hookup->prepare($sql);
$grabgig->execute(#replacement_values) or die "Did not execute";
If you want to do it more intelligently (i.e. to generalize), you will have the form fields in a hash; have a config hash mapping the form field name to the DB column name and the operator, and instead do the above as:
my %fields = (
city => ["city" , "="]
,number1 => ["number", ">"]
,number2 => ["number", "<"]
);
my $sql = qq{SELECT MY_FIELD_LIST_TOO_LAZY_TO_TYPE FROM `gigs` WHERE 2=2};
my #replacement_values = (); # These go into execute() instead of "?"s
foreach my $field (keys %form_data) {
next unless exists $fields{$field};
if ($form_data{$field} ne "*") {
$sql .= qq[ AND $fields{$field}->[0] $fields{$field}->[1] ?];
push #replacement_values, $form_data{$field};
}
}
my $grabgig = $hookup->prepare($sql);
$grabgig->execute(#replacement_values) or die "Did not execute";
I am assuming that you want to construct a query where only a few input parameters have valid values and the rest are undefined. If that is indeed what you want, here is what you could do: Construct the query dynamically. Here are the steps you could take assuming you are using CGI.pm and assuming that the where clause is just a series of "this = that" - In your case you have different operators - but the idea is the same.
First construct a "where" string from the CGI query parameter (Sorry untested code):
my $qrystr = '';
foreach ($query->param) {
if (my $val = $query->param($_)) {
$qrystr .= "where $_ = " . $dbh->quote($val) . ' and ';
}
}
$qrystr .= "where 1 = 1";
Now you can just prepare and execute the query : "select * from table $qrystr"
If you want automatic quoting you will have to use bind parameters which is an easy extension of the code above
Update There was a missing "where" in the last true clause "1 = 1" - Sorry, added it now
Sorry, the formatting bar was not appearing so, I rebooted. Now I cannot edit my question or comment.
What I am trying to do is provide a search for the users.
They select a city from a dropdown then some optional data can be entered / selected to narrow the results.
The optional data May or May Not be present in the table, could be a blank field.
I would like the results to show based on the selected criteria of the search in that City.
So, WHERE selected "input city" = "tables city column" look for the other options (ignore that particular criteria if field is empty) and return any matches that exist for that city.
I am then pushing into array in a While for output display.
I guess it would be like a car query. Select make where doors = 2 and color = red and engine = hamsterwheel but, the color field may be empty in the database..