I have a form attributes called, name, description and features where features is a multiple checkboxes which is like
feature 1
feature 2
feature 2
feature 4
User can select multiple checkbox at once. I have a database table called product like
-----------------------------------------
id name description features
-----------------------------------------
When user selects the multiple checkbox, i need to insert all checkbox value in the features column. Right now I can echo the selected checkbox value like
$feat = Input::get('features');
foreach ($feat as $key => $n){
echo $feat[$n];
}
but I need those features to insert into the database, for normal insertion, we would do like:
$product = new Product;
$product->name = Input::get('name');
$product->description = Input::get('description');
$product->features = Input::get('features');
$product->save();
but how should i modify the above code in order to save the array value to the database? I am trying to insert the value to same column because i won't be querying it on the basis of features.
It's quite simple. If you know that you won't query the features, it's perfectly fine to store them as Json or a serialized array. But if you will need to query them and they are a key aspect of your application, you should put them in their own table.
I prefer to store arrays in Json-format because it's easier to read and is not specific to PHP. Laravel gives you pretty sweet options to make this work.
At first, declare the features-field of you products-table as json in your migration:
Schema::create('products', function (Blueprint $table) {
// ...
$table->json('features');
});
Then tell your Product-model to automatically cast it to an array when you access it by simply setting a $casts-attribute:
class Product extends Model
{
// ...
protected $casts = [
'features' => 'json'
];
}
That's it. Now the array will be stored as Json, but when you access it with $product->features you'll get an array back.
To make everything even more simple, you should set up a fillable attribute on your Product model:
class Product extends Model
{
// ...
protected $fillable = ['name', 'description', 'features'];
}
This allows for doing something like this in your controller (or wherever you create the product):
$product = Product::create(Input::all());
...instead of newing it up and setting the attributes one by one.
And as mentioned above, be sure you don't need the features to be query-able, meaning you won't encounter situation where you're trying to get certain products only having specific features or something. But if you do need to look up features, you should put them in their own table. Otherwise this approach is just fine because it's more convenient.
Please look to database normalization for information how to store Data which is in a 1:N relationship. You have to create an extra table like "product_feature" with the attributes: ['id', 'product_id', 'function_name'].
Then your Insert function looks like this:
$product = new Product;
$product->name = Input::get('name');
$product->description = Input::get('description');
$product->save();
$feat = Input::get('features');
foreach ($feat as $key => $n){
$product_function = new ProductFunction;
$product_function->product_id = $product->id;
$product_function->function_name = $feat[$n];
$product_function->save();
}
Hope it helps!
You could use the json_encode function to save the array as a json string.
$product->features = json_encode(Input::get('features'));
But I will also agree with #AdrianBR it is a bad idea to saving the array value to the database in a single column.
I had something similar to this although i used ajax to send the values
<div class="row mb-3" id="insert_new_item">
<div class="col-lg-6">
<p>Item Description</p>
<input value="" type="text" name="order[description]" class="form-control product " id="" placeholder="Your Item Description">
</div>
<div class="col-lg-1 col-sm-6 col-12 mt-lg-0 mt-3">
<p>Qty</p>
<input placeholder="0" type="text" name="order[quantity]" min="1" class="text-right form-control qty" id="" min="1">
</div>
<div class="col-lg-2 col-sm-6 col-12 mt-lg-0 mt-3">
<p>Rate/Unit (₦ )</p>
<input placeholder="0.00" type="text" name="order[rate]" class="text-right form-control rate" id="">
</div>
<div class="col-lg-2 mt-lg-0 mt-3">
<p>Amount (₦ )</p>
<input type="text" name="order[amount]" id="" class="text-right form-control amount" readonly value="0" >
</div>
<div class="col-lg-1">
<span><i class="fa fa-times text-danger removeItem" style="font-size: 22px"></i></span>
</div>
So when i console.log(any value) i get this:
["0" : "value 1", "1" : "value 2"]
from my controller i can do this
foreach ($request->description as $key => $description) {
$order = Order::create([
'description' => $description,
'amount' => $request->rate[$key],
'quantity' => $request->quantity[$key],
'invoice_id' => 7
]);
}
You can insert like this,
$candidate_data = array(
'mobile' => $request->get('mobile'),
'password' => $request->get('password')
);
DB::('tablename')->insert($candidate_data);
Related
I'm beginner in laravel and I want to update multiple checkboxes in database ..
when I click at update button automatically my inputs show old value also my permissions are checked by old value to update it ..
relation between user and permission is manytomany .. I have another table named userpermissions who has id_user and id_permission
this is my update form in ( edit.blade.php)
<form action="{{ url('users/'.$user->id) }}" method="POST">
#csrf
#method('PUT')
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Name</label>
<input type="text" name="name" id="name" required class="form-control" value="{{ $user->name }}">
#error('name')
<ul class="alert"><li class="text-danger">{{ $message }}</li></ul>
#enderror
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Email</label>
<input type="email" name="email" id="email" required class="form-control" value="{{ $user->email }}">
</div>
</div>
<div class="col-md-12">
<div class="form-group">
#foreach($permissions as $permission)
<input type="checkbox" name="data[]" value="{{ $permission->id }}"
<?php if( in_array($permission->id, $user->userPermissions->pluck('permission_id')->toArray())){ echo 'checked="checked"'; } ?>/>
{{ $permission->name }}
#if($loop->iteration % 3 == 0 ) <br> #else #endif
#endforeach
</div>
</div>
</div>
<div class="text-right mt-4">
<button type="submit" class="btn btn-primary"> Add</button>
</div>
</form>
and this is my controller where I think have a problem with methods :
edit function
public function edit(User $user)
{
$permissions = Permission::get();
return view('users.edit', compact('user','permissions'));
}
update function :
public function update(UserRequest $request,User $user)
{
$user->update(
$request->only('name', 'email')
);
$user->userPermissions()->save($request->input('data'));
return redirect()->back()->with('status','user updated !');
}
and this is my functio store :
public function store(UserRequest $request)
{
$this->validate($request, [
'name' => 'required',
'email'=>'required|email',
'password' => 'required|confirmed|min:6',
]);
$user = User::create(
$request->only('name', 'email', 'password')
);
$user->userPermissions()->createMany($request->input('data'));
return redirect()->back()->with('status','Utilisateur ajouté !');
}
Thanks for advance !
$user->userPermissions()->save($request->input('data'));
One important thing to understand here, is that save() on relation doesn't remove old values from pivot table, it just add more values to it(no distinction check). You need something like refresh functionality. Look at attaching\detaching or sync, second one is more convenient.
In first case before saving permissions you can do this
// remove all old permissions
$user->userPermissions()->detach();
// update them with new one
$user->userPermissions()->attach($request->input('data'));
In second case, which is less verbose then first one you just need to pass and array of permissions to user object.
// this will do both things which we did before
$user->userPermissions()->sync($request->input('data'))
But i encourage you to read the docs and ask questions after ;)
Another thing which i saw and its not related to the current topic is
$user->userPermissions->pluck('permission_id')->toArray()
you are using lazy load inside of foreach loop which means that on each iteration of the loop you are making a query to the database(N + 1 problem). You can preload/eager load userPermissions instead of loading them on a fly by declaring with relation in your User model like this
class User extends Model
{
/**
* The relationships that should always be loaded.
*
* #var array
*/
protected $with = ['userPermissions'];
...
}
and then in your User object will have userPermissions property which you can compare to permissions.
Hope that you get main idea and info was useful for you!
i have a input fields to insert names to the database at the moment it works like every time i enter one name it inserts and does not allow duplications the name but i want to enter multiple names comma separated this si what i have at the moment
front end
<form method="POST" action="{{route('store.names')}}">
#csrf
<div class="form-group row">
<label for="names"
class="col-md-4 col-form-label text-md-right">Add New Name
</label>
<div class="col-md-6">
<input id="names" type="text"
class="form-control #error('names') is-invalid #enderror" name="names"
value="{{ old('names') }}" autocomplete="names" autofocus>
#error('names')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
Add Names
</button>
</div>
</div>
</form>
Controller
public function store(Request $request)
{
$validation = Names::create($this->validateRequest());
return back()->with('message','Added'));
}
private function validateRequest()
{
return request()->validate([
'names' => 'required|min:2|unique:Names',
]);
}
what this does is it inserts names of one person at a time how can i insert multiple people with comma separated with the validations intact
but this iss what i need
i have figured it needs to be somthing like this
$searchString = ',';
if( strpos($request->names;, $searchString) !== false )
{
// insert in to db separately
}else{
$names= Names::create($this->validateRequest());
}
you could override prepareForValidation to preprocess the data. In this case, it would split the string by your delimiter. Then you can apply array validation using the rules method or your own explicit validation call.
protected function prepareForValidation() {
$this->replace(['names' => explode(',', $this->names)]);
}
public function rules() {
return [
'name' => 'required|min:2|unique:Names',
'names.*' => 'name'
];
}
You can use the explode() PHP function to split the string given by the input field into an array. The array will give you more flexibility to store multiple names.
Example:
explode(", ", "peter, jhon, pete");
Adapt this to your code and you'll be fine!
For more informations about the explode() function you can read the PHP documentation: https://www.php.net/manual/en/function.explode.php
I have a form for a user create custom questions. The user needs to introduce the question and also the type of field (text, long text, checkbox, select menu, radio button). If the user selects one of this types: checkbox, select menu or radio button the div "#availableOptions" appears for the user to write the options for the questions of that type.
My doubt is how to store in the database this options. For now the database has the questions table that is like below but and dont have in account the available options.
For example if the user is creating a custom question "Receive notifications?" and select the type of the question as checkbox, it will appear the #availableOptions div. And the user can write in the first option "Yes" and in the second option "No".
My doubt is how to store in the database that "Yes" and "No" options. Do you know how this can be achieved? And the same for when is a select_menu or radio_btn.
In the database in the questions table is like:
id question conference_id type
1 Whats your phone? 1 text
2 Receive notifications? 1 radio_btn
3 .............. 1 checkbox
4 .............. 1 long_txt
5 .............. 1 select_menu
...
Form for the user create the custom question:
<form method="post" class="clearfix" action="{{route('questions.store', ['conference_id' => $conference->id])}}" enctype="multipart/form-data">
{{csrf_field()}}
<div class="form-group">
<label for="question">Question</label>
<input type="text" class="form-control" name="question" id="question">
</div>
<div class="form-group">
<label for="type">Type of field</label>
<select class="form-control" name="type" id="customQuestionType">
<option value="text">Text</option>
<option value="long_text">Long Text</option>
<option value="checkbox">Checkbox</option>
<option value="radio_btn">Radio Button</option>
<option value="select_menu">Select menu</option>
</select>
</div>
<div>
<input type="submit" class="btn btn-primary" value="Store"/>
</div>
</form>
<div class="form-group" id="availableOptions">
<label for="inputName" class="text-heading h6 font-weight-semi-bold">Available options</label>
<div class="option d-flex justify-content-between">
<input type="text" class="form-control col-md-8">
<input type="button" class="removeOption btn btn-outline-primary col-md-3" value="Remove option"/>
</div>
<div class="option mt-3 d-flex justify-content-between">
<input type="text" class="form-control col-md-8">
<input type="button" class="removeOption btn btn-outline-primary col-md-3" value="Remove option"/>
</div>
</div>
<div class="form-group">
<input type="button" class="btn btn-outline-primary mt-3" id="addNewOption" value="Adicionar nova opção"/>
</div>
<div class="float-right">
Voltar à pàgina anterior
<input type="submit" class="btn btn-primary mt-3" value="Guardar"/>
</div>
Then I have some jQuery, when a option is selected, if is a "select_menu", "radio_btn", "checkbox" it appears a div for the user to
$('#addNewOption').hide();
$('#availableOptions').hide();
$('#customQuestionType').change(function(){
var selected_option = $('option:selected', this).val();
alert(selected_option);
if (selected_option == "select_menu" || selected_option == "radio_btn" || selected_option == "checkbox") {
$('#addNewOption').show();
$('#availableOptions').show();
$('#addNewOption').click(function() {
$('#availableOptions').append(
'<div class="option form-row mt-3 d-flex justify-content-between">' +
'<input type="text" class="form-control col-md-8">' +
'<button class="removeOption btn btn-outline-primary col-md-3">Remove Option</button>' +
'</div>');
});
}else{
$('#availableOptions').hide();
}
});
QuestionController store() method:
public function store(Request $request, $id){
$this->validate($request, [
'question' => 'required|max:255|string',
'type' => 'required|max:255|string',
]);
$conference = Conference::find($id);
Question::create([
'conference_id' => $conference->id,
'question' => $request->question,
'type' => $request->type,
]);
Session::flash('success', 'Question created with success.');
return redirect()->back();
}
Question model:
class Question extends Model
{
public function registration_type(){
return $this->belongsToMany('App\TicketType', 'ticket_type_questions')->withPivot('required');
}
}
You can create a question_options table that looks like this:
id | question_id | value
Create a relationship on the Question model as follows:
public function options() {
return $this->hasMany(QuestionOption::class);
}
And the inverse on the QuestionOption model
public function question() {
return $this->belongsTo(Question::class);
}
In your form name the input fields for the options questionOptions[]
This will allow you to send the options in an array
Then in your store method you will have to do the following:
$question = Question::create([
'conference_id' => $conference->id,
'question' => $request->question,
'type' => $request->type,
]);
if($request->type == 'radio_btn') {
foreach($request->input('questionOptions') as $questionOption) {
QuestionOption::create([
'question_id' => $question->id,
'value' => $questionOption
]);
}
}
Now when you need to get the options you can simply check if the Question type is radio_btn and get the options via the relationship
It might be useful to add this to your Question model:
public function hasOptions() {
return $this->type == 'radio_btn';
}
And then you can easily check if a Question has options and show them (for example):
if($question->hasOptions()) {
foreach($question->options as $option) {
<p>{{ $option->value }}</p>
}
}
-- edit --
To make it easier to see which Question type has options you can add this to the Question model:
public static $typeHasOptions = [
'radio_btn',
'select_menu'
];
This will allow you to add more types that may have options in the future easily.
Then in your Controller method replace:
if($request->type == 'radio_btn') {
with:
if(in_array($request->type, Question::$typeHasOptions))
You can also update the hasOptions method to be as follows:
public function hasOptions() {
return in_array($this->type, self::$typeHasOptions);
}
store in DB with a boolean for your value default value 0 => NO and get the value of your checkbox with
$(".yourcheckbox").change(function() {
if(this.checked) {
//Do the stuff
}
});
and just for your advice, you can refacto this
$('#addNewOption').click(function() {
$('#availableOptions').append(
'<div class="option form-row mt-3 d-flex justify-content-between">' +
'<input type="text" class="form-control col-md-8">' +
'<button class="removeOption btn btn-outline-primary col-md-3">Remove Option</button>' +
'</div>');
});
with a .trigger event of jquery here
or doing like this
var newString = [
'<div id="newDiv">',
'This is a new div',
'</div>'
].join('');
//New div created
$(newString).appendTo('.someClass');
//Append your new div to some class
hi #johnW can you try with this approach
Table Design
Here there is 4 tables
Question table : it will store thr dteails of question (id, question, conference_id, etc ) not storing the field information (text, radio_tbn etc)
Question_fields table : this will store the input type related to the question (id, question_id(fk), field_type_id (fk), value , text ) here value and text optional it will useful for radio button and check box
Field_type table : this will store actual html input type names (id,name) like textbox, radio_btn,select, etc
Select_options : this table is used to store the select box options (if you are adding the select potion in a json format with question_fields table you can remove this table )
Sample Data
I have the code below that is a resume of the process to create a new conference. To create a new conference is ncessary that the user introduce some info like the conference name, etc. The user also needs to introduce between 1 and 3 categories for the conference.
So there is a select element using select2 plugin so the user can select the categories:
<div class="form-row">
<div class="form-group col-lg-6">
<label for="categories">Category</label>
<select id="tag_list" required multiple class="form-control" value="{{ old('categories') }}" name="categories" id="categories">
#foreach($categories as $category)
<option value="{{$category->id}}">{{$category->name}}</option>
#endforeach
</select>
</div>
</div>
Then the laravel code to store the conference info and also the categories of the conference in the conference_category table since there is a many to many relationship between confernece and category:
public function store(Request $request)
{
$this->validate($request, [
'conference_name' => 'required|max:255|string',
'conference_categories' => 'required|array|between:1,3|integer',
]);
$conference = Conference::create([
'name' => $request->conference_name,
]);
$conference->categories()->attach($request->conference_categories);
}
The select2 JS:
$(function() {
$('#tag_list').select2({
placeholder: '',
dropdownAutoWidth: 'true',
width: '100%'
});
});
Errors
If the user selects more than one category in the $request output just appears the id of one category
And it appears a laravel validation error after submit the form "The conference categories must be an array.
"
Do you know where can be the issue?
You gotta change the name attribute of your select to an array, like this and also remove one id attribute from it, it can't have 2
<select required multiple class="form-control" value="{{ old('categories') }}" name="categories[]" id="categories">
What I'm trying to do is get the available credits from the users table and 'credits' field and get the price of the current item in the foreach loop which is the 'normalprice' field in the 'items' table.
When a user fills in the amount he wants to put toward the 'normalprice' of an item, i want to subtract from the number in his 'credits' field, and create a new variable for 'This is the price of the item after you've put credits toward it' and display it.
The users table and items table are on a many-to-many relationship, and i've been able to display a user item by doing
$user->item
What i've done is bellow is wrong, because 'normalprice' in '$item->normalprice;' is not a property. I'm trying to find out how I can make $itemprice equal the value of 'normalprice' in the current #foreach ($user->items as $item)
Controller:
public function allocateCredit(){
$validator = Validator::make(Input::all(),
array(
'puttoward' => 'Integer',
));
$user = Auth::user();
$items = Item::all();
$userItems = Auth::user()->items;
$itemprice = $item->normalprice;
$available = $user->credits;
$goodtogo = ($available > $itemprice) ? TRUE : FALSE;
if($goodtogo === true){
$howmuch = Input::get('puttoward');
$newavailable = $howmuch - $available;
$itembalance = $itemprice - $howmuch;
$user->credits = $newavailable;
}
if($user->save()){
return Redirect::route('account')->with('global', 'Success.');
}
}
View:
#foreach ($user->items as $item)
<div class="sep">
<div class="nameIt">
{{ $item->name }}
<form action="{{ URL::route('allocate-credits-post') }}" method="post" role="form">
<div class="form-group">
<label for="exampleInputPassword1">Allocate credits</label>
<input type="intiger" class="form-control" name="puttoward" placeholder="$0.00">
</div>
<button type="submit" class="btn btn-default">Submit</button>
{{ Form::token() }}
</form>
Since you're using a form submission to call your Controller, why don't you populate the $item->normalprice into the form as hidden type like:
<input type="hidden" name="NormalPrice" value="{{$item->normalprice}}">
Then access the value in your controller with Input::get('NormalPrice')
or if that is not desired for security reason, then you can populate the $item->id instead and find out the price for that ID in your controller.