Trying to implement a comments system using pusher on my laravel project. Everything seems to be in order, however every post request which is meant to send the input data to the database returns with error 500.
Used F12 on firefox to monitor what gets sent to /tip/select, it seems that it passes the text of the comment just fine, so it could be the issue with the controller.
Routes
Route::get('/tip/select','TipController#select');
Route::post('/tip/select', 'TipController#addComment');
Comment model
namespace App;
use Illuminate\Database\Eloquent\Model;
use Zttp\Zttp;
use App\model\User;
use App\Tip;
class Comment extends Model
{
protected $guarded = [];
protected $table='comments';
//protected $fillable=['tip_id','user_id','body'];
public static function moderate($comment)
{
$response = Zttp::withoutVerifying()->post("https://commentator.now.sh", [
'comment' => $comment,
'limit' => -3,
])->json();
if ($response['commentate']) {
abort(400, "Comment not allowed");
}
}
public function tip(){
return $this->belongsTo('App\Tip');
}
public function user(){
return $this->belongsTo('App\model\User');
}
}
Controller
use Pusher\Laravel\Facades\Pusher;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\File;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Input;
use DB;
use Image;
use App\Tip;
use App\model\User;
use App\Subcategories;
use App\Category;
use App\City;
use App\Comment;
use App\CityAreas;
//use App\Http\Requests\TipFormRequest;
class TipController extends Controller
{
public function select(){
//$db=DB::table('tips')->orderBy('created_at','desc');
$data=Tip::get();
$url = Storage::disk('s3');
//$data=Tip::paginate(10);
//$data=$db->get();
// dd($data);
$comments = Comment::orderBy('id')->get();
return view('tip', compact('data', 'url','comments'));
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function create(){
$categories=Category::all();
$cities=City::all();
return view('tip.create',compact('categories','cities'));
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function store(Request $request, City $city, Category $category){
$this->validate($request, [
'image' => 'image|nullable|max:1999']);
$tipsnew = new Tip;
$tipsnew->title = $request->title;
$tipsnew->description = $request->description;
$tipsnew->category_id = $request->category;
$tipsnew->city_id = $request->city;
$tipsnew->user_id = auth()->id();
$tipsnew->url = $request->url;
if ($request->hasFile('image')) {
try{
$file = $request->file('image');
$name = time() . '.' . $file->getClientOriginalExtension();
$img = \Image::make($file->getRealPath());
$img->fit(1080);
$img->stream();
Storage::disk('s3')->put('tip'.'/'.$name, $img->__toString());
$tipsnew->image = 'tip'.'/'.$name;
}
catch (\Exception $e)
{
$response = [
'information' => 'Error. Something went wrong. Please try again',
];
$statusCode = 400;
return response()->json($response, $statusCode);
}
}
$tipsnew->save();
return redirect ('tip/create')->with('status','your tip is created');
}
public function edit($id){
$tip=Tip::whereId($id)->firstOrFail();
$categories=Category::all();
$selectedCategories=$tip->categories->lists('id')->toArray();
return view('tip.edit',compact('tip','categories','selectedCategories'));
}
public function search(Request $request, City $city, Category $category, User $user){
$q = $request->get('q');
if ($q != ""){
$tips = Tip::where('title','LIKE','%'.$q.'%')
->orWhere('description','LIKE','%'.$q.'%')
->orWhereHas('user', function($id) use($q){
return $id->where('name', 'LIKE','%'.$q.'%');
})
->orWhereHas('city', function($id) use($q){
return $id->where('name', 'LIKE','%'.$q.'%');
})
->orWhereHas('category', function($id) use($q){
return $id->where('name', 'LIKE','%'.$q.'%');
})
->get();
if(count($tips) > 0)
return view('tip.search', ['tips' => $tips]);
}
}
public function addComment(Request $request)
{
$data = $request;
Comment::moderate($data['text']);
$comment = Comment::create($data);
Pusher::trigger('comments', 'new-comment', $comment, request()->header('X-Socket-Id'));
//add creation of new comment to DB
$commentnew = new Comment;
$commentnew->user_id = Auth::user()->id();
//$commentnew->tip_id= $request->post(['tip_id']);
$commentnew->body = $request->text;
$commentnew->save();
return $comment;
}
}
Snippet of the blade
<h3>Comments</h3>
<form onsubmit="addComment(event);">
<input type="text" placeholder="Add a comment" name="text" id="text" required>
<input type="hidden" name="tip_id" id="tip_id" value="{{$val->tip_id}}">
<input type="hidden" name="username" id="username" value="{{Auth::user()->name}}">
<button id="addCommentBtn">Comment</button>
</form>
<div class="alert" id="alert" style="display: none;"></div>
<br>
<div id="comments">
#foreach($comments as $comment)
<div>
<small>{{ $comment->username }}</small>
<br>
{{ $comment->text }}
</div>
#endforeach
</div>
<!--jQuery script used to be here -->
<script>
function displayComment(data) {
let $comment = $('<div>').text(data['text']).prepend($('<small>').html(data['username'] + "<br>"));
$('#comments').prepend($comment);
}
function addComment(event) {
function showAlert(message) {
let $alert = $('#alert');
$alert.text(message).show();
setTimeout(() => $alert.hide(), 4000);
}
event.preventDefault();
$('#addCommentBtn').attr('disabled', 'disabled');
var data = {
text: $('#text').val(),
username: $('#username').val(),
tipid: $('#tip_id').val(),
};
fetch('/tip/select', {
body: JSON.stringify(data),
credentials: 'same-origin',
headers: {
'content-type': 'application/json',
'x-csrf-token': $('meta[name="csrf-token"]').attr('content'),
'x-socket-id': window.socketId
},
method: 'POST',
mode: 'cors',
}).then(response => {
$('#addCommentBtn').removeAttr('disabled');
displayComment(data);
showAlert('Comment posted!');
})
}
</script>
Related
I am working on a Laravel 8 app with Jetstream and Inertia and I created a form that has two text fields and one image upload field. The problem is when I edit the resource and upload a new image everything works but when I try to save the resource again immediately after the first time it looks like it is uploading the image again even though the data after the first upload for the field is a URL to the image. The goal is to prevent the second image upload on the second edit as the image is the same - there is no change. If you reload the page after the first edit and save the data again it works fine there is no image upload.
I've uploaded a video here.
I assume the loading indicator below my bookmarks is somehow done by InertiaJS when making ajax requests. Or maybe it is doing a full page reload?
I've spend hours on this, googled various things, looked and tinkered with the code, read InertiaJS documentation and found nothing!
I am using S3 to upload the images to. Also, I am using Spatie's media-library package to handle the images.
here is my Edit page component:
<template>
<app-layout title="Edit author information">
<div>
<div class="max-w-7xl mx-auto py-5 sm:px-6 lg:px-8">
<div>
<create-or-update-author-form :author="author" method="PUT" :blank_avatar_image="$page.props.assets.blank_avatar_image"/>
</div>
</div>
</div>
</app-layout>
</template>
<script>
import AppLayout from '#/Layouts/AppLayout.vue'
import CreateOrUpdateAuthorForm from '#/Pages/Authors/Partials/CreateOrUpdateAuthorForm.vue'
export default {
props: ['sessions', 'author'],
components: {
AppLayout,
CreateOrUpdateAuthorForm,
},
}
</script>
here is my CreateOrUpdateAuthorForm component:
<template>
<jet-form-section #submitted="save">
<template #title>
<span v-if="method === 'POST'">Create new author</span>
<span v-else-if="method === 'NONE'">Viewing author</span>
<span v-else>Update author information</span>
</template>
<template #form>
<!-- Photo -->
<div class="col-span-6 sm:col-span-4">
<!-- Photo File Input -->
<input type="file" class="hidden"
ref="photo"
#change="updatePhotoPreview">
<jet-label for="photo" value="Photo" />
<!-- Current Photo -->
<div class="mt-2" v-show="! photo_preview">
<img v-if="photo_or_blank_image" :src="photo_or_blank_image" :alt="author.name" class="rounded-full h-20 w-20 object-cover">
</div>
<!-- New Photo Preview -->
<div class="mt-2" v-show="photo_preview">
<span class="block rounded-full w-20 h-20"
:style="'background-size: cover; background-repeat: no-repeat; background-position: center center; background-image: url(\'' + photo_preview + '\');'">
</span>
</div>
<jet-secondary-button v-if="method !== 'NONE'" class="mt-2 mr-2" type="button" #click.prevent="selectNewPhoto">
Select A New Photo
</jet-secondary-button>
<jet-secondary-button v-if="author.photo && method !== 'NONE' && !author_photo_is_blank" type="button" class="mt-2" #click.prevent="deletePhoto">
Remove Photo
</jet-secondary-button>
<jet-input-error :message="form.errors.photo" class="mt-2" />
</div>
<!-- Name -->
<div class="col-span-6 sm:col-span-4">
<jet-label for="name" value="Name" />
<jet-input id="name" type="text" class="mt-1 block w-full disabled:bg-gray-100" v-model="form.name" autocomplete="name" :disabled="disabled" />
<jet-input-error :message="form.errors.name" class="mt-2" />
</div>
<!-- Email -->
<div class="col-span-6 sm:col-span-4">
<jet-label for="bio" value="Bio" />
<jet-input id="bio" type="text" class="mt-1 block w-full disabled:bg-gray-100" v-model="form.bio" :disabled="disabled" />
<jet-input-error :message="form.errors.bio" class="mt-2" />
</div>
</template>
<template v-if="!disabled" #actions>
<jet-button :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
<span v-if="method === 'POST'">Create</span>
<span v-else>Save</span>
</jet-button>
<progress-bar :progress="form.progress"/>
<jet-action-message :on="form.wasSuccessful" class="ml-3">
<span v-if="method === 'POST'">Created.</span>
<span v-else>Saved.</span>
</jet-action-message>
</template>
</jet-form-section>
</template>
<script>
import JetButton from '#/Jetstream/Button.vue'
import JetFormSection from '#/Jetstream/FormSection.vue'
import JetInput from '#/Jetstream/Input.vue'
import JetInputError from '#/Jetstream/InputError.vue'
import JetLabel from '#/Jetstream/Label.vue'
import JetActionMessage from '#/Jetstream/ActionMessage.vue'
import JetSecondaryButton from '#/Jetstream/SecondaryButton.vue'
import ProgressBar from '#/Shared/Elements/ProgressBar.vue'
import Utils from '#/Shared/Utils'
import Forms from '#/Shared/Forms'
export default {
components: {
JetActionMessage,
JetButton,
JetFormSection,
JetInput,
JetInputError,
JetLabel,
JetSecondaryButton,
ProgressBar,
},
props: {
author: {
type: Object,
default: {
id: null,
name: '',
bio: '',
photo: null,
}
},
blank_avatar_image: {
type: String,
default: null,
},
method: {
type: String,
default: 'POST',
},
disabled: {
default: false
}
},
data() {
return {
form: this.$inertia.form({
_method: this.method,
id: this.author.id,
name: this.author.name,
bio: this.author.bio,
photo: this.author.photo,
}),
formDetails: {
routes: {
store: route('authors.store'),
update: this.author.id
? route('authors.update', { author : this.author.id})
: null,
},
errorBag: 'createOrUpdateAuthor',
},
photo_preview: null,
}
},
methods: Forms,
computed: {
photo_or_blank_image() {
return this.author.photo ? this.author.photo : this.blank_avatar_image;
},
author_photo_is_blank() {
return Utils.isBlankAvatarImage(this.author.photo);
}
}
}
</script>
here is my Forms class:
var Forms = {
save() {
var self = this;
// if method is NONE don't submit form
if (this.method === 'NONE') {
return false;
}
if (this.$refs.photo && this.$refs.photo.files[0]) {
this.form.photo = this.$refs.photo.files[0];
}
var request = {
errorBag: this.formDetails.errorBag,
preserveScroll: true,
forceFormData: true,
};
var route = this.formDetails.routes.store;
if (this.method === 'PUT') {
route = this.formDetails.routes.update;
}
this.form.wasSuccessful = false;
this.form.post(route, request);
},
selectNewPhoto() {
this.$refs.photo.click();
},
updatePhotoPreview() {
const photo = this.$refs.photo.files[0];
if (! photo) return;
this.author.photo = photo;
const reader = new FileReader();
reader.onload = (e) => {
this.photo_preview = e.target.result;
};
reader.readAsDataURL(photo);
},
deletePhoto() {
this.author.photo = null;
this.form.photo = null;
this.photo_preview = this.blank_avatar_image;
this.clearPhotoFileInput();
},
clearPhotoFileInput() {
if (this.$refs.photo?.value) {
this.$refs.photo.value = null;
}
}
}
export default Forms;
here is my AuthorsController which handles the requests, I've only copied the edit and update methods as they are the only ones relevant:
<?php
namespace App\Http\Controllers;
use App\Actions\Zavoon\Authors\AuthorActions;
use App\Models\Author;
use Illuminate\Http\Request;
use Laravel\Jetstream\Jetstream;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Inertia\Inertia;
class AuthorsController extends Controller
{
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$author = Author::where('id', $id)
->where('team_id', Auth::user()->currentTeam->id)
->first();
if (!$author) {
abort(404);
}
return Inertia::render('Authors/Edit', ['author' => $author->id])
->with('author', $author);
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id, AuthorActions $action)
{
$author = $action->update($request->all());
$success = 'Author information updated.';
session()->flash('success', $success);
return Redirect::route('authors.edit', ['author' => $author->id]);
}
}
here is my AuthorActions class which handles authors related logic:
<?php
namespace App\Actions\Zavoon\Authors;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use App\Models\Author;
use App\Rules\Rules;
use Illuminate\Validation\Rule;
class AuthorActions
{
/**
* Creates new author
*/
public function create(array $input)
{
if ($this->validate($input, 'create')) {
$user = Auth::user();
$input['user_id'] = $user->id;
$input['team_id'] = $user->currentTeam->id;
$author = new Author();
$author->fill($input);
$author->save();
$author->updatePhoto($input);
return $author;
}
return false;
}
/**
* Updates author
*
* #param array $input
* #return boolean|Author
*/
public function update(array $input)
{
if ($this->validate($input, 'update')) {
$author = Author::find($input['id']);
$author->fill($input);
$author->save();
$author->updatePhoto($input);
return $author;
}
return false;
}
/**
* Validates input
*/
public function validate(array $input, $type)
{
$user = Auth::user();
$rules = [
'name' => ['required', 'string', 'max:255'],
'bio' => ['required', 'string', 'max:4000'],
'photo' => Rules::photo($type),
];
if ($type === 'update') {
$rules['id'] = [
'required',
Rule::exists('authors')->where(function ($query) use ($input, $user) {
return $query
->where('id', $input['id'])
->where('team_id', $user->currentTeam->id);
}),
];
}
Validator::make($input, $rules)->validateWithBag('createOrUpdateAuthor');
return true;
}
}
here is my Rules class which gives me some of the validation rules:
<?php
namespace App\Rules;
use App\Rules\ImageOrLink;
class Rules
{
public static function photo($type = 'create')
{
if ($type === 'create') {
return ['nullable', self::mimes(), self::maxImageSize()];
} else {
return ['nullable', new ImageOrLink()];
}
}
public static function mimes()
{
return 'mimes:jpg,jpeg,png';
}
public static function maxImageSize()
{
return 'max:5120';
}
}
and finally here is my ImageOrLink rule which is used in validating the image uploads:
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Validator;
use App\Rules\Link;
class ImageOrLink implements Rule
{
/**
* Create a new rule instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine if the validation rule passes.
* True if it is an image upload or a valid url.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
if (Link::isLink($value)) {
return true;
} else {
$validator = Validator::make([
'image' => $value
], [
'image' => ['required', Rules::mimes(), Rules::maxImageSize()],
]);
if ($validator->fails()) {
return false;
}
return true;
}
return false;
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'This needs to be an image upload or a link to an image.';
}
}
Any ideas appreciated! I really don't get why it's happening.
EDIT 1: It seems it is something to do with Inertia's Form helper. When the form is submitted once then the form.photo does not get updated with the new value. No idea why though.
The solution was strange, still don't know why exactly it happens. Maybe it is an Inertia bug. So, after the request was submitted successfully just do this:
this.form.photo = this.author.photo;
this goes in its own method in Forms.js and to repeat myself, it is called in the onSuccess callback.
I got this error and I cant seem to find the bug.
This is the function in my controller.
class ConfigSplitCleansingController extends Controller
{
public function storeNewArea(Request $request)
{
$setArea = $request->setNewArea;
$decode = json_decode($setArea, true);
$activity = Activities::where('activityCode', $request->activityId)->first();
$lastrow = PubCleansingScheduleStreet::join('pubcleansingschedule_activity','pubcleansingschedule_street.pubCleansingActivityId', '=', 'pubcleansingschedule_activity.id')
->select('pubcleansingschedule_street.rowOrder')
->where('pubcleansingschedule_activity.pubCleansingScheduleParkId',$request->scheduleparkId)
->where('pubcleansingschedule_activity.activityId',$activity->id)
->orderBy('pubcleansingschedule_street.rowOrder','desc')
->limit(1)->first();
$row = $lastrow->rowOrder;
foreach ($decode as $key => $value) {
$row = $row + 1;
if($value['id'] == 0){
$schedulestreet = PubCleansingScheduleStreet::find($request->schedulestreetId);
$newsplit = new CleansingSplit;
$newsplit->pubCleansingId =$schedulestreet->pubCleansingId;
$newsplit->streetId =$schedulestreet->streetId;
$newsplit->activityCode =$schedulestreet->activityCode;
$newsplit->serviceType =$schedulestreet->serviceType;
$newsplit->value =$value['value'];
$newsplit->frequency =$schedulestreet->frequency;
$newsplit->save();
$newstreet->pubCleansingActivityId =$schedulestreet->pubCleansingActivityId;
$newstreet->pubCleansingId =$schedulestreet->pubCleansingId;
$newstreet->streetId =$schedulestreet->streetId;
$newstreet->streetName =$schedulestreet->streetName;
$newstreet->streetType =$schedulestreet->streetType ;
$newstreet->activityCode =$schedulestreet->activityCode;
$newstreet->serviceType =$schedulestreet->serviceType;
$newstreet->value =$value['value'];
$newstreet->frequency =$schedulestreet->frequency;
$newstreet->frequency_PJ =$schedulestreet->frequency_PJ;
$newstreet->rowOrder =$row;
$newstreet->save();
}
else {
$newstreet = CleansingSplit::find($value['id']);
$newstreet->value = $value['value'];
$newstreet->save();
}
}
return response()->json($newstreet);
}
}
This is my model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class CleansingSplit extends Model
{
//
protected $table = 'publiccleansingsplit';
protected $fillable = [
'id',
'pubCleansingId',
'streetId',
'activityCode',
'serviceType',
'value',
'frequency'
];
}
Route
Route::post('splitpembersihan/storeNewArea', ['as' => 'storeNewArea', 'uses' => 'ConfigSplitCleansingController#storeNewArea']);
And this is the ajax
$.ajax(
{
url: '{{url("splitpembersihan/storeNewArea")}}',
type: 'post',
data: {
"setNewArea": setarray,
"scheduleparkId": scheduleparkId,
"schedulestreetId": schedulestreetId,
"splitId": splitId,
"activityId" : #if(isset($schedulestreet->activityCode))"{{ $schedulestreet->activityCode}}"#endif,
"_token": token
},
success: function (data)
{
alert("success");
window.location.replace('/splitpembersihan/splitBin/'+ PubCleansingID +'/splitValueArea');
},
error: function (data)
{
alert("error");
}
});
The error is the opposite. The data is stored successfully. However, it shows the error alert instead of the success alert. And if I just press the submit button without submitting anything, it shows the success alert.
I want to know how I can call the function ajax_check_login available in my User class, this class exists in user.php.
This is the basic content:
class User extends {
/**
* Class Constructor
*/
public function __construct() {
}
public function ajax_check_login() {
try {
if (!isset($_POST['username']) || !isset($_POST['password'])) {
throw new Exception('Invalid credentials given!');
}
$this->load->model('user_model');
$user_data = $this->user_model->check_login($_POST['username'], $_POST['password']);
if ($user_data) {
$this->session->set_userdata($user_data); // Save data on user's session.
echo json_encode(AJAX_SUCCESS);
} else {
echo json_encode(AJAX_FAILURE);
}
} catch(Exception $exc) {
echo json_encode(array(
'exceptions' => array(exceptionToJavaScript($exc))
));
}
}
}
and this is my ajax request:
var postUrl = GlobalVariables.baseUrl + 'application/controllers/user.php/ajax_check_login';
var postData =
{
'username': $('#username').val(),
'password': $('#password').val()
};
$.post(postUrl, postData, function(response)
{
// Some stuff..
});
How you can see I want call the function ajax_check_login available in the user.php file. But I can't access directly to this function 'cause is located inside the User class, so I should create another file to bounce the request or I can do it in the same file user.php file?
You have a typo:
class User extends {
Extends what?
Add this to user.php (outside of the class):
$allowed_functions = array('ajax_check_login');
$ru = $_SERVER['REQUEST_URI']
$func = preg_replace('/.*\//', '', $ru);
if (isset($func) && in_array($func, $allowed_functions)) {
$user = new User();
$user->$func();
}
Ok, so I'm stuck again. I'm doing an todo-list application, using Laravel and Angular. I can fetch data from the database via the Laravel- and Angular controllers but when I try do write data, I can't get it working.
So I have a form, whing uses ng-submit to post the data. When I - in the Angular controller - log the data to the console, the data from the form is correct. But when I try to pass it on to the Laravel Controller, I get stuck.
I can't find out whats wrong and browing the web for answers hasn't helped me.
Laravel routes:
<?php
Route::get('/', function () {
return view('index');
});
Route::get('/notes', 'NoteController#index');
Route::delete('/notes', 'NoteController#destroy');
Route::post('/notes', 'NoteController#store');
//Route::post('/notes', 'NoteController#update');
Route::get('/projects', 'ProjectController#index');
Route::get('/users', 'UserController#index');
Route::group(['middleware' => ['web']], function () {
//
});
?>
Laravel controllers:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Note;
use App\User;
use App\Project;
use Input;
use Response;
use Redirect;
class NoteController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$notes = Note::where('removed', 0)->get()->toArray();
$response = [];
foreach ($notes as $note) {
$user = User::find($note['user_id']);
$project = Project::find($note['project_id']);
$this_row = array(
'id' => $note['id'],
'user' => $user['uname'],
'project' => $project['pname'],
'content' => $note['content'],
'completed' => $note['completed'],
'removed' => $note['removed'],
'created' => $note['time_created'],
'deadline' => $note['time_deadline']
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
public function store()
{
$note = Input::json()->get()->toArray();
var_dump($note);
/*
$note->user_id = $note['user'];
$note->project_id = $note['project'];
$note->content = $note['content'];
$note->time_deadline = $note['deadline'];
$note->save();*/
}
}
class ProjectController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$projects = Project::orderBy('pname', 'asc')->get()->toArray();
$response = [];
foreach ($projects as $project) {
$this_row = array(
'id' => $project['id'],
'name' => $project['pname'],
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
}
class UserController extends Controller
{
public function index()
{
try {
$statusCode = 200;
$users = User::orderBy('uname', 'asc')->get()->toArray();
$response = [];
foreach ($users as $user) {
$this_row = array(
'id' => $user['id'],
'name' => $user['uname'],
);
$response[] = $this_row;
}
} catch (Exception $e) {
$statusCode = 400;
} finally {
return Response::json($response, $statusCode);
}
}
}
Angular controller:
angular.module('todoApp', []).controller('MainController', function($scope, $http) {
var thisApp = this;
$http({method : 'GET', url : 'http://localhost:8000/notes'})
.then (function(response) {
thisApp.todos = response.data;
}, function() {
alert("Error getting todo notes");
});
$http({method : 'GET',url : 'http://localhost:8000/users'})
.then(function(response) {
thisApp.users = response.data;
}, function() {
alert("Error getting users");
});
$http({method : 'GET', url : 'http://localhost:8000/projects'})
.then(function(response) {
thisApp.projects = response.data;
}, function() {
alert("Error getting projects");
});
thisApp.addTodo = function(note) {
console.log($scope.note);
$http({
method : 'POST',
url : 'http://localhost:8000/notes',
data : $.param($scope.note),
headers : {'Content-Type': 'application/x-www-form-urlencoded'}
});
};
});
HTML:
<!doctype html>
<html ng-app="todoApp">
<head>
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="/js/MainController.js"></script>
</head>
<body ng-controller="MainController as myControl">
<h2>Todo</h2>
<div>
<table>
<tr>
<th>Note:</th>
<th>Author:</th>
<th>Project:</th>
<th>Created:</th>
<th>Deadline:</th>
</tr>
<tr ng-repeat="todo in myControl.todos">
<td> {{ todo.content }} </td>
<td> {{ todo.user }} </td>
<td> {{ todo.project }} </td>
<td> {{ todo.created }} </td>
<td> {{ todo.deadline }} </td>
<td><button>Update</button></td>
<td><button>Delete</button></td>
</tr>
</table>
</div>
<h2>Add new:</h2>
<div>
<form ng-submit="myControl.addTodo()">
User:<br/>
<select ng-model="note.user">
<option ng-repeat="user in myControl.users" value="{{ user.id }}">{{ user.name }}</option>
</select><br/>
Project:<br/>
<select ng-model="note.project">
<option ng-repeat="project in myControl.projects" value="{{ project.id }}">{{ project.name }}</option>
</select><br/>
Note:<br/>
<textarea rows="5" cols="30" ng-model="note.content"></textarea><br/>
Deadline (format YYYY-MM-DD HH:MM):<br/>
<input type="text" ng-model="note.deadline" /><br/>
<input type="submit" value="Add" />
</form>
</div>
</body>
</html>
The result can be seen in this image: http://imgur.com/60hIzSb
I have no idea what I'm doing wrong. I guess my problem is in the Angular controller in the addTodo function, but I really don't know. Any suggestions?
I also wonder if anyone knows if I have to do anything else than change method : 'POST' to method : 'PUT' if I want to use the PUT method for creating new notes?
I feel like it has something to do with this:
$note = Input::json()->get()->toArray();
var_dump($note);
In angular you are sending form encoded data not json. And I believe Laravel automatically decodes received json anyway, so this should work:
$note = Input::all();
var_dump($note);
If it is the CSRF token then inject the CSRF TOKEN to your view
angular.module("todoApp").constant("CSRF_TOKEN", '{!! csrf_token() !!}');
and to your addTodo function in the headers pass the token....
thisApp.addTodo = function(note) {
console.log($scope.note);
$http({
method : 'POST',
url : 'http://localhost:8000/notes',
data : $.param($scope.note),
headers : {'Content-Type': 'application/x-www-form-urlencoded',
'x-csrf-token': CSRF_TOKEN}
});
I've been trying to override the ProfileFormType from the FOSUserBundle. I followed the steps from my previous problem which has been solved since my current task is somehow similar to the previous one. (I use AngularJS for frontend)
Unfortunately, I can't seem to override the buildForm() function from the parent class.
I've logged the form errors and it says:
ERROR: This form should not contain extra fields.
current_password:
ERROR: This value should be the user's current password.
services.yml
services:
acme.profile.form.type:
class: Acme\BulletinBundle\Form\Type\ProfileFormType
arguments: ["%fos_user.model.user.class%"]
tags:
- { name: form.type, alias: acme_user_profile }
config.yml
fos_user:
profile:
form:
type: acme_user_profile
ProfileFormType.php
namespace Acme\BulletinBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ProfileFormType extends AbstractType {
private $class;
public function __construct($class) {
$this->class = $class;
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('username', null, array('label' => 'form.username', 'translation_domain' => 'FOSUserBundle'))
->add('email', 'email', array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'));
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => $this->class,
'intention' => 'profile',
'csrf_protection' => false,
));
}
public function getParent() {
return 'fos_user_profile';
}
public function getName() {
return 'acme_user_profile';
}
}
UserController.php
/**
* #Method("POST")
* #Route("/user/edit", name="user_edit", options={"expose"=true})
*/
public function editAction(Request $request) {
$id = $request->request->get('id');
$user = $this->getDoctrine()
->getManager()
->getRepository("AcmeBulletinBundle:User")
->find($id);
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->get('fos_user.profile.form.factory');
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
$userManager->updateUser($user);
return new JsonResponse(['valid' => true]);
}
$errs = (string) $form->getErrors(true, false);
return new JsonResponse(['valid' => $errs]);
}
edit.html
<form class="form-group text-left" ng-submit="submit()" novalidate name="userFrm">
<div class="form-group">
<label for="user.email" class="required">Email</label>
<input id="user.email" name="user.username" class="form-control" required type="text" ng-model="user.email" />
</div>
<div class="form-group">
<label for="user.username" class="required">Username</label>
<input id="user.username" name="user.username" class="form-control" required type="text" ng-model="user.username" />
</div>
<input type="submit" value="Update" ng-disabled="userFrm.$invalid" class="btn btn-primary center-block col-lg-2" />
</form>
edit.js
angular.module('myApp', [])
.controller('EditUserCtrl', ["$scope", "$http", "$state", "$stateParams", function ($scope, $http, $state, $stateParams) {
//returns {username: data1, email: data2, enabled: data3}
$http.get(Routing.generate('get_user', {id: $stateParams.id}))
.then(function (response) {
var user = response.data.user;
$scope.user = user;
});
$scope.submit = function () {
var formData = {
fos_user_profile_form: $scope.user,
id : $stateParams.id
};
var success = function (response) {
var valid = response.data.valid;
console.log(valid);
};
var error = function (reason) {
alert('error');
};
console.log($scope.user);
$http.post(Routing.generate('user_edit'), $.param(formData), {
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
.then(success, error);
}
}
}]);
The problem is that you extending profile form, but in your form template none of main fields exist. Remove this lines from your form type:
public function getParent() {
return 'fos_user_profile';
}
or add missing field current_password to edit.html.