I'm using symfony 3.2 and I'd like to login with ajax form. Everything works fine except messages are not translated.
this is the AjaxAuthenticationFailureHandler class
class AjaxAuthenticationFailureHandler extends DefaultAuthenticationFailureHandler
{
/**
* #var mixed
*/
private $translator;
/**
* #param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel
* #param \Symfony\Component\Security\Http\HttpUtils $httpUtils
* #param array $options
* #param \Psr\Log\LoggerInterface $logger
* #param mixed $translator
*/
public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null, $translator = null)
{
parent::__construct($httpKernel, $httpUtils, $options, $logger);
$this->translator = $translator;
}
/**
* {#inheritDoc}
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
if ($request->isXmlHttpRequest()) {
return new Response(json_encode(array(
'has_error' => true,
'message' => $this->translator->trans($exception->getMessage())
)));
}
return parent::onAuthenticationFailure($request, $exception);
}
Solution for symfony 4:
For symfony 4 we can do like this:
'message' => $this->translator->trans($exception->getMessageKey(), array(), 'security'),
Try changing your translation line to this:
$this->translator->trans($exception->getMessage(), array(), 'messages')
then create translation file in your Resources/translations folder for each language i.e. messages.en.yml, messages.fr.yml, etc...
your $exception->getMessage() should try and return translation keys to simplify things so for example it should return "error.name.missing" and then in the yml translation file you'd have:
error.name.missing: 'The name cannot be missing'
Related
I am refactoring my application according to this article:
https://laravel-news.com/controller-refactor
I had all logic in my controllers so it seems like a good idea to do this. But now I have some struggles with the update function.
class CategoryController extends Controller
{
/**
* Display a listing of the resource.
*
* #param Request $request
* #return JsonResponse
*/
public function index(Request $request): JsonResponse
{
$categories = Category::where('created_by', $request->company->id)->orderBy('order')->get();
return response()->json($categories);
}
/**
* Store a newly created category
*
* #param StoreCategoryRequest $request
* #param CategoryService $categoryService
* #return JsonResponse
*/
public function create(StoreCategoryRequest $request, CategoryService $categoryService): JsonResponse
{
$category = $categoryService->createCategory($request);
if ($category) {
return response()->json(['success' => true, 'message' => 'api.category.save.success']);
}
return response()->json(['success' => false, 'message' => 'api.category.save.failed']);
}
/**
* Update the specified resource in storage.
*
* #param StoreCategoryRequest $request
* #param Category $category
* #param CategoryService $categoryService
* #return JsonResponse
*/
public function update(StoreCategoryRequest $request, Category $category, CategoryService $categoryService): JsonResponse
{
try {
$result = $categoryService->updateCategory($request, $category);
if ($result) {
return response()->json(['success' => true, 'message' => 'api.category.update.success']);
}
return response()->json(['success' => false, 'message' => 'api.category.update.failed']);
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'api.category.update.failed']);
}
}
}
And the route:
Route::put('category/{category}', [CategoryController::class, 'update']);
Laravel is getting the category based on the id, but I don't know how to handle this correctly in my controller. I autoload the CategoryService there, so that I can use the update function. After that I give the actual category as a property to that service, I also don't know if handling the exceptions like this is the 'best way'.
class CategoryService
{
public function createCategory(Request $request): bool {
$category = new Category();
$category->fill($request->all());
$category->created_by = $request->company->id;
return $category->save();
}
/**
* #throws \Exception
*/
public function updateCategory(Request $request, Category $category): bool {
if($this->isOwnerOfCategory($category, $request->company)) {
$category->fill($request->all());
$category->created_by = $request->company->id;
return $category->save();
}
throw new \Exception('Not the owner of the category');
}
private function isOwnerOfCategory(Category $category, Company $company): bool
{
return $category->created_by === $company->id;
}
}
The create function/ flow feels good. But the update function feels like properties are coming from everywhere and the code is a lot less readable. Are there any suggestions to improve this?
EDIT:
in novas ActionEvent.php class i edited the two rows fields and exceptions for the forResourceUpdate function:
Whats actually strange now my resource is updated but there is nothing in the ACTION EVENT table.
public static function forResourceUpdate($user, $model)
{
return new static([
'batch_id' => (string) Str::orderedUuid(),
'user_id' => $user->getKey(),
'name' => 'Update',
'actionable_type' => $model->getMorphClass(),
'actionable_id' => $model->getKey(),
'target_type' => get_class($model),
'target_id' => $model->getKey(),
'model_type' => get_class($model),
'model_id' => $model->getKey(),
'fields' => 'test',
'status' => 'finished',
'exception' => 'test',
]);
}
so i just installed Nova set up some Resources, it shows everything fine, but when i try to update any of them, i get a Database error that i cant insert NULL into ACTION_EVENT.FIELDS.
https://nova.laravel.com/docs/1.0/actions/defining-actions.html#action-fields
The Doc says i can define some fields in the Actions fields function , but i didnt generate any Action class not i want to. I think its some sort of default action logging?
Can i turn it off, or do i have to add some Fields somewhere?
<?php
namespace App\Nova;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Http\Requests\NovaRequest;
class Chain extends Resource
{
public static $category = "Stammdaten";
/**
* The model the resource corresponds to.
*
* #var string
*/
public static $model = 'App\Model\System\Partner\Chain';
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'id';
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id',
];
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
}
And The Model:
class Chain extends Model
{
use SoftDeletes;
use ObservantTrait;
use TranslationTrait;
protected $primaryKey = 'partner_chain_id';
protected $table = 'tbl_prm_partner_chain';
public $sequence = 'seq_partner_chain_id';
const CREATED_BY = 'insert_user';
const CREATED_AT = 'insert_timestamp';
const UPDATED_BY = 'update_user';
const UPDATED_AT = 'update_timestamp';
const DELETED_BY = 'delete_user';
const DELETED_AT = 'delete_timestamp';
protected $fillable = ['name_text', 'partner_type_id'];
protected $dates = ['delete_timestamp', 'insert_timestamp'];
thats all its quit simple, thats why i have no Clue right now where i am going wrong.
I'm experimenting with laravel and I came across this article.
I followed it exactly but for some reason when sending the mail in the Notification class, he can't find the $user variable I declared in the constructor. When printing it in the constructor it works so the user object is passed correctly, but when I want to access it in the toMail method, it's inexisting for some reason. Anyone know why & how to fix this?
<?php
namespace App\Notifications;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class UserRegisteredSuccessfully extends Notification
{
use Queueable;
/**
* #var User
*/
protected $user;
/**
* Create a new notification instance.
*
* #param User $user
*/
public function __construct(User $user)
{
$this->$user = $user;
// printing here works
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
// ERROR HERE (Undefined variable: user)
$user = $this->$user;
return (new MailMessage)
->subject('Succesfully created new account')
->greeting(sprintf('Hello %s', $user->username))
->line('You have successfully registered to our system. Please activate your account.')
->action('Click here', route('activate.user', $user->activation_code))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
Register Method:
/**
* Register new user
*
* #param Request $request
* #return User
*/
protected function register(Request $request)
{
$validatedData = $request->validate([
'username' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
]);
try {
$validatedData['password'] = Hash::make(array_get($validatedData, 'password'));
$validatedData['activation_code'] = str_random(30).time();
$user = app(User::class)->create($validatedData);
} catch(\Exception $ex) {
logger()->error($ex);
return redirect()->back()->with('message', 'Unable to create new user.');
}
$user->notify(new UserRegisteredSuccessfully($user));
return redirect()->back()->with('message', 'Successfully created a new account. Please check your email and activate your account.');
}
Thanks in Advance!
You made 2 typos:
In your constructor:
$this->$user = $user;
Should be:
$this->user = $user;
And in the toMail() method:
$user = $this->$user;
Should be:
$user = $this->user;
The reason it is not working, is because you are currently using the value of $user as the variable name, and you are not assigning the value of the User object to $this->user.
I want to extend/overwrite my LinkedInProvider.php (in vendor\laravel\socialite\src\Two) to add new fields in the Linkedin Request.
I've create a new LinkedInProvider.php (in app\Providers) with the following code :
namespace App\Providers;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use Laravel\Socialite\Two\AbstractProvider;
use Laravel\Socialite\Two\ProviderInterface;
use Laravel\Socialite\Two\User;
class LinkedInProvider extends AbstractProvider implements ProviderInterface
{
/**
* The scopes being requested.
*
* #var array
*/
protected $scopes = ['r_basicprofile', 'r_emailaddress'];
/**
* The separating character for the requested scopes.
*
* #var string
*/
protected $scopeSeparator = ' ';
/**
* The fields that are included in the profile.
*
* #var array
*/
protected $fields = [
'id', 'first-name', 'last-name', 'formatted-name',
'email-address', 'headline', 'location', 'industry', 'positions',
'public-profile-url', 'picture-url', 'picture-urls::(original)',
];
/**
* {#inheritdoc}
*/
protected function getAuthUrl($state)
{
return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization', $state);
}
/**
* {#inheritdoc}
*/
protected function getTokenUrl()
{
return 'https://www.linkedin.com/oauth/v2/accessToken';
}
/**
* Get the POST fields for the token request.
*
* #param string $code
* #return array
*/
protected function getTokenFields($code)
{
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
}
/**
* {#inheritdoc}
*/
protected function getUserByToken($token)
{
$fields = implode(',', $this->fields);
$url = 'https://api.linkedin.com/v1/people/~:('.$fields.')';
$response = $this->getHttpClient()->get($url, [
'headers' => [
'x-li-format' => 'json',
'Authorization' => 'Bearer '.$token,
],
]);
return json_decode($response->getBody(), true);
}
/**
* {#inheritdoc}
*/
protected function mapUserToObject(array $user)
{
return (new User)->setRaw($user)->map([
'id' => $user['id'], 'nickname' => null, 'name' => Arr::get($user, 'formattedName'),
'email' => Arr::get($user, 'emailAddress'), 'avatar' => Arr::get($user, 'pictureUrl'),
'avatar_original' => Arr::get($user, 'pictureUrls.values.0'),
]);
}
/**
* Set the user fields to request from LinkedIn.
*
* #param array $fields
* #return $this
*/
public function fields(array $fields)
{
$this->fields = $fields;
return $this;
}
}
But now, I've got this error :
Type error: Argument 1 passed to Laravel\Socialite\Two\AbstractProvider::__construct() must be an instance of Illuminate\Http\Request, instance of Illuminate\Foundation\Application given, called in G:\laragon\www\localhost\vendor\laravel\framework\src\Illuminate\Foundation\ProviderRepository.php on line 201
I know I can install Socialite Manager, but I just want to overwrite the fields list to add new field (like position and industry)
You shouldn't have to overwrite/extend the whole class. In the Laravel\Socialite\Two\User object that is being created, there is a $user property, which contains the raw information the provider sent back.
When making the request, you can set the fields you want LinkedIn to return in your controller method:
public function redirectToProvider()
{
$fields = [
'id', 'first-name', 'last-name', 'formatted-name',
'email-address', 'headline', 'location', 'industry',
'public-profile-url', 'picture-url', 'picture-urls:(original)',
'positions', 'summary' // <-- additional fields here
];
return Socialite::driver('linkedin')->fields($fields)->redirect();
}
You can see two additional fields being requested, positions and summary, which aren't included by default.
Happy hacking!
I want user to register and also buy a package. To do that I took input for registration details and package details. Now when I'm processing order to save package details in session and register, I get this error : Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\View\View given, called in C:\xampp\htdocs\rename\app\Traits\OrderRegister.php on line 63 and defined. I'm using an trait to register user and return back to function when registration is complete.
OrderController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Package;
use App\ListingType;
use Illuminate\Support\Facades\Auth;
use App\Order;
use Carbon\Carbon;
use App\Traits\OrderRegister;
class OrderController extends Controller
{
use OrderRegister;
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index($type)
{
$listingtype = ListingType::where('type', '=', $type)->first();
if ($listingtype) {
$packages = $listingtype->packages()->get();
return view('packages.index', compact('packages'));
}
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create($id)
{
$package = Package::where('id', '=', $id)->first();
if (Auth::check()) {
return view('order.create_loggedin', compact('package'));
}
else {
return view('order.create_register', compact('package'));
}
}
/**
* Process a new order request. Store order values in session.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function process(Request $request)
{
$order = ['package_id' => $request->package_id, 'order_qty' => $request->no_of_listing];
session(['order' => $order]);
if (Auth::guest()) {
return $this->register($request); // need to check session for orders available in OrderRegister trait.
}
return $this->store($request);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
if($request->session()->has('order')) {
$package = Package::where('id', '=', $request->package_id )->first();
if($request->user() == Auth::user()) {
for( $n=1;$n<=$request->no_of_listing;$n++) {
$order = new Order;
$order->package_id = $request->package_id;
$order->user_id = Auth::user()->id;
$order->expire_at = Carbon::now()->modify('+'.$package->duration_in_months.' months');
$order->save();
}
return redirect('/');
}
}
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
trait : OrderRegister.php
<?php
namespace App\Traits;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Validator;
trait OrderRegister
{
use RedirectsUsers;
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'username' => 'required|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'username' => $data['username'],
'password' => bcrypt($data['password']),
]);
$user->profile()->save(new UserProfile);
return $user;
}
/**
* Execute the job.
*
* #return void
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
Auth::guard($this->getGuard())->login($this->create($request->all()));
return $this->store($request);
}
/**
* Get the guard to be used during registration.
*
* #return string|null
*/
protected function getGuard()
{
return property_exists($this, 'guard') ? $this->guard : null;
}
}
I could not find any solution for this error so created my own thread for the first time please someone help.
It throws an error because you are trying to login a vue.
in your OrderController.php you are using create method which return a view.
this method will override the create method on your trait.
So you have something like this :
Auth::guard($this->getGuard())->login(/* A view */);
you can at least rename the method on the trait from create to createUser for example.
then you call it from the guard like this :
Auth::guard($this->getGuard())->login($this->createUser($request->all()));