Route issue: URL doesn't change - laravel

I've created a page to edit a message, I can edit my message and save in my database. After the save, I return View::make("messages.index");
But if I look at the URL, it is: http://localhost:8000/update/42 instead of http://localhost:8000/messages
Did I do something wrong? (I assume I made a mistake in my routes.php, but I can't find it)
Routes:
Route::get('/', array('as' => '/', function()
{
return View::make('index');
}));
Route::get("Messages", function()
{
return View::make("Messages.index");
});
Route::resource('messages', 'MessageController');
Route::post('messages/{messages}', 'MessageController#destroy');
Route::put('update/{messages}', array('as' => 'putMessage', 'uses' => 'MessageController#update'));
Route::get('messages/{messages}/edit', array('as' => 'editMessage', 'uses' => 'MessageController#edit'));
Route::post('messages', array('as' => 'storeMessage', 'uses' => 'MessageController#store'));
MessageController:
<?php
class MessageController extends \BaseController {
public function index()
{
$messages = Message::join('tblMessages_tblTeams', 'tblMessages.PK_message', '=', 'tblMessages_tblTeams.FK_message')
->join('tblTeams', 'tblMessages_tblTeams.FK_team', '=', 'tblTeams.PK_team')
->where('PK_team', 1)
->orderBy('created_at', 'DESC')
->get();
return View::make("messages.index")->withMessages($messages);
}
public function create()
{
//
}
// HARD CODED WILL BE REPLACED WHEN ABLE TO LOG IN
// FK_user => Auth::id()->FK_team
public function store()
{
$date = new DateTime;
// INSERT IN DATABASE
$message = new Message;
$message->FK_user = 1;
$message->priority = Input::get("messagePriority");
$message->title = Input::get('messageTitle');
$message->content = Input::get('messageContent');
$message->visible = true;
$message->showFrom = Input::get('messageShowFrom');
$message->removeFrom = Input::get('messageHideFrom');
$message->created_at = $date;
$message->updated_at = $date;
$message->save();
$message->teams()->attach(array(1,3));
return Redirect::back();
}
public function show($id)
{
$deleteMessage = Message::findOrFail($id);
$deleteMessage->visible = 0;
$deleteMessage->save();
return Redirect::back();
}
public function edit($id)
{
$message = Message::findOrFail($id);
$showFrom = $message->showFrom;
$removeFrom = $message->removeFrom;
$showFrom = str_replace(' 00:00:00', '', $showFrom);
$removeFrom = str_replace(' 00:00:00', '', $removeFrom);
return View::make('messages.index')
->withMessage($message)
->with("showFrom", $showFrom)
->with("removeFrom", $removeFrom);
}
public function update($id)
{
$date = new DateTime;
$editMessage = Message::findOrFail($id);
$editMessage->FK_user = 1;
$editMessage->priority = Input::get("messagePriority");
$editMessage->title = Input::get('messageTitle');
$editMessage->content = Input::get('messageContent');
$editMessage->visible = true;
$editMessage->showFrom = Input::get('messageShowFrom');
$editMessage->removeFrom = Input::get('messageHideFrom');
$editMessage->updated_at = $date;
$editMessage->save();
return View::make("messages.index");
}
public function delete($id)
{
//
}
public function destroy($id)
{
dd('destroy');
}
}

What you are returning here, is the page /app/views/Messages/index.php
return View::make("Messages.index");
If you want to call another route, you should use:
Redirect::route('messages');

That is the way it works because your form has been submitted to update/42.
You can return by redirecting like below to have the URL you want the user to be at.
return Redirect::to('/Messages');
and if you want to carry any values to that view you can use
->withInput();
Also refer this for more information

Related

Laravel Create a request internally Resolved

I need to recreate a resquest so that it behaves like a call via api to go through the validator, but my $request->input('rps.number') always arrives empty, although I can see the data in the debug
I also couldn't get it to go through the laravel validator
I can't use a technique to make an http call, because I need to put this call in a transaction
<?php
$nota = new stdClass();
$rps = new stdClass();
$rps->numero = (int)$xml->Rps->IdentificacaoRps->Numero;
$rps->serie = (string)$xml->Rps->IdentificacaoRps->Serie;
$rps->tipo = (int)$xml->Rps->IdentificacaoRps->Tipo;
$nota->rps = $rps;
$controller = new NotaController(new Nota());
$content = new StoreNotaRequest();
$content->request->add($nota);
$result = $controller->store($content);
StoreNotaRequest
<?php
class StoreNotaRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
$request = $this->request;
return [
'rps.numero' => 'required_with:rps|numeric|between:1,999999999999999',
'rps.serie' => 'required_with:rps|string|min:1|max:5',
'rps.tipo' => 'required_with:rps|integer|in:1,2,3'
];
}
}
NotaController
<?php
class NotaController extends Controller
{
private Nota $nota;
public function __construct(Nota $nota)
{
$this->nota = $nota;
}
public function store(StoreNotaRequest $request): JsonResponse
{
// $validated = $request->validated();
try {
$nota = DB::transaction(function () use ($request) {
$request->input('rps.numero');
});
return response()->json($nota);
} catch (Throwable $e) {
return response()->json($data, 409);
}
}
}
Solution
the solution was a little too verbose, I believe it is possible to solve with less code.
more does what it needs to go through the validation of the data contained in the StoreNotaRequest
and it returns an http response, in addition to being able to put all these isolated calls in a single transaction
DB::beginTransaction();
$errors = [];
foreach ($itens as $item) {
$controller = new NotaController(new Nota());
$request = new StoreNotaRequest();
$request->setMethod('POST');
$request->request->add($nota);
$request
->setContainer(app())
->setRedirector(app(Redirector::class))
->validateResolved();
$response = $controller->store($request);
if ($response->statusText() !== 'OK') {
$errors[$item->id] = 'ERROR';
}
}
if (count($errors) === 0) {
DB::commit();
} else {
DB::rollBack();
}

Display content for user and for admin

I would like that normal users don't see the pictures with a status of 0 (not visible) only the visible ones (status 1) but that admins can see everything.
Is this kind of solution viable or is there something cleaner to do?
The gates/policies are not adapted for that, I don't see any other solution to my knowledge, that's why I come to you
Thanks in advance
public function show($name)
{
if(Auth::user()->isAdmin()) {
$model = cache()->remember('model_show'.$name, Config::get('cache.ttl'), function() use ($name) {
return Model::where('name', $name)->with('pictures')->first();
});
$pictures = $model->pictures()->latest()->paginate(18);
} else {
$model = cache()->remember('model_show'.$name, Config::get('cache.ttl'), function() use ($name) {
return Model::where('name', $name)->with('visible_pictures')->first();
});
$pictures = $model->visible_pictures()->latest()->paginate(18);
}
return view('model.model')->with(['model' => $model, 'pictures' => $pictures]);
}
You can clean it up by using when function in the query itself.
public function show($name)
{
$model = cache()->remember('model_show'.$name, Config::get('cache.ttl'), function() use ($name) {
return Model::where('name', $name)->when( Auth::user()->isAdmin() , function ($q)
{
return $q->with('pictures');
}, function ($q)
{
return $q->with('visible_pictures');
})->first();
});
$pictures = $model->pictures()->latest()->paginate(18);
return view('model.model')->with(['model' => $model, 'pictures' => $pictures]);
}
or we could also use arrow functions
public function show($name)
{
$model = cache()->remember('model_show'.$name, Config::get('cache.ttl'), function() use ($name) {
return Model::where('name', $name)->when( Auth::user()->isAdmin() ,
fn($q) => $q->with('pictures') ,
fn($q) => $q->with('visible_pictures')
)->first();
});
$pictures = $model->pictures()->latest()->paginate(18);
return view('model.model')->with(['model' => $model, 'pictures' => $pictures]);
}

"Trying to get property of 'type' of non-object" error when sending array through Mail Laravel

NotiMail.php
public $notiInfo;
public function __construct($notiInfo)
{
$this->type = $notiInfo->type;
$this->name = $notiInfo->name;
}
public function build()
{
if($this->type=="Document") {
return $this->markdown('emails.statusDoc')->with('name', $this->name);
}
elseif($this->type=="Announcement") {
return $this->markdown('emails.statusTap')->with('name', $this->name);
}
}
AnnouncementController.php
use Illuminate\Support\Facades\Mail;
use App\Mail\NotiMail;
public function store(Request $request)
{
$hawkers = Hawker::select('hawker_id')->get();
$request->validate([
'announce_title' => ['required', 'unique:announcements,title'],
'announce_desc' => ['required'],
]);
$current = new Carbon('now', 'UTC');
$Mtime = $current->addHours(8);
$announce = new Announcement();
$announce->title = $request->input('announce_title');
$announce->desc = $request->input('announce_desc');
$announce->announce_date = $Mtime;
$announce->save();
foreach ($hawkers as $hawk) {
$noti = new Notification();
$noti->hawker_id = $hawk->hawker_id;
$noti->title = $request->input('announce_title');
$noti->desc = $request->input('announce_desc');
$noti->notiDate = $Mtime;
$noti->save();
$hawker = Hawker::find($hawk->hawker_id);
$notiInfo = [
'name' => $hawker->name,
'type' => "Announcement"
];
Mail::to($hawker->email)->send(new NotiMail($notiInfo));
}
return redirect()->route('announcement.index')->with('success', "Announcement made!");
}
The error appears from NotiMail.php. Most of the solutions where because the public variable was not included. However, as you can see i already have. Yet the array from AnnouncementController does not seem to pass the values to NotiMail.php.

want to update array values in vuejs using laravel

i have an array values in update form. i need to update specific values when user change in textareas. it looks like this
In my vuejs data objects looks like this.
data() {
return {
jobs: [],
details: {
basic_id: this.$route.params.id,
work: this.jobs
}
};
},
and my update method i wrote like this.
updateDetails() {
this.loading = true;
this.updateWorkedPlaces(this.details)
.then(() => {
console.log("success");
this.loading = false;
})
.catch(() => {
this.loading = false;
});
}
i pass these values it my vuex action methods.
async updateWorkedPlaces({ commit }, payload) {
let job = await Api().put("works/" + payload.basic_id, payload.work);
commit("UPDATE_WORK", job);
},
i pass these values to my laravel backend update function. it looks like this.
public function update(Request $request, $id)
{
$work = $request->work;
$basic = $request->basic_id;
foreach ($request->work as $i => $id) {
$job = Job::findOrFail($basic);
$job->fill(['position' => $id['position'], 'address' => $id['address']])->save();
}
return response()->json(['message' => 'success']);
}
but when i pass these values to this function it shows me this error.
Invalid argument supplied for foreach()
how can i fix this error. anyone can help me?
i figure out my problem with this function
public function update(Request $request, $id)
{
$collection = $request->all();
for ($i = 0; $i < count($collection); $i++) {
Job::where('id', $collection[$i]['id'])
->update([
'position' => $collection[$i]['position'],
'address' => $collection[$i]['address']
]);
}
return response()->json(['collection' => $collection]);
}

Auth::user() Returns Null in API Controller

I'm using Laravel 7 and my problem is to get null from Auth::user();
auth()->user and Auth::id() return null as well.
BTW, in balde template Auth::user() works.
It returns null when I try to use it in controller.
What I'm trying to do is to create a comment page in backend (Vuejs) and I want to build up a filter logic. In order to do that, I want to add a new property named repliedBy into each comment in controller. If a comment isn't replied by the current user, repliedBy will be notByMe. So I don't event try to return user id to Vuejs. I can't get id even in the controller. BTW, login, registration etc work normal way.
Here is my CommentsController:
public function index()
{
$comments = Comment::join("site_languages", "language_id", "=", "site_languages.id")
->select("content_comments.*", "site_languages.shorthand as lang_shorthand")
->with(["replies", "post", "user"])
->orderBy('id', 'desc')
->get()
->groupBy("commentable_type");
$grouppedComments = [];
foreach ($comments as $type => $typeSet) {
$newType = strtolower(explode("\\", $type)[1]);
$grouppedByLanguage = $typeSet->groupBy("lang_shorthand");
$langSet = [];
foreach ($grouppedByLanguage as $lang => $commentSet) {
$grouppedBycontent = [];
foreach ($commentSet as $comments) {
$content = $newType . "_" . $comments->commentable_id;
if (array_key_exists($content, $grouppedBycontent)) {
array_push($grouppedBycontent[$content], $comments);
} else {
$grouppedBycontent[$content] = [$comments];
}
}
$groupAfterOrganized = [];
foreach ($grouppedBycontent as $content => $comments) {
$order = 1;
$commentAndReplies = [];
foreach ($comments as $comment) {
if ($comment->parent_id === null) {
if (isset($comment->order) === false || $comment->order > $order) {
$comment->order = $order;
}
array_push($commentAndReplies, $comment);
} else {
foreach ($comments as $parentComment) {
if ($parentComment->id === $comment->parent_id) {
$parent = $parentComment;
break;
}
}
foreach ($parent->replies as $replyInParent) {
if ($replyInParent->id === $comment->id) {
$reply = $replyInParent;
break;
}
}
if (isset($comment->order) === false) {
$comment->order = $order;
$order++;
}
if (isset($parent->order) === false || $parent->order > $comment->order) {
$parent->order = $comment->order;
}
$reply->order = $comment->order;
$reply->replies = $comment->replies;
$reply[$newType] = $comment[$newType];
$basePower = 6;
if ($comment->user_id !== null) {
if ($comment->user_id === Auth::id()) {
$reply->replyFrom = "me";
} else if ($comment->user->role->power >= $basePower) {
$reply->replyFrom = "staff";
} else {
$reply->replyFrom = "user";
}
} else {
$reply->replyFrom = "visitor";
}
$iReplied = false;
$staffReplied = false;
foreach ($reply->replies as $replyOfReply) {
if ($replyOfReply->user_id !== null) {
$power = $replyOfReply->user->role->power;
if ($power >= $basePower) {
$staffReplied = true;
}
}
if ($replyOfReply->user_id === Auth::id()) {
$iReplied = true;
}
}
if ($staffReplied === false) {
if ($reply->replyFrom === "user" && $reply->replyFrom === "visitor") {
$reply->replied = "notReplied";
} else {
$reply->replied = "lastWords";
}
} else if ($staffReplied && $iReplied === false) {
$reply->replied = "notByMe";
} else if ($staffReplied) {
$reply->replied = "replied";
}
}
}
$groupAfterOrganized[$content] = $commentAndReplies;
}
$langSet[$lang] = $groupAfterOrganized;
}
$grouppedComments[$newType] = $langSet;
}
return $grouppedComments;
}
api.php
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::apiResources([
'languages' => 'API\LanguagesController',
'users' => 'API\UsersController',
'roles' => 'API\RolesController',
'tags' => 'API\TagsController',
'categories' => 'API\CategoryController',
'pictures' => 'API\PicturesController',
'posts' => 'API\PostsController',
'comments' => 'API\CommentsController'
]);
EDIT
I'm using the code down below in RedirectIfAuthenticated.php and when I try with
dd(Auth::user());
it returns null as well. BTW obviosly, redirect to backend doesn't work.
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
if (Auth::user()->role->power > 5) {
return redirect('backend');
}
return redirect(RouteServiceProvider::HOME);
}
return $next($request);
}
The solution to this problem is fairly simple . because you are using api request laravel default auth can not understand the user so here the passport comes :
https://laravel.com/docs/7.x/passport
as written in documenation you should go 3 steps :
composer require laravel/passport
php artisan migrate
php artisan passport:install
after that you can generate token for logged in users and use that token in api authentication to use for your api which is the only and more reliable way that laravel default auth .
this link can be helpful to you too :
https://laravel.io/forum/laravel-passport-vue-check-user-authentication
this way if you intent to use you api in mobile or any other application you can simply authenticate your user in that :)
hope this helps
EDIT
according To your comment now you must generate token for your vue api to use so this would be like below :
$token = $user->createToken(config('app.name'))->accessToken;
if ($this->isApiType()) {
$token = $user->createToken(config('app.name'))->accessToken;
} else {
Auth::login($user);
$redirect = $this->getRedirectTo($user);
}
this must be added in the end of your login method so if the request comes from api it generates a JWT token for you which can be used in vue for login
yes for getting the authencated user detail your API must under the auth:API middleware.
Route::group(['middleware' => 'auth:api'], function () {
}
As you are using Resource those are not under the Api middleware just put that into that and Auth::user will return the result set.
Route::group(['middleware' => 'auth:api'], function () {
Route::apiResources([
'comments' => 'API\CommentsController'
]);
}
will fix the issue.

Resources