display message for database insert operation - laravel

Is there any mechanism that we can know that the data sent from app is successfully inserted to database, as in stored procedure, we use output parameter.
How can we be sure that the data is inserted into database and in case if the data insertion operation is failed, how to catch the error cause and display in a user friendly way?
// controller code
public function store(Request $request)
{
$validatedInput = $request -> validate([
'NBookName' => 'required|string|min:3|max:100',
'NBookId' => 'required|string|min:2|max:10|unique:books,BookID', // unique:table_name,column_name
'NBookUnitPrice' => 'required|max:5|'
]);
$book = new Book;
$book -> BookName = $request->input('NBookName');
$book -> BookID = $request->input('NBookId');
$book -> BookUnitPrice = $request->input('NBookUnitPrice');
$book->save();
return view('pages.about');
}

The Eloquent method save returns either true or false, thus checking the return of the save will let you know if the operation was successful.
You can alternatively use the method saveOrFail which will also return true / false, but may also give a Throwable
From the documentation: https://laravel.com/api/5.3/Illuminate/Database/Eloquent/Model.html#method_save
Examples:
if( $book->save() ){
return response()->json($book, 200);
} else {
return response()->json(['error' => 'Could not save'], 400);
}
or
try {
$book->saveOrFail();
return response()->json($book, 200);
} catch( \Exception $e ){
return response()->json(['error' => $e->getMessage()], 400);
}

save() will return a boolean, saved or not saved. So you can either do Like:
$saved = $book->save();
if(!$saved)
{
App::abort(500, 'Error');//Or return any message to view
}
For more details:check-if-laravel-model-got-saved-or-query-got-executed

I'd start off by separating the layer, I don't like watching validations, Eloquent queries and view related output in the same place.
Before reading the answer below, take a look at
https://laravel.com/docs/5.6/validation#form-request-validation
I'd make middleware to authenticate and authorize users, then use formrequests to validate the input data, and by the time it reaches the controller, the user is authenticated, authorized, data validated and all it's needed is call someone that is responsible for the insert operation and return something to the UI.
"How can we be sure that the data is inserted into database and in
case if the data insertion operation is failed"
Generally, a try catch will do:
public function store(Request $request)
{
try {
$validatedInput = $request -> validate([
'NBookName' => 'required|string|min:3|max:100',
'NBookId' => 'required|string|min:2|max:10|unique:books,BookID', // unique:table_name,column_name
'NBookUnitPrice' => 'required|max:5|'
]);
$book = new Book;
$book -> BookName = $request->input('NBookName');
$book -> BookID = $request->input('NBookId');
$book -> BookUnitPrice = $request->input('NBookUnitPrice');
$book->save();
} catch (\Exception $e) { 
// return your pretty response
// If the operation saving to the database fails, you'll get the information here on whatever it is about,
// as the generic exception catchs it. It should catch the stored procedure output aswell
}
return view('pages.about');
}
If you plan on having a series of insertions and updates/deletes and you don't want them to break logic (insert some and stop at inserting when 1 is wrong), you can use DB; and use DB::beginTransaction(), DB::commit() and DB::rollback() on your code
https://laravel.com/docs/5.6/database

Related

Laravel: How can I return more data from a custom UserProvider?

I have successfully created a custom user provider and have implemented a user interface.
I am trying to save the user object to my local Postgres database that is returned from a third party backend.
Here is what my retrieveByCredentials method looks like:
// MyCustomUserProvider.php
public function retrieveByCredentials(array $credentials) {
if (empty($credentials)) {
return null;
}
try {
$response = Http::asForm()
->retry(3, 100)
->timeout(5)
->post('https://my-custom-auth-endpoint', $credentials)
->json();
if ($response) {
$user = User::firstOrNew([
'foo' => $response['foo'],
]);
$user->save();
return $user;
}
} catch (RequestException $e) {
Log::info('-----------------------------------------------------------');
Log::info(print_r($e->getMessage(), true));
Log::info('-----------------------------------------------------------');
return $e->getMessage();
}
}
...
public function validateCredentials(Authenticatable $user, array $credentials): bool {
return strtoupper($user->foo) === strtoupper($credentials['foo']);
}
So far, everything is working great. I am getting the correct values/booleans for each required method. However, I need to be able to return additional info to my controller than just a boolean value. For example, if a user's password has expired, this information is coming from my 3rd party database. So far, it looks like returning the user results in a true or false response in my LoginController. If I get false back from my CustomProvider I can set a flash message of, "Invalid Credentials". But that may not always be the appropriate error.
Here is how I am calling the CustomUserProvider:
// LoginController.php
$authenticated = Auth::guard('foo')
->attempt([
'userid' => $request->username,
'password' => $request->password,
]);
// $authenticated is the response from CustomUserProvider.
dd($authenticated) // true or false.
It is understood that in my provider I just want to authenticate the user. How can I return the authenticated user back to the controller? Additionally, how can I return the error back to the controller so I can display a proper error message?
The function Auth::guard('foo')->attempt([]) will also return a boolean to tell user if the authentication is successful or not. If you want to get the auth user, just return Auth::user() after the calling that function, like return response()->json(Auth::user())

Laravel transaction saves data into DB even when it's rollbacked

I send a request, trying to save multiple documents at once.
Here is my code
DB::beginTransaction();
try {
foreach ($request->documents as $index => $documentInfo) {
// Check
if (// some statement) {
$documentExists = Document::where([
// some checks
])
->exists();
if ($documentExists) {
throw new \Exception("Error Processing Request", 1);
}
}
// Assign document properties
$document->save();
}
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
if ($request->ajax()) {
return response()->json([
'success' => false,
'document' => $index,
'message' => '// message',
]);
}
return redirect()->back()->with('error', '// message');
}
The thing that happens is that I check every document for its own unique values. If two documents with same values try to get saved I want to return an error.
I tried uploading two documents with the same values, the error is returned on the second document and the transaction must fail, but the first document gets saved into the database.
I don't want this, if there is an error I don't want any documents saved into the DB.

Laravel save new record returns nothing

I'm trying to save new record, all i get is a white page
even dump and dd for $applicant ->save() returns nothing.
public function store(Request $request) {
try {
if (Auth::guest()) {
return redirect()->route('login');
}
$applicant = new Applicant();
$applicant->first_name = $request->get('first_name');
$applicant->middle_name = $request->get('middle_name');
$applicant->last_name = $request->get('last_name');
dump($applicant);
$applicant->save();
dd('Saved');
} catch (Exception $e) {
Log::error("Error during orders creation:" .$e>getTraceAsString());
}
}
I expected the record should be saved
Try this instead
public function store(Request $request){
$applicant = new Applicant;
$applicant->first_name = $request->input('first_name');
$applicant->save();
}
and don't forget to include use App\Applicant model in your Controller class; If it does not solve your problem. please double check your form action post in view section.
I think save function will not return anything.
for data you must use create method.
Used return after save.
$applicant->save();
return response()->json(['success' => 'Data Added successfully.']);
Use create in stead, write less code if you can us always better.
Try this:
Application::create($request->all());
Or change it the way you need by assigning every array key to its value

How to avoid error when using Eloquent's toArray when getting null result

l am getting start at a new laravel project with 5.7, but one problem, when l use first() to fetch data, and if data is not exist, it will return null, and then execute toArray() will throw a PHP error. So l use follow code to reslove it.
$user_model = \App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
$user_data = $user_model->first();
$user_data = $user_data ?? $user_data->toArray();
So is there any better way?
Any one of the following will work, each providing their own way of dealing with a null result:
1. optional helper:
The optional function accepts any argument and allows you to access
properties or call methods on that object. If the given object is null,
properties and methods will return null instead of causing an error.
$user_data = optional($user_model->first())->toArray();
2. firstOr():
Execute the query and get the first result or call a callback.
$data = User::where('id', $id)->when(!is_null($select), function ($query) use ($select) {
return $query->select(explode(',', $select));
})->firstOr(function () {
return ['message' => 'No results'];
});
3. rescue helper:
The rescue function executes the given Closure and catches any exceptions that occur during its execution. All exceptions that are caught will be sent to your exception handler's report method; however, the request will continue processing.
$data = rescue(function () use ($select) {
\App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
return $user_model->first()->toArray();
});
4. try catch:
try {
$user_model = \App\Model\User::where('id', $id);
if ($select) {
$user_model->select(explode(',', $select));
}
$user_data = $user_model->first();
$user_data = $user_data ?? $user_data->toArray();
} catch(\Exception $e) {
// handle the exception...
}
Laravel provides a firstOrFail method which throws an 404 Exception by default.
$user_data = $user_model->firstOrFail(); // If not found an exception is thrown and will be handled by default ExceptionHandler which displays a 404 error page.
// if found, cast the User to array
$user_data = $user_data->toArray();

yii2 how to keep form data in case of model->save fails

I loose my form data, if model->save function fails. My form is based on two different models, because they are related to each other. The controller function is actionCreate.
public function actionCreate()
{
$model = new Model1();
if ($model->load(Yii::$app->request->post())) {
//try to save Model1 in the first step
$transaction = Yii::$app->db->beginTransaction();
try {
$model->save();
$new_model1_id = $model->id; //id of new inserted company
// write in model2 second step
$model2 = new Model2();
$model2->example1 = $example1;
$model2->example2 = $example2;
if ($model2->save()) {
$transaction->commit();
return $this->redirect(['index']);
} else {
$transaction->rollBack();
Yii::$app->session->setFlash('error', 'Error!');
//return $this->redirect(Yii::$app->request->referrer ?: Yii::$app->homeUrl);// return to last page
return $this->goBack((!empty(Yii::$app->request->referrer) ? Yii::$app->request->referrer : null));
};
} catch (Exception $e) {
$transaction->rollBack();
Yii::$app->session->setFlash('error', 'Error!');
//return $this->redirect(Yii::$app->request->referrer ?: Yii::$app->homeUrl);// return to last page
return $this->goBack((!empty(Yii::$app->request->referrer) ? Yii::$app->request->referrer : null));
}
}
return $this->render('create', [
'model' => $model,
]);
}
I'am trying to go back to the last page, when model saving has error.:
return $this->goBack((!empty(Yii::$app->request->referrer) ? Yii::$app->request->referrer : null));
But this is not working. How can I stay on the page respectively coming back to the page without loosing all the existing form entries?
According to the recommendation of Yupic,..Just render the page again, don't use goBack() or any redirect. Allow your code to get to line with return $this->render(...

Resources