Laravel8 | Vuex: POST error 500 (Internal Server Error) - laravel

I've been learning Vue and Laravel for the last 2 months and recently I started to work on a project in order to apply all the knowledge I've learned so far. I set several GET and POST routes successfully but for some reason, this request keeps failing.
I'm trying to set a simple POST request using Vuex, Laravel and Axios but I keep on getting the 500 (Internal Server Error) and I'm not sure what is causing it. I have the feeling that it may be that the Model is not correctly set up, bcs if I output the data that the controller received, it looks correct but when I instantiate the model and save the data to DB I get the error.
I would really appreciate any help or feedback on my code since I'm in a early stage of my learning curve and there are some things that I'm sure could be optimized.
Route:
//StreamingProviders
Route::get('/api/all-streaming-providers', [StreamingProviderController::class, 'getAllStreamingProviders']);
Route::post('/api/add-streaming-providers', [StreamingProviderController::class, 'addStreamingProviders']);
Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Repository\Dictionaries\StreamingProvidersList;
use App\Models\StreamingProvider;
class StreamingProviderController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function getAllStreamingProviders()
{
$streamingProviders = StreamingProvidersList::$map;
return response()->json([
'allProviders' => $streamingProviders
]);
}
public function addStreamingProviders(Request $request, StreamingProvider $userStreamingProviders)
{
$user = auth()->user();
$data = $request->all();
$userStreamingProviders = new StreamingProvider();
$userStreamingProviders->user_id = $user['id'];
$userStreamingProviders->Netflix = $request->input('Netflix');
$userStreamingProviders->Amazon_Prime_Video = $request->input('Amazon Prime Video');
$userStreamingProviders->Sky_Ticket = $request->input('Sky Ticket');
$userStreamingProviders->Disney_Plus = $request->input('Disney Plus');
$userStreamingProviders->HBO_Video = $request->input('HBO Video');
$userStreamingProviders->save();
return response()->json([
'streamingProviders' => $userStreamingProviders
]);
}
}
FormComponent.vue
<template>
<div class="container">
<div class="row justify-content-center">
<div class="card">
<div class="card-header">
<h2>Select your streaming country</h2>
</div>
<form #submit.prevent="updateUserDetails()">
<div class="card-body">
<div class="form-control">
<select class="selectpicker" id="countryList">
<option v-for="(value, name) in getCountriesList" :key="name" :value="name">
{{ value }}
</option>
</select>
</div>
<div v-for="(value, name) in getAllStreamingProviders" :key="name" class="form-check">
<input v-model="streamingProviders[value]"
type="checkbox"
:id="name"
:value="value"
:name="streamingProviders[value]"
class="form-check-input" />
<label>{{ value }}</label>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-success center-text">Save</button>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import router from '../../routes/index';
export default {
name: 'edituserdetails',
data() {
return {
value: '',
streamingProviders: {
'Netflix': false,
'Amazon Prime Video': false,
'Disney Plus': false,
'HBO Video': false,
'Sky Ticket': false
}
}
},
created() {
this.$store.dispatch('getCountriesList'),
this.$store.dispatch('getAllStreamingProviders')
},
methods: {
updateUserDetails() {
const country = {
'id': $('#countryList').children("option:selected").val(),
'name': $('#countryList').children("option:selected").text()
};
this.$store.dispatch('updateUserStreamingProviders', this.streamingProviders);
this.$store.dispatch('updateCountry', country).then(() => {
router.push('/user-settings');
});
}
},
computed: {
...mapGetters(['getCountriesList', 'getAllStreamingProviders']),
}
}
</script>
Vuex store:
import axios from "axios";
const state = {
userName: "",
country: "",
countriesList: {},
allStreamingProviders: {},
userStreamingProviders: []
};
const mutations = {
UPDATE_USERNAME(state, payload) {
state.userName = payload;
},
GET_COUNTRIES_LIST(state, payload) {
state.countriesList = payload;
},
UPDATE_COUNTRY(state, payload) {
state.country = payload;
},
GET_ALL_STREAMING_PROVIDERS(state, payload) {
state.allStreamingProviders = payload;
},
UPDATE_STREAMING_PROVIDERS(state, payload) {
state.userStreamingProviders = payload;
}
};
const actions = {
updateUserData({ commit }) {
axios.get("/api/user").then(response => {
commit("UPDATE_USERNAME", response.data.name);
commit("UPDATE_COUNTRY", response.data.country);
});
},
getCountriesList({ commit }) {
axios.get("/api/countries-list").then(response => {
commit("GET_COUNTRIES_LIST", response.data.list);
});
},
updateCountry({ commit }, country) {
axios
.post("/api/update-country", country)
.then(response => {
commit("UPDATE_COUNTRY", response.data.country);
})
.catch(err => {
console.log(err);
});
},
getAllStreamingProviders({ commit }) {
axios.get("/api/all-streaming-providers").then(response => {
commit("GET_ALL_STREAMING_PROVIDERS", response.data.allProviders);
});
},
updateUserStreamingProviders({ commit }, streamingProviders) {
axios
.post("/api/add-streaming-providers", streamingProviders)
.then(response => {
commit(
"UPDATE_STREAMING_PROVIDERS",
response.data.streamingProviders
);
})
.catch(err => {
console.log(err);
});
}
};
const getters = {
getUserName: state => state.userName,
getCountry: state => state.country,
getCountriesList: state => state.countriesList,
getAllStreamingProviders: state => state.allStreamingProviders
};
const userStore = {
state,
mutations,
actions,
getters
};
export default userStore;
Streaming Provider Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class StreamingProvider extends Model
{
use HasFactory;
/**
* Attributes that are mass assignable
*
* #var array
*/
protected $fillable = ['user_id', 'Netflix', 'Amazon_Prime_Video', 'Sky_Ticket', 'Disney_Plus', 'HBO_Video'];
protected $table = 'streaming_provider';
protected $cast = [
'Netflix' => 'boolean',
'Amazon_Prime_Video' => 'boolean',
'Sky_Ticket' => 'boolean',
'Disney_Plus' => 'boolean',
'HBO_Video' => 'boolean'
];
public function user()
{
return $this->belongsTo(User::class);
}
}
Do I have to cast the data before saving it to DB?
Are the boolean properties considered $fillable ??
migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class StreamingProvidersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('streaming_provider', function (Blueprint $table) {
$table->id();
$table->string('user_id');
$table->boolean('Netflix')->default(0);
$table->boolean('Amazon_Prime_Video')->default(0);
$table->boolean('Sky_Ticket')->default(0);
$table->boolean('Disney_Plus')->default(0);
$table->boolean('HBO_Video')->default(0);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('streaming_provider');
}
}
Laravel.log:
[2021-10-27 09:12:39] local.ERROR: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' (SQL: insert into `streaming_provider` (`user_id`, `Netflix`, `Amazon_Prime_Video`, `Sky_Ticket`, `Disney_Plus`, `HBO_Video`, `updated_at`, `created_at`) values (1, 1, 1, 0, 0, 0, 2021-10-27 09:12:39, 2021-10-27 09:12:39)) {"userId":1,"exception":"[object] (Illuminate\\Database\\QueryException(code: 42S22): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' (SQL: insert into `streaming_provider` (`user_id`, `Netflix`, `Amazon_Prime_Video`, `Sky_Ticket`, `Disney_Plus`, `HBO_Video`, `updated_at`, `created_at`) values (1, 1, 1, 0, 0, 0, 2021-10-27 09:12:39, 2021-10-27 09:12:39)) at C:\\xampp\\htdocs\\laravel_vue\\Fullstack_Project_Movie_III\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:703)
[previous exception] [object] (PDOException(code: 42S22): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' at C:\\xampp\\htdocs\\laravel_vue\\Fullstack_Project_Movie_III\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Connection.php:486)
Thanks you all!!

You have this error because $table->timestamps(); is missing from your migration so you have to add it, Laravel will automatically create updated_at and created_at column for you.
For every entry and update in laravel it automatically assign value to these columns, so obviously you get this error when they are missing from your database.
After, your migration will look like this:
`Schema::create('streaming_provider', function (Blueprint $table) {
$table->id();
$table->string('user_id');
$table->boolean('Netflix')->default(0);
$table->boolean('Amazon_Prime_Video')->default(0);
$table->boolean('Sky_Ticket')->default(0);
$table->boolean('Disney_Plus')->default(0);
$table->boolean('HBO_Video')->default(0);
$table->timestamps();
});`

Related

Livewire choicesjs component with AplineJS returns Cannot redefine property: $nextTick

I try to get working choicesjs with livewire but I get on the way a lot problems. For now what I try
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class ChoicesLivewire extends Component
{
/**
* #var array
*/
public array $options;
/**
* #var array
*/
public array $selectedOptions;
protected $listeners = [
'reloaded'
];
public function mount()
{
$collection = [
1 => 'Architektur',
2 => 'Bauwirtschaft',
3 => 'Straßenbau',
4 => 'Tiefbau',
];
$this->options = $collection;
$this->selectedOptions = [2];
}
public function updatedOptions()
{
//dump($this->selectedOptions);
}
public function render()
{
$this->dispatchBrowserEvent('reloaded', ['currentSelects' => $this->selectedOptions]);
return view('livewire.choices-livewire');
}
}
than the blade
<div>
<select wire:model="options" x-ref="multiple" x-data="livewareChoices" multiple>
#foreach($options as $key => $option)
<option value="{{$key}}" {{ in_array($key, $selectedOptions) ? 'selected' : '' }}>{{$option}}</option>
#endforeach
</select>
#dump($selectedOptions)
</div>
and my custom js file
import Choices from "choices.js";
window.choices = Choices;
const livewareChoices = {
init() {
if (!typeof Choices === 'function' || !this.$refs.multiple) return;
const self = this
//console.log(this.$wire.livewareChoices)
choices = new Choices(this.$refs.multiple, {
itemSelectText: '',
removeItems: true,
//allowHTML: true,
removeItemButton: true,
});
/*choices.passedElement.element.addEventListener(
'change',
function (event) {
console.log(self.$refs.$attributes)
//self.$wire.set('livewareChoices', event.target.value)
})*/
}
}
window.addEventListener('livewire:load', function () {
window.livewareChoices = livewareChoices;
})
on request choices is getting rendered correctly as I try to select some values choicesjs will break with the following error Uncaught TypeError: Cannot redefine property: $nextTick. What is wrong in this case?

Displaying json data on datatables with laravel resources

I have some data i have stored in my table and i have cast to array and accessing it in my resource like this
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class JobRequests extends JsonResource
{
public $preserveKeys = true;
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
$data = DB::select('select order_data from orders where id=9');
return [
'email' => json_decode($data[0]->order_data)->personal_data->email,
'telephone_number' => json_decode($data[0]->order_data)->personal_data->telephone_number,
'car_registration' => json_decode($data[0]->order_data)->personal_data->car_registration,
'postal_code' => json_decode($data[0]->order_data)->personal_data->postal_address
/**
'commission' => function(){
$final_price = 700;
return (int)$final_price;
}
*/
];
}
}
My data looks like this
{
"personal_data": {
"email": "info#info.com",
"telephone_number": "0999",
"postal_address": "LON",
"car_registration": "GB BHG"
},
"inperson_diagnostic": {
"diagnostic_inspection": "67.30",
"car_wont_start_inspection": "67.30",
"plugin_diagnostic_inspection": "67.30"
},
"tyres": {
"front_wheels": 1,
"rear_wheels": 1,
"wheel_width": 45,
"wheel_profile": 1,
"wheel_rim": 1,
"speed_rating": "w",
"final_price": 90
},
"servicing_and_mot": {
"mot_with_collection_delivery": 75,
"major_service": 304.52,
"full_service": 203.45,
"interim_service": "149.70",
"vehicle_health_check": 50
},
"inspection_services": {
"premium_prepurchase_inspection": 146.38,
"standard_prepurchase_inspection": 104,
"basic_prepurchase_inspection": 86.44
},
"repairs": {
"ABS wheel speed sensor replacement": 964,
"ABS pump replacement": 712,
"Brake pedal switch replacement": 568,
"Air conditioning regas (R1234yf Gas ONLY)": 469
}
}
This is the function i am trying to fetch data with
//Fetch Job Requests
public function jrData(Request $request)
{
//$data = DB::select('select order_data from orders where id=9');
$jobRequest = new JobRequests($request);
$object_json = $jobRequest->toJson();
$object_array = (array)$object_json;
return Datatables::of($object_array)
->addIndexColumn()
->addColumn('action', function($row){
$btn = 'View';
return $btn;
})
->rawColumns(['action'])
->make(true);
}
and this is my blade page
<script>
$(function() {
$('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: '{!! url('jrData') !!}',
columns: [
{ data: 'id', name: 'id' },
{ data: 'email', name: 'email' },
{ data: 'telephone_number', name: 'telephone_number' },
{ data: 'car_registration', name: 'car_registration' },
{ data: 'postal_code', name: 'postal_code' },
{data: 'action', name: 'action', orderable: false, searchable: false}
]
});
});
</script>
This is the data returned by my jrData
{"draw":0,"recordsTotal":1,"recordsFiltered":1,"data":[{"0":"{\"email\":\"info#info.com\",\"telephone_number\":\"0900\",\"car_registration\":\"KGB BHG\",\"postal_code\":\"00200\"}","action":"<a href=\"view_job_request\/\" class=\"edit btn btn-info btn-sm m-2\">View<\/a>","DT_RowIndex":1}],"input":[]}
I get this error on my blade file
DataTables warning: table id=users-table - Requested unknown parameter
'id' for row 0. For more information about this error, please see
http://datatables.net/tn/4
How can i display the data in the datatables?
Ok here is an example:
You have
$data = DB::select('select order_data from orders where id=9');
This really isn't going to give you the data you need.
Try doing this:
$data = YourModel::where('id',$id)->first();
$id is a dynamic id so you can run this to grab anything instead of being static. I'm guessing you are doing a post to get the data, so if you send that through it would be $request->id so you just set it to $id = $request->id; now you're fully dynamic in your eloquent.

Get data from component

I have component: ckeditor. I am trying to get data from it and save it to the database. Every time I save the data using the store function I get an empty record in the database:
public function store(Request $request)
{
$business = Business::create($request->all());
if($request->has('photos')) {
foreach ($request->photos as $photo) {
$filename = $photo->store('public/photos');
Photo::create([
'business_id' => $business->id,
'filename' => $filename
]);
}
}
return redirect()->action('BusinessController#clist');
}
Here is my code of component:
<template>
<vue-ckeditor type="classic" v-model="editorData" :editors="editors" id="description" name="description"></vue-ckeditor>
</template>
<script>
import VueCkeditor from 'vue-ckeditor5'
export default {
components: {
'vue-ckeditor': VueCkeditor.component
},
data(){
return {
editors: {
classic: ClassicEditor
},
editorData: '<p>Content of the editor.</p>',
}
},
}
</script>
The code in create.blade.php:
<vue-ck name="description" id="description"></vue-ck>
I will just add that the store function works fine for textarea input. Thanks for help guys.
Model:
class Business extends Model
{
protected $fillable = [
'title',
'description',
'order',
'visible',
'lang'
];
public function photos()
{
return $this->hasMany(Photo::class);
}
}
I have additional columns there, title, lang etc. But the important column is a description. I do not know why I do not want to download data from this component.

Laravel nova, custom resource tool not appears in edit mode

I have a custom resource-tool working fine in the view panel of a resource, but it dont appears when i go o the edit mode. Is there something i should add to the component or to the Nova configuration to enable the component in the edit mode?
Code in User.php
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('First name', 'firstName')
->sortable()
->rules('required', 'max:255'),
Text::make('Last name', 'lastName')
->sortable()
->rules('required', 'max:255'),
Text::make('Email')
->sortable()
->rules('required', 'email', 'max:254')
->creationRules('unique:users,email')
->updateRules('unique:users,email,{{resourceId}}'),
Password::make('Password')
->onlyOnForms()
->creationRules('required', 'string', 'min:6')
->updateRules('nullable', 'string', 'min:6'),
YesNovaUserPermissions::make(),
];
}
User view:
User edit:
Nova does not seem to allow you to obtain this functionality with a custom resource but you can with a custom field. You basically create a "dummy" field which does not really exist on the model and use a mutator on the model to overwrite the default model saving functionality.
Following the documentation above, you can build a Vue component which will appear within the resource edit form itself, similarly to how I have done with the tags picker pictured below.
Code for that:
<template>
<default-field :field="field" :errors="errors" :show-help-text="showHelpText">
<label for="tag" class="inline-block text-80 pt-2 leading-tight">Tag</label>
<template slot="field">
<div id="multitag-flex-holder">
<div id="multitag-search-holder" class="w-1/2">
<div class="search-holder">
<label>Search Categories</label>
<input type="text" v-model="searchString" #focus="isSearching = true" #blur="isSearching = false" style="border:2px solid #000"/>
<div class="found-tags" v-if="isSearching">
<div v-for="(tag, i) in foundTags" #mousedown="addToSelected(tag)" :key="i">{{tag.name}}</div>
</div>
</div>
</div>
<div class="select-tags-holder w-1/2">
<div class="selected-tags">
<div v-for="(tag, i) in selectedTags" :key="'A'+i" #click="removeTag(tag)">{{tag.name}} X</div>
</div>
</div>
</div>
</template>
</default-field>
</template>
<script>
import { FormField, HandlesValidationErrors } from 'laravel-nova'
export default {
mixins: [FormField, HandlesValidationErrors],
props: ['resourceName', 'resourceId', 'field'],
data: function () {
return {
selectedTags:[],
isSearching:false,
searchString:''
}
},
mounted(){
console.log(this.field)
this.field.value.forEach((tag)=>{
this.addToSelected(tag)
})
formData.append('whereType', 'Tag');
},
computed: {
// a computed getter
foundTags() {
// `this` points to the vm instance
return this.field.tags.filter((tag) => {
if(tag.name.search(new RegExp(this.searchString, "i")) >= 0){
if(this.selectedTagNames.indexOf(tag.name) == -1){
return tag;
}
};
})
},
selectedTagNames(){
var selNames = this.selectedTags.map((tag) => {
return tag.name;
})
return selNames;
}
},
methods: {
/*
* Set the initial, internal value for the field.
*/
setInitialValue() {
this.value = this.field.value || ''
},
removeTag(tag){
var index = this.selectedTags.indexOf(tag);
if (index > -1) {
this.selectedTags.splice(index, 1);
}
},
addToSelected(tag){
this.selectedTags.push(tag)
},
/**
* Fill the given FormData object with the field's internal value.
*/
fill(formData) {
var tagIdArray = []
this.selectedTags.forEach((tag)=>{
tagIdArray.push(tag.id)
})
formData.append(this.field.attribute, tagIdArray)
},
},
}
</script>
Then, you can overwrite how the save functionality works in your model to accommodate for the "dummy" field. Note below instead of syncing the tags directly on the mutator, which will work most of the time depending on your data structure, I had to pass the tags to the "Saved" event on the model to accommodate for when creating a new record and the associated record id is not yet available, thus cannot be synced for a many to many relationship.
public function setTagsAttribute($value)
{
$tags = explode(",", $value);
$this->tempTags = $tags;
unset($this->tags);
}
protected static function booted()
{
static::saved(function ($article) {
$article->tags()->sync($article->tempTags);
});
}

Laravel 5, self reference hasone not work in blade

All
I have Invoice model, and self reference
\\Invoice Model
public function parentInvoice()
{
return $this->hasOne('App\Invoice', 'id', 'parent_invoice_id');
}
for test in web.php it's work
Route::get('self', function () {
$parent = Invoice::find(132);
$children = $parent->parentInvoice->invoice_date;
echo $children;
// 2018-06-08 - it's work
});
but on blade don't work :( Why?
not work! - <b>Date:</b> {{$invoice->parentInvoice->invoice_date)}} <br /><br />
it's work - <div class="header">Korekta faktury nr {{ $invoice->invoice_date
}}</div>
Error: Trying to get property of non-object
Please help :(
This is my function on Invoice model:
private function generateCreditnoteInvoiceChangeData()
{
$config = InvoiceConfig::find(1);
$pdf = \PDF::loadView(
'pdf.creditnote_invoice_change_data',
array(
'config' => $config,
'invoice' => $this
)
);
return $pdf;
}

Resources