In my Laravel-8 and Maatwebsite-3.1 package, I have this code:
use App\Models\User;
use App\Models\Country;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\SkipsErrors;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\SkipsFailures;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Validators\Failure;
use Throwable;
class CountryImport implements
ToModel,
WithValidation,
WithHeadingRow,
SkipsOnError,
SkipsOnFailure,
WithBatchInserts
{
private $rows = 0; // variable to count rows
use Importable, SkipsErrors, SkipsFailures;
public function model(array $row)
{
return new Country([
'name' => $row[0],
'nationality' => $row[1],
'created_at' => date("Y-m-d H:i:s"),
'created_by' => Auth::user()->id,
]);
}
public function headingRow(): int
{
return 1;
}
public function getRowCount(): int
{
return $this->rows;
}
public function customValidationAttributes()
{
return [
'0' => 'Country',
'1' => 'Nationality',
];
}
public function rules(): array
{
return [
'*.0' => [
'required',
'string',
'max:100',
Rule::unique('countries', 'name')
],
'*.1' => [
'nullable',
'string',
'max:50',
Rule::unique('countries', 'nationality')
],
];
}
public function batchSize(): int
{
return 1000;
}
public function chunkSize(): int
{
return 1000;
}
public function onFailure(Failure ...$failures)
{
// Handle the failures how you'd like.
}
}
Controller:
public function importCountry(Request $request)
{
DB::beginTransaction();
$user = Auth::user()->id;
$userEmail = Auth::user()->email;
try {
$validator = Validator::make($request->all(), [
'document' => 'file|mimes:xlsx|max:10000',
]);
if($validator->fails()) {
return $this->error($validator->errors(), 401);
} else {
$check = User::where('id', $user)->pluck('id');
if($check[0] !== null || $check[0] !== undefined) {
$file = $request->file('document');
$file->move(public_path('storage/file_imports/location_imports'), $file->getClientOriginalName());
Excel::import(new CountryImport, public_path('storage/file_imports/location_imports/' . $file->getClientOriginalName() ));
DB::commit();
return $this->success('Nationalities Successfully Imported.', [
'file' => $file
]);
} else {
return $this->error('Not allowed', 401);
}
}
} catch(\Exception $e) {
DB::rollback();
Log::error($e);
return $this->error($e->getMessage(), $e->getCode());
}
}
I am using Laravel as the API endpoint and Angular as the frontend.
It displays successful, and the Excel file found in storage/file_imports/location_imports as instructed.
But nothing was stored in the database without any error.
How do I resolve this?
Thanks
Your controller code is not correct. You are doing wrong stuff about the DB Transaction... See that, if you have any validation error, you are never reverting back or doing anything with the transaction itself...
Try this code:
public function importCountry(Request $request)
{
$request->validate([
'document' => 'file|mimes:xlsx|max:10000',
]);
try {
DB::beginTransaction();
$file = $request->file('document');
$file->move(
public_path('storage/file_imports/location_imports'),
$file->getClientOriginalName()
);
Excel::import(
new CountryImport,
public_path('storage/file_imports/location_imports/' . $file->getClientOriginalName())
);
DB::commit();
} catch(\Throwable $e) {
DB::rollback();
Log::error($e);
return $this->error($e->getMessage(), $e->getCode());
}
return $this->success('Nationalities Successfully Imported.', compact('file'));
}
Please, see how I removed a lot of code:
I have updated your validation, I know you were returning 401, but that is not correct, as you are having a validation error (422 error). If you still need 401 (that is unauthorized) you have to add your code again.
I have updated your if check, as it makes no sense to get the user and check if it is not null or undefined (undefined does not even exist in PHP, that should be a PHP error). It makes no sense, because you are using Auth::user()->id or Auth::id() (both are the same), and you will always get a user back, so why go to the database and get it again ? You already have it...
If you want to check if the user is logged in or similar, you have to add a middleware to the route... If you are in this part of the controller, it means that the previous layer "authorized" the entry to it, so it is the route's middleware responsibility to allow or not, not the controller in this case.
And if you want to still do that in the controller, simply do ->first() instead of ->pluck('id') and check if the variable is null or not.
I updated your catch exception, try to stick to Throwable as it is more correct. You can google more about it.
Related
I am facing an issue when trying to login and register a user using Twitter. Google is working except for Twitter. I cant seem to figure it out.
Temporary identifier passed back by server does not match that of stored temporary credentials. Potential man-in-the-middle.
<?php
namespace App\Http\Controllers;
use Exception;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class TwitterController extends Controller
{
protected $redirectTo = '/home';
public function redirectToProvider($provider)
{
return Socialite::driver($provider)->redirect();
}
public function handleProviderCallback($provider)
{
$user = Socialite::driver($provider)->user();
$authUser = $this->findOrCreateUser($user, $provider);
Auth::login($authUser, true);
return redirect($this->redirectTo);
}
public function findOrCreateUser($user, $provider)
{
$authUser = User::where('provider_id', $user->id)->first();
if ($authUser) {
return $authUser;
}
return User::create([
'name' => $user->getName(),
'username' => $user->getName(),
'email' => $user->getEmail(),
'provider' => $provider,
'provider_id' => $user->getId()
]);
}
}
I am kinda new to both Laravel and Vue and I am working on a school project. I have been following a guide and trying to develop the product but I have the following problem: in the guide was only possible to do an order with a single product. Using LocalStorage a created a Cart component where you can add several products instead. How do I use axios.post to correctly post the order in the database now?
app/Http/Controllers/OrderController.php:
<?php
namespace App\Http\Controllers;
use App\Models\Order;
use Auth;
use Illuminate\Http\Request;
class OrderController extends Controller
{
public function index()
{
return response()->json(Order::with(['product'])->get(),200);
}
public function store(Request $request)
{
$order = Order::create([
'product_id' => $request->product_id,
'user_id' => Auth::id(),
'quantity' => $request->quantity,
'address' => $request->address
]);
return response()->json([
'status' => (bool) $order,
'data' => $order,
'message' => $order ? 'Order Created!' : 'Error Creating Order'
]);
}
public function show(Order $order)
{
return response()->json($order,200);
}
Resources/JS/views/Checkout.vue (between < script > tag):
placeOrder(e) {
e.preventDefault()
let address = this.address
let product_id = this.product.id
let quantity = this.quantity
axios.post('api/orders/', {address, quantity, product_id})
.then(response => this.$router.push('/confirmation'))
},
App/Http/Models/Order.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Order extends Model
{
use SoftDeletes;
protected $fillable = [
'product_id', 'user_id', 'quantity', 'address'
];
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
public function product()
{
return $this->belongsTo(Product::class, 'product_id');
}
}
Actually, You can achieve your goal by changing many lines of code instead of using your current code at backend (laravel Model-Controller) and frontend (Vue). I will show you how to do by adding hasMany relationship in your User model structure, then changing saving method at controller, and axios request payload. This method has limitation, you have to post an array of products of the same user ID.
Add hasMany relationship in your User Model. Read this
class User extends Model
{
//add this line
public function order()
{
return $this->hasMany(Order::class);
}
Use createMany function to save multiple rows in your controller. Read this
public function store(Request $request)
{
//use this lines to store array of orders
$user = Auth::user();
$orderStored = $user->order()->createMany($request->data);
//return your response after this line
}
Change your axios payload from vue method
data(){
return {
//add new key data to store array of order
arrayOfOrders:[];
};
},
methods:{
placeOrder(e) {
e.preventDefault()
let address = this.address
let product_id = this.product.id
let quantity = this.quantity
//remark these lines, change with storing to arrayOfOrders data instead of doing post request
//axios.post('api/orders/', {address, quantity, product_id})
//.then(response => this.$router.push('/confirmation'))
this.arrayOfOrders.push({
product_id:product_id,
quantity:quantity,
address:address
});
},
//create new function to make post request and call it from your button
postData(){
let instance = this;
axios.post('api/orders/', {
data:instance.arrayOfOrders
}).then(response => this.$router.push('/confirmation'))
}
}
Thank you for your answer! Just one thing is not so clear.. in my OrderController.php should the final code look something like this?
public function store(Request $request)
{
$user = Auth::user();
$order = $user->order()->createMany([
'product_id' => $request->product_id,
'user_id' => Auth::id(),
'quantity' => $request->quantity,
'address' => $request->address
]);
return response()->json([
'status' => (bool) $order,``
'data' => $order,
'message' => $order ? 'Order Created!' : 'Error Creating Order'
]);
}
We are trying to setup the Facebook social connect on our Laravel application, but it seems like we have an issue on session creation.
Here is the code for the Controller :
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Laravel\Socialite\Facades\Socialite;
use App\Services\SocialAuthService;
class SocialAuthController extends Controller
{
public function redirect()
{
return Socialite::driver('facebook')->redirect();
}
public function callback(SocialAuthService $service)
{
$user = $service->createOrGetUser(Socialite::driver('facebook')->stateless()->user());
auth()->login($user);
return redirect()->intended('/');
}
}
And the code for the service :
<?php
namespace App\Services;
use Laravel\Socialite\Contracts\User as ProviderUser;
use Myproject\Users\User;
use Myproject\Users\SocialLogin;
class SocialAuthService
{
public function createOrGetUser(ProviderUser $providerUser)
{
$account = SocialLogin::where('provider', '=', 'facebook')
->where('provider_user_id', '=', $providerUser->getId())
->first();
if ($account) {
return $account->user;
}
$user = User::where('email', '=', $providerUser->email)->first();
if (!$user) {
$fullname = explode(' ', $providerUser->getName());
$user = User::create([
'email' => $providerUser->getEmail(),
'firstname' => $fullname[0],
'lastname' => $fullname[1],
'password' => md5(rand(1, 9999)),
]);
}
$account = new SocialLogin([
'provider_user_id' => $providerUser->getId(),
'provider' => 'facebook'
]);
$account->user()->associate($user);
$account->save();
return $user;
}
}
And finally the Model :
<?php
namespace Myproject\Users;
use Illuminate\Database\Eloquent\Model;
use Myproject\Users\User;
class SocialLogin extends Model
{
protected $table = 'social_logins';
protected $fillable = ['user_id', 'provider_user_id', 'provider'];
public function user()
{
return $this->belongsTo(User::class);
}
}
When we're trying to connect via Facebook, the information is correctly insert in Database, and the callback URL set on Facebook Developers correspond to what we have in our .env, so the redirection is correctly done but at the end we don't have any session created for the user.
I think the issue comes from cross-domain, here are the interesting parts of our .env file :
APP_URL=https://www.website.com
APP_DOMAIN=website.com
SESSION_DOMAIN=.website.com
CACHE_DRIVER=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
FACEBOOK_REDIRECT=https://www.website.com/callback/facebook
GOOGLE_REDIRECT=https://www.website.com/auth/google/callback
And our routing on web.php :
Route::domain('{subdomain}.{domain}')->middleware('locale')->group(function () {
Route::get('/callback/facebook', 'Auth\SocialAuthController#callback');
Route::get('/redirect/facebook', 'Auth\SocialAuthController#redirect');
});
I really think the issue is located on routing or SESSION_DOMAIN, but we tried to :
delete the session domain
routing outside the middleware locale, in a middleware auth
It still doesn't affect the login.
I want to know what is wrong in my code given below, I am make my code clean and problem arises since function is not called in another function.example my retrieve function is not called in form method...similary my saveintodatabase function in not called in form method?
there is my code
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Register;
class Admincontroller extends Controller
{
public function form(Request $request)
{
return $this->retrieve($request);
$register= new Register;
return $this->saveintodatabase($name,$phone,$email,$course,$address);
if($register->save())
{
return redirect()->route('displaydata');
}
else
{
echo "fail to insert";
}
}
public function display()
{
$records = Register::all();
return view('displaydata',['records' => $records]);
}
public function delete($id)
{
$records = Register::destroy($id);
$records = Register::all();
if(count($records) > 0)
{
return redirect()->route('displaydata');
}
else
{
echo "No record found";
}
}
public function update($id)
{
$records = Register::find($id);
return view('updatedata',['records' => $records]);
}
public function afterupdate(Request $request)
{
return $this->retrieve($request);
$id=$request->id;
$register = Register::find($id);
if($register->save())
{
//$this->display();
return redirect()->route('displaydata');
}
else
{
echo "fail to insert";
}
}
public function __construct(Request $request)
{
$this->validate($request,[
'name' =>'required',
'phone' => 'required',
'email' => 'required',
'course' => 'required',
'address' => 'required',
]);
}
private function saveintodatabase($name,$phone,$email,$course,$address)
{
$register->name=$name;
$register->phone=$phone;
$register->email=$email;
$register->course=$course;
$register->address=$address;
}
private function retrieve(Request $request )
{
$name=$request->name;
$phone=$request->phone;
$email=$request->email;
$course=$request->course;
$address=$request->address;
}
}
From your code if form function is called then retrieve function should be called However:
your retrieve function does not return anything or change any value for form function. How can you know if it is called. Set XDebugger could be good for you to check. Or simple put die in retrieve function to see if you are there or not.
Chances are your validatoin is failed in your constructor for this you also need to check by either debugger or die method
Laravel 5 has middleware, check if you are using it to cause you never reach to form function
Undefined property: Illuminate\Validation\Validator::$errors in laravel
here is my controller file how to solve it i think here problem is any namespace where is it i do not know please guide me
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Route;
use Input;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Http\Request;
use App\models\Designation;
use Validator;
use Illuminate\Support\Facades\Response;
class Cdesigination extends Controller
{
public $flight;
public function __construct(){
$this->flight = new Designation;
}
public function index()
{
return view('designation');
}
public function techer(Request $request) {
$Validator =Validator::make(array(
'name'=>Input::get('name'),
'detail'=>Input::get('detail')
),array(
'name' => 'required',
'detail' => 'required'
));
if ($Validator->fails()) {
return Response::json([
'success'=>false,
'error' =>$Validator->errors->toArray()
]);
}
else{
$this->flight->name = $request->name;
$this->flight->detail = $request->detail;
$this->flight->save();
return Response::json([
'success'=>true]);
}
}
$Validator->errors()->toArray()
Errors() is function, so the braces are important