i am new to laravel
this is my code for controller
I am writing a code to save the data from the user in Mysql
And then redirect me to the list page with updated table and a flash message that the data has been updated successfully
i also tried using session->('key') but it didn't work
<?php
namespace App\Http\Controllers;
use App\restaurent_name;
use Illuminate\Http\Request;
class RestaController extends Controller
{
function Index()
{
return view('home');
}
function list()
{
$data = restaurent_name::all();
return view('list',["Data"=>$data]);
}
function add(Request $req)
{
//return $req->input();
$save = new restaurent_name;
$save->name=$req->input("name");
$save->address=$req->input("address");
$save->contact=$req->input("contact");
$save->save();
$save->session()->has('status');
//$save->session()->put('status', 'Task was successful!');
//$save->session()->flash('status','Restaurent added succesfully');
return redirect('/list');
}
}
the data gets saved properly into the database but the issue is that i am not able to receive message from flash session
This the error message i receive when i try to use flash session
`
Illuminate\Database\Eloquent\Model::throwBadMethodCallException C:\xampp\htdocs\Laravel
Projects\Restaurants\vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php:50
$pattern = '~^Call to undefined method (?P<class>[^:]+)::(?P<method>[^\(]+)\(\)$~';
if (! preg_match($pattern, $e->getMessage(), $matches)) {
throw $e;
}
if ($matches['class'] != get_class($object) ||
$matches['method'] != $method) {
throw $e;
}
static::throwBadMethodCallException($method);
}
}
/**
* Throw a bad method call exception for the given method.
*
* #param string $method
* #return void
*
* #throws \BadMethodCallException
*/
protected static function throwBadMethodCallException($method)
{
throw new BadMethodCallException(sprintf(
'Call to undefined method %s::%s()', static::class, $method
));
}
}
`
You can do that with :
return redirect('/list')
->with('status', 'Restaurent added succesfully')
->with('status2', 'Task was successful!');
With Session Flash :
Session::flash('status', 'Restaurent added succesfully');
Session::flash('status2', 'Task was successful!');
return redirect('/list');
Related
I am working with the Laravel 9 application. I have created a custom Exception. I want to report the General Exception to the sentry and this custom Exception to another vendor like Papertrail.
The Handler.php is not calling the reportable closure function when the application throws a custom exception i.e ServiceException.
By the way, the Laravel documentation for errors is also not understandable
Handler.php
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Inertia\Inertia;
use Throwable;
use Exception;
use App\Exceptions\ServiceException;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* #var array
*/
protected $dontReport = [
// ServiceException::class
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* #var array
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* #return void
*/
public function register()
{
$this->reportable(function (Throwable $e) {
// this block is calling for Exception but not for custom Exception like ServiceException.
if ($this->shouldReport($e) && app()->bound('sentry')) {
app('sentry')->captureException($e);
}
});
$this->reportable(function (ServiceException $e) {
// this block is not calling when I throw ServiceException.
echo "Send this ServiceException to papertrail app."; // this line is never called.
die;
});
}
public function render($request, Throwable $e)
{
$response = parent::render($request, $e);
if ($request->isJson()) {
//prevent error for local and staging.
if (! app()->environment(['local', 'staging']) && in_array($response->status(), [500, 503, 404, 403])) {
\Log::error('API Error Handler', [$response->getOriginalContent()]);
$message = trans('message.error_description_500');
if ($response->status() == 404) {
$message = trans('message.data_not_found');
} elseif ($response->status() == 403) {
$message = trans('message.you_are_not_allowed_perform');
} elseif ($response->status() == 503) {
$message = trans('message.error_description_503');
}
return response()->json([
'message' => $message,
], $response->status());
}
}
return $response;
}
}
ServiceException.php
<?php
namespace App\Exceptions;
use Exception;
class ServiceException extends Exception
{
/**
* Report the exception.
*
* #return void
*/
public function report()
{
//
}
/**
* Render the exception into an HTTP response.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function render($request, $exception)
{
if (! $request->ajax()) {
// view('error_handler', compact('exception'));
}
return response()->json([
'code' => $exception->getCode(),
'status' => 'error',
'message' => $exception->getMessage(),
'data' => 'sample data',
]);
}
}
AnyController.php
public function anyFunction() {
// throw new Exception('Unhandled Exception.'); // It will call the $this->reportable(function (Throwable $e) { block.
// throw new ServiceException('Unhandled ServiceException.'); // It will call the $this->reportable(function (Throwable $e) { block.
try {
$this->service->aFunctionThatThrowException(); // this function will throw ServiceException.
} catch (Exception $e) {
Log::error('controller_fun_error', ['error' => $e->getMessage()]);
report($e);
return $this->failResponse();
}
}
AnyService.php
public function aFunctionThatThrowException() {
try {
throw new ServiceException('Throwing ServiceException...)');
} catch (ServiceException | Exception $e) {
Log::error('service_fun_error', ['error' => $e->getMessage()]);
throw $e;
}
}
I'm not intirely sure, but I don't think the error will be reported if you put a try catch around it yourself.
Create a new helper functions file eg: app/Helpers/Common.php and create a service provider HelperServiceProvider in app/Providers/HelperServiceProvider.php use the code below :
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
require_once __DIR__ . '/../Helpers/Common.php';
}
}
Now copy the below mentioned code to the app/Helpers/Common.php file :
if (! function_exists('throwResponse')) {
function throwResponse($message='Exceptions',$data=[],$statusCode=500){
if(request()->wantsJson()) {
if ((gettype($message) !== 'string') && ($message instanceof \Exception)) {
if($message->getMessage()){
$data = (!empty($message->getTrace())) ? $message->getTrace() : [];
$message = (!empty($message->getMessage())) ? $message->getMessage() : "Something went wrong";
$data = $data?:[$message];
$statusCode = 500;
}else{
throw new \Illuminate\Http\Exceptions\HttpResponseException($message->getResponse());
}
}
$errStatus = (in_array($statusCode,[200,201])) ? false : true;
$response = ['code'=>(int)$statusCode,
'error'=>$errStatus,
'message'=>$message];
if(!empty($data)){
$response['data'] = $data;
}
if($statusCode == 200 && $data == "empty"){
$response['data'] = [];
}
throw new \Illuminate\Http\Exceptions\HttpResponseException(response()->json($response,$statusCode));
} else{
if(is_object($message)){
throw $message;
}else{
return $message;
}
}
}
}
Now you can easily call the throwResponse function from anywhere in the project :
for normal response
throwResponse('Message for the response',['user_id'=>1],200);
{
"code":200,
"error":false,
"message":"Message for the response",
"data":{
"user_id":1
}
}
or
throwResponse('unauthorized',null,401);
{
"code":401,
"error":true,
"message":"unauthroized",
}
or for exceptions simply pass the exception $e
throwResponse($e);
{
"code":500,
"error":true,
"message":"exception message",
"data":{
exception data
}
}
The response will be
for example :
public function exampleFunction(Request $request){
try{
if(empty($request->userId)){
throwResponse('Validation error',null,401);
}
$userData = User::find($request->userId);
if(!empty($userData)){
throwResponse('User data',$userData,401);
}else{
throwResponse('Invalid user id',null,422);
}
}catch(\Exception $e){
throwResponse($e);
}
}
Change responses according to your need
I have a form when the user submits lostFound model. The validation request is as follows:
public function rules()
{
return [
'LFImage' => 'required|image|mimes:jpeg,jpg,png,gif,webp', // TODO: Read about 'Sometimes'.
'handoverStatement' => 'nullable|image|mimes:jpeg,jpg,png,gif,webp',
];
}
So, one attached is required (LFImage) and the other isn't (handoverStatement).
I created a dynamic image upload action:
class UploadImageAction implements UploadImageContract {
public function handle(Request $request, $image, $imageLocation)
{
$storedImage = ($request->hasFile($image))
? $request->file($image)->store($imageLocation)
: NULL;
if(!$storedImage)
{
throw new ImageUploadException('Something went wrong with the image upload.' . $storedImage);
}
return $storedImage;
}
}
Then calling it in the controller store() with try, catch:
// Add new Record.
public function store(LostFoundRequest $request, LostFoundService $lostFoundService, UploadImageContract $uploadImageAction)
{
try {
$LFImage = $uploadImageAction->handle($request, 'LFImage', 'lostFound/lostItems');
$handoverStatement = $uploadImageAction->handle($request, 'handoverStatement', 'lostFound/handoverStatements');
$lostFoundService->storeLostFound($request, $LFImage, $handoverStatement);
return redirect('data-entry/lost-and-found')->with('success', 'Item Added Successfully');
} catch (ImageUploadException $exception) {
// Handle upload image error
return back()->withErrors($exception->getMessage());
} catch (LostFoundException $exception) {
// Handle lostfound created error
return back()->withErrors('lostFound', $exception->getMessage());
} catch (\Throwable $exception) {
throw $exception;
}
}
Every time I submit the form without attaching handoverStatement I get the exception error (The data isn't saved, yet LFImage is uploaded to the dir).
What am I missing here?
Note: the ImageUploadException class doesn't have any methods:
<?php
namespace App\Exceptions;
use Exception;
class ImageUploadException extends Exception {}
I made my code where an administrator can send a message to a group, and soon all users within that group receive notification on the mobile app:
public function create(Request $request)
{
if(!($error = $this->isNotValidate($request))){
//Log::error(print_r("validado", true));
$message = Message::create($request->toArray());
$message->recives()->attach($request->recive_ids);
foreach($message->recives as $group){
foreach($group->users as $user){
$user->notify(new NotificationMessage($message));
}
}
$response = ['message' => $message];
return response($response, 200);
}
return response($error, 422);
}
I used the library: https://github.com/laravel-notification-channels/fcm it is working he send the notification to the mobile through the firebase.
my difficulty is that in the toFcm function I want to retrieve the message to build the notification I'm sending:
public function toFcm($notifiable)
{
return FcmMessage::create()
->setData(['message_id' => $this->invoice->id, 'message_created' => $this->invoice->created_at])
->setNotification(\NotificationChannels\Fcm\Resources\Notification::create()
->setTitle($this->invoice->title)
->setBody($this->invoice->content)
//->setImage('http://example.com/url-to-image-here.png')
)->setAndroid(
AndroidConfig::create()
->setFcmOptions(AndroidFcmOptions::create()->setAnalyticsLabel('analytics'))
->setNotification(AndroidNotification::create()->setColor('#0A0A0A'))
)->setApns(
ApnsConfig::create()
->setFcmOptions(ApnsFcmOptions::create()->setAnalyticsLabel('analytics_ios')));
}
I thought that in the variable $this->invoice or in the $notifiable would come the $message that I am passing as a parameter in the creation, but it does not pass, both are returning the user.
does anyone know how i can make this dynamic notification with my message data?
UPDATE
class NotificationMessage extends Notification
{
/**
* Specifies the user's FCM token
*
* #return string|array
*/
public function routeNotificationForFcm()
{
return $this->fcm_token;
}
public function via($notifiable)
{
return [FcmChannel::class];
}
public function toFcm($notifiable)
{
return FcmMessage::create()
->setData(['message_id' => $notifiable->id, 'message_created' => $notifiable->created_at])
->setNotification(\NotificationChannels\Fcm\Resources\Notification::create()
->setTitle($notifiable->title)
->setBody($notifiable->content)
//->setImage('http://example.com/url-to-image-here.png')
)->setAndroid(
AndroidConfig::create()
->setFcmOptions(AndroidFcmOptions::create()->setAnalyticsLabel('analytics'))
->setNotification(AndroidNotification::create()->setColor('#0A0A0A'))
)->setApns(
ApnsConfig::create()
->setFcmOptions(ApnsFcmOptions::create()->setAnalyticsLabel('analytics_ios')));
}
// optional method when using kreait/laravel-firebase:^3.0, this method can be omitted, defaults to the default project
public function fcmProject($notifiable, $message)
{
// $message is what is returned by `toFcm`
return 'app'; // name of the firebase project to use
}
}
I decided to invert the logic of who was my notify, now instead of the user being the notify, my message became
In my control I'm even simpler:
public function create(Request $request)
{
if(!($error = $this->isNotValidate($request))){
//Log::error(print_r("validado", true));
$message = Message::create($request->toArray());
$message->recives()->attach($request->recive_ids);
$message->notify(new NotificationMessage);
$response = ['message' => $message];
return response($response, 200);
}
return response($error, 422);
}
in my message template I made the following changes:
use Illuminate\Notifications\Notifiable;
...
class Message extends BaseModel
{
use Notifiable;
...
public function routeNotificationForFcm()
{
$tokens = [];
foreach($this->recives as $group){
foreach($group->users as $user){
$tokens = array_merge($tokens, $user->notifications()->pluck('token')->toArray());
}
}
return $tokens;
}
}
with that in my variable $notifiable started to receive the information of the message and then it was easy to pass them as parameter.
I'm confused by the error that is being received while attempting to throw an exception, Undefined variable: validation
This is the first time I've tried to create a custom exception and I must be doing something wrong. Here I'm just trying to validate a row being inserted into the database (which works), the problem I'm having is with the exception.
Controller
public function store()
{
try
{
$this->deals->insertDeal(Input::all());
}
catch(ValidationError $e)
{
return Redirect::route('deals.create')
->withInput()
//this is the unknown variable
->withErrors($validation->errors);
}
return Redirect::route('deals.create')
->with('message', 'Deal Created');
}
Model
public function insertDeal($input)
{
$validation = new Services\Validators\Deal;
if ($validation->passes()) {
$deals = Deals::create($input);
}
$errors = $validation->errors;
throw new ValidationError($validation->errors);
}
Custom Validation Error
class ValidationError extends Exception {}
App::error(function(ValidationError $e){
});
To recap, i'm just not sure why i'm getting the error of undefined variable when I try to trigger the exception. Thanks for the help.
Basically, $validation is not available within the scope of the store() method. You can pass the errors through the exception by rewriting your ValidationError class:
class ValidationError extends Exception
{
protected $errors;
public function __construct($errors)
{
$this->errors = $errors;
}
public function getErrors()
{
return $this->errors;
}
}
and accessing the errors in store():
public function store()
{
try {
$this->deals->insertDeal(Input::all());
} catch(ValidationError $e) {
return Redirect::route('deals.create')
->withInput()
->withErrors($e->getErrors());
}
return Redirect::route('deals.create')
->with('message', 'Deal Created');
}
I am trying to return my validation errors to angular but I can't figure out how to return them in the format array('field under validation' => 'error message'). This exact array is held in errors->messages() but it is a protected property.
here is my code
validator.php
<?php namespace TrainerCompare\Services\Validation;
use Validator as V;
/**
*
*/
abstract class Validator
{
protected $errors;
public function validate($data)
{
$validator = V::make($data, static::$rules);
if ($validator->fails()) {
$this->errors = $validator->messages();
return false;
}
return true;
}
public function errors()
{
return $this->errors;
}
}
controller
<?php
use TrainerCompare\Services\Validation\ProgramValidator;
class ProgramsController extends BaseController
{
protected $program;
protected $validator;
public function __construct(Program $program, ProgramValidator $validator)
{
$this->program = $program;
$this->validator = $validator;
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
$input = Input::all();
$v = $this->validator->validate($input);
if ($v == true) {
//$this->program->create($input);
return Response::json(
array('success' => true)
);
} else {
$errors = $this->validator->errors();
return Response::json(
array('errors' => $errors)
);
}
}
}
this returns the json
{"errors":{}}
if I change the controller to
$errors = $this->calidator->errors()->all();
this is returned
{"errors":["The title field is required.","The focus field is required.","The desc field is required."]}
what I really want returned is
{"errors":[title: "The title field is required.",focus: "The focus field is required.",desc: "The desc field is required."]}
The Validator errors in Laravel return a MessageBag object, which has many useful methods you may want to look over.
It sounds like what you want is the toArray method, and you can use it like so in your controller.
Replace the following code that you have in your controller;
$errors = $this->validator->errors();
return Response::json(
array('errors' => $errors)
);
With;
$errors = $this->validator->errors()->toArray();
return Response::json(
array('errors' => $errors)
);
Or, depending how how you're using it with Angular, you can return the object directly, using the toJson method.
return $this->validator->errors()->toJson();