I need to select only id and name attribute from users table except roles attribute. I tried this:
$school_user = User::select('name', 'id')->get()->toArray();
but when I print it to screen it returns array with his roles. Like this:
Array
(
[0] => Array
(
[name] => Admin
[id] => 1
[roles] => Array
(
[0] => Array
(
[id] => 3
[name] => admin
[pivot] => Array
(
[user_id] => 1
[role_id] => 1
)
)
)
)
)
Any suggestions to get only name and id attributes except roles?
There is my User Model class (a bit cleaned):
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
protected $fillable = array('email', 'name', 'password', 'block');
protected $guarded = array('id');
/**
* Get the schools or kindergardens a user can moderate
*/
public function schools()
{
return $this->belongsToMany('School', 'school_user');
}
/**
* Get the roles a user has
*/
public function roles()
{
return $this->belongsToMany('Role', 'users_roles');
}
/**
* Find out if User is an employee, based on if has any roles
*
* #return boolean
*/
public function isEmployee()
{
$roles = $this->roles->toArray();
return !empty($roles);
}
/**
* Find out if user has a specific role
*
* $return boolean
*/
public function hasRole($check)
{
return in_array($check, array_fetch($this->roles->toArray(), 'name'));
}
/**
* Get key in array with corresponding value
*
* #return int
*/
private function getIdInArray($array, $term)
{
foreach ($array as $key => $value) {
if ($value['name'] == $term) {
return $key;
}
}
throw new UnexpectedValueException;
}
/**
* Add roles to user to make them a concierge
*/
public function makeEmployee($role_id)
{
$assigned_roles = array();
$roles = Role::all()->keyBy('id')->toArray();
$this->roles()->attach(array($role_id));
}
public $invitation;
protected static function boot()
{
parent::boot();
static::creating(function($model)
{
$data = array(
'invitation' => $model->invitation,
'email' => $model->email,
'name' => $model->name,
'password' => $model->password
);
$model->password = Hash::make($model->password);
$rules = array(
'invitation' => 'required',
'email' => 'unique:users,email|required|email',
'name' => 'required|min:3|max:20',
'password' => 'required|min:8|max:30'
);
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
throw new ValidationException(null, null, null, $validator->messages());
} else {
return $model->validate();
}
});
static::created(function($model)
{
$role_id = Invitation::where('code', '=', $model->invitation)->first()->role_id;
$model->makeEmployee($role_id);
$invitation_code = Invitation::where('code', '=', $model->invitation)->update(array('used_by' => $model->id));
});
}
public function validate()
{
if (is_null(Invitation::where('code', '=', $this->invitation)->where('used_by', '=', '0')->first())) {
throw new ValidationException(null, null, null, array('invitation' => "Грешен код."));
} else {
return true;
}
}
public function updatePass($old_password, $new_password, $repeat_new_password)
{
$data = array(
'old_password' => $old_password,
'new_password' => $new_password,
'repeat_new_password' => $repeat_new_password
);
$rules = array(
'old_password' => 'required',
'new_password' => 'required|min:8|max:30',
'repeat_new_password' => 'required|same:new_password'
);
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
throw new ValidationException(null, null, null, $validator);
} else {
$user = User::find(Auth::user()->id);
if (Hash::check($old_password, $user->password)) {
$user->password = Hash::make($new_password);
if($user->save()) {
return true;
} else {
throw new ValidationException(null, null, null, array('mainError' => "Грешка с базата данни."));
}
} else {
throw new ValidationException(null, null, null, array('old_password' => "Моля въведете правилно страта Ви парола."));
}
}
}
public function login($email, $password, $remember)
{
$data = array(
'email' => $email,
'password' => $password
);
$rules = array(
'email' => 'required|email',
'password' => 'required'
);
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
throw new ValidationException(null, null, null, $validator);
} else {
if (User::where('email', '=', $email)->first()->block == true) {
throw new ValidationException(null, null, null, array('mainError' => "Акаунтът ви е блокиран."));
} else {
$remember = ($remember) ? true : false;
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
return true;
} else {
throw new ValidationException(null, null, null, array('mainError' => 'Имейлът или паролата е грешна.'));
}
}
}
}
}
And Role Model:
<?php
class Role extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'roles';
protected $fillable = array('name');
protected $guarded = array('id');
/**
* Set timestamps off
*/
public $timestamps = false;
/**
* Get users with a certain role
*/
public function users()
{
return $this->belongsToMany('User', 'users_roles');
}
}
I'm sorry for use of bulgarian language in exceptions
Looking at the code it's rather not possible that running just:
$school_user = User::select('name', 'id')->get()->toArray();
make appending roles to result.
You should make sure that you don't add anything to $appends property and you don't load relationship somewhere in your code. You should also make sure that you don't have custom toArray() method implemented that loads this relationship when converting to array. If you are sure you don't you should show the full code and your exact Laravel version.
EDIT
You didn't show where you launch your code with select or lists however you load your roles relationship in many methods - for example isEmployee, isEmployee or hasRole. That's why roles are used when you are converting to array. You might want to write your custom toArray method to remove roles from your result set when converting to array.
Related
I am using Laravel 9, Vue 3 and Inertia.
I have created the following test:
public function test_send_notification(): void
{
Notification::fake();
$this->seed(OccupationSeeder::class);
$responder = Responder::factory()->create();
$responder->notify(new InviteResponder());
Notification::assertSentTo($responder, InviteResponder::class);
}
When I run the test I am getting
TypeError : Illegal offset type
It fails when executing
$this->notifications[get_class($notifiable)][$notifiable->getKey()][get_class($notification)][] = [
'notification' => $notification,
'channels' => $notifiableChannels,
'notifiable' => $notifiable,
'locale' => $notification->locale ?? $this->locale ?? value(function () use ($notifiable) {
if ($notifiable instanceof HasLocalePreference) {
return $notifiable->preferredLocale();
}
}),
];
in NotificationFake.php sendNow()
Here is part of my Responder model
class Responder extends Model
{
use HasFactory, Notifiable;
protected $primaryKey = 'uuid';
protected $keyType = 'string';
public $incrementing = false;
/**
* The attributes that are mass assignable.
*
* #var array<int, string>
*/
protected $fillable = [
'uuid',
'diagnostic_event_id',
'school_id',
'user_id',
'occupation_id',
'years',
'status'
];
/**
* Autogenerate uuid
*
* #return void
*/
protected static function boot()
{
parent::boot();
static::creating(function($model) {
// Automatically create an uuid when creating a new responder
$model->setAttribute($model->getKeyName(), Str::uuid());
});
}
and here is ResponderFactory
class ResponderFactory extends Factory
{
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition()
{
return [
'uuid' => $this->faker->uuid,
'diagnostic_event_id' => DiagnosticEvent::factory()->lazy(),
'school_id' => School::factory()->lazy(),
'user_id' => User::factory()->lazy(),
'occupation_id' => $this->faker->numberBetween(1,13),
'years' => $this->faker->numberBetween(1,5),
'status' => 'created',
'created_at' => now(),
'updated_at' => now()
];
}
}
When I call $responder->notify(...) in my program, I get no error.
Here is my ResponderController invite() function that works:
public function invite(Request $request): RedirectResponse
{
$this->authorize('create', Responder::class);
$responders = Responder::where('diagnostic_event_id', $request->diagnostic_event_id)->get();
$questions = Question::all();
DB::transaction( function() use ($request, $responders, $questions) {
foreach ($responders as $responder) {
// Skip if responder already notified
if ($responder->status === 'created') {
// Create null answers for the responder if not already exists
foreach ($questions as $question) {
Answer::create([
'diagnostic_event_id' => $request->diagnostic_event_id,
'responder_uuid' => $responder->uuid,
'question_id' => $question->id,
'score' => null
]);
}
// Send notification to responder
$responder->notify(new InviteResponder());
// Update responder status
$responder->update(['status' => 'sent']);
}
}
});
return redirect()->route('responder.select',
['event_id' => $request->diagnostic_event_id]);
}
What is wrong with my test and what can I do to fix this?
You may want to change your faker to this:
'uuid' => Str::ulid()->toBase32()
Or simply:
'uuid' => $this->newModel()->newUniqueId()
I'm struggling with getting my custom validator to work.
The thing is I have a custom form element that uses a custom validator.
But when field is being created the ValidatorPluginManager fails to find my custom validator.
Now I know that it's a scope issue but I can' resolve it.
Error message:
A plugin by the name "AliasExists" was not found in the plugin manager Zend\Validator\ValidatorPluginManager
Validator code:
class AliasExists
extends AbstractValidator
implements AdapterAwareInterface
{
use AdapterAwareTrait;
const NOT_UNIQUE = 'notUnique';
/**
* Validation failure message templates definition
*
* #var array
*/
protected $messageTemplates = [
self::NOT_UNIQUE => "Entry with alias %value% already exists",
];
/**
* #var string
*/
protected $table;
/**
* #var Select
*/
protected $select;
/**
* #var string
*/
protected $categoryField = 'category';
/**
* #var int
*/
protected $categoryValue;
public function __construct($options)
{
parent::__construct($options);
if ($options instanceof Traversable) {
$options = ArrayUtils::iteratorToArray($options);
} elseif ($options instanceof Adapter) {
$temp = [];
$temp['adapter'] = $options;
$options = $temp;
} else {
if (func_num_args() > 1) {
$options = func_get_args();
$firstArgument = array_shift($options);
if (is_array($firstArgument)) {
$temp = ArrayUtils::iteratorToArray($firstArgument);
} else {
$temp['table'] = $firstArgument;
}
if (!empty($options)) {
$temp['adapter'] = array_shift($options);
}
$options = $temp;
}
}
if (array_key_exists('table', $options)) {
$this->setTable($options['table']);
}
if (array_key_exists('adapter', $options)) {
$this->setAdapter($options['adapter']);
}
}
public function isValid($value, $context = null)
{
if (null === $this->adapter) {
throw new \RuntimeException('No database adapter set.');
}
if (empty($this->table)) {
throw new \RuntimeException('Table has not been set.');
}
$valid = true;
$this->setValue($value);
if ($context) {
// TODO
}
$result = $this->query($value);
if (!$result) {
$valid = false;
$this->error(self::NOT_UNIQUE);
}
return $valid;
}
public function getSelect()
{
if ($this->select instanceof Select) {
return $this->select;
}
$select = new Select();
$table = new TableIdentifier($this->table);
$select->from($table);
$select->where->equalTo(
'alias',
null
);
if (!empty($this->categoryField) && !empty($this->categoryValue)) {
$select->where->equalTo(
$this->categoryField,
$this->categoryValue
);
}
$select->columns(['id']);
$this->select = $select;
return $this->select;
}
/**
* Returns the set adapter
*
* #return Adapter
*/
public function getAdapter(): Adapter
{
return $this->adapter;
}
/**
* Sets a (new) DB adapter
*
* #param Adapter $adapter
* #return self Provides a fluent interface
*/
public function setAdapter(Adapter $adapter)
{
return $this->setDbAdapter($adapter);
}
/**
* Returns the set table
*
* #return string
*/
public function getTable(): string
{
return $this->table;
}
/**
* Sets a (new) table
*
* #param string $table
* #return self Provides a fluent interface
*/
public function setTable(string $table)
{
$this->table = $table;
$this->select = null;
return $this;
}
/**
* #return string
*/
public function getCategoryField(): string
{
return $this->categoryField;
}
/**
* #param string $categoryField
*/
public function setCategoryField(string $categoryField)
{
$this->categoryField = $categoryField;
}
/**
* #return int
*/
public function getCategoryValue(): int
{
return $this->categoryValue;
}
/**
* #param int $categoryValue
*/
public function setCategoryValue(int $categoryValue)
{
$this->categoryValue = $categoryValue;
}
protected function query($value)
{
$sql = new Sql($this->getAdapter());
$select = $this->getSelect();
$statement = $sql->prepareStatementForSqlObject($select);
$parameters = $statement->getParameterContainer();
$parameters['where1'] = (string)$value;
$result = $statement->execute();
return $result->current();
}
}
Validator factory:
class AliasExistsFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$db = $container->get(AdapterInterface::class);
return new AliasExists($db);
}
}
Custom form element code:
class Alias
extends Text
implements InputProviderInterface
{
protected $attributes = [
'name' => 'alias',
'required' => 'required',
'class' => 'form-control',
];
protected $label = 'Alias';
public function __construct($name = null, array $options = [])
{
parent::__construct($name, $options);
$this->setAttribute('id', $this->getName());
}
public function getInputSpecification()
{
return [
'name' => $this->getName(),
'required' => true,
'filters' => [
['name' => 'StringTrim'],
['name' => 'StringToLower'],
],
'validators' => [
[
'name' => 'NotEmpty',
'options' => [
'type' => 'string'
],
],
[
'name' => 'Regex',
'options' => [
'pattern' => '/^[0-9a-zA-Z-_]+$/',
'messages' => [
Regex::NOT_MATCH => 'Only numbers, underscore, dash and characters from A to Z are allowed'
],
],
],
[
'name' => 'StringLength',
'options' => [
'min' => 1,
'max' => 255
],
],
[
'name' => 'AliasExists', <--- Custom validator
]
],
];
}
}
module.config.php
'form_elements' => [
'factories' => [
Form\Element\Alias::class => InvokableFactory::class,
],
],
'validators' => [
'factories' => [
Validator\AliasExists::class => Factory\AliasExistsFactory::class,
],
'aliases' => [
'AliasExists' => Validator\AliasExists::class,
]
]
Controller factory that instantiates form that has this custom field:
class EditControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$formManager = $container->get('FormElementManager');
$form = $formManager->get(ArticleForm::class);
return new EditController($form);
}
}
The only way I can get my custom validator to work is (as found in this answer Possible to create a factory to instantiate custom Form validators?) is to set validator chain in controller factory that instantiates form but its an overkill to have to do this in every controller factory that could possibly have a form that uses this field that has custom validator in it.
I have seen tutorial on how to uses the default authentication mechanism of laravel.
I want to make my authentication to work for different parameters.
I have following to store in the controller which is for registration of an user:
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'username' => 'required|max:255',
'email' => 'required',
'password' => 'required|alphaNum|min:6',
]);
if ($validator->fails()) {
return redirect('/register')
->withInput()
->withErrors($validator);
}
$confirmation=$this->createConfirmation_code();
$user = new User;
$user->first_name = $request->first_name;
$user->last_name = $request->last_name;
$user->username = $request->username;
$user->email = $request->email;
$user->password = -$request->password;
$user->country = $request->country;
$user->street = $request->street;
$user->zip = $request->zip;
$user->state = $request->state;
$user->city = $request->city;
$user->state = $request->city_state;
$user->institute = $request->institute;
$user->confirmation_code=$confirmation;
$user->confirmed='no';
$this->sendEmailReminder($request,$user);
User::create([
'first_name' => $user->first_name,
'last_name' => $user->last_name,
'username' =>$user->username,
'email' =>$user->email,
'password' => bcrypt($user->password),
'country' =>$user->country,
'street' =>$user->street,
'zip' => $user->zip,
'state' =>$user->state,
'institute' =>$user->institute,
'confirmation_code' =>$user->confirmation_code,
'confirmed' => $user->confirmed
]);
return redirect('/confirm')->with('user',$user);
}
Then for login I an using the following:
public function login(Request $request)
{
$rules = array(
'username' => 'required',
'password' => 'required'
);
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
return Redirect::to('/login')
->withErrors($validator);
} else {
$userdata = array(
'username' => $request->username,
'password' => $request->password
);
// attempt to do the login
if (Auth::attempt($userdata)) {
return redirect('/{username}');
} else {
return Redirect::to('/login');
}
}
}
But my login is being failed.
Here is the handle in my Authenticate class:
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
}
}
return $next($request);
}
This is my User model:
class User extends Authenticatable
{
protected $fillable = [
'first_name', 'last_name','username','email','password','country','street','zip','state','institute','confirmation_code','confirmed'
];
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password');
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
public function getRememberToken()
{
return $this->remember_token;
}
public function setRememberToken($value)
{
$this->remember_token = $value;
}
public function getRememberTokenName()
{
return 'remember_token';
}
}
And I have not made any change to the default auth.php file. Can anyone help me how can i make it work?
I am developing my own login and I have the following code
public function login(Request $request ) {
$email = \Request::input('email');
$password = \Request::input('password');
if (Auth::attempt(['email' => $email, 'password' => $password]))
{
//echo "success";
return redirect('home');
}
else {
return "fail";
}
}
And the CreateUserRequest
<?php namespace App\Http\Requests;
use App\Http\Requests\Request;
class CreateUserRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'nif' => 'required | max:9 ',
'name' => 'required | max:255',
'email' => 'required',
'cognoms' => 'required | max:255',
'birthday' => 'required',
'password' => 'required | confirmed',
'password_confirmation' => 'required',
'municipios' => 'required | Integer|Min:1',
'presentacion' => 'required',
'file' => 'required'
];
}
}
My register controller
public function registro(CreateUserRequest $request){
$usuario = new User();
$usuario->nif = \Request::input('nif');
$usuario->name = \Request::input('name');
$usuario->cognoms = \Request::input('cognoms');
$usuario->birthday = \Request::input('birthday');
$usuario->email = \Request::input('email');
$usuario->password= \Request::input('password');
/**Foto del usuario**/
$file = \Request::file('file');
$fileName = $file->getClientOriginalName();
$file->move(public_path().'/uploads/', $fileName);
$usuario->file = 'uploads/'.$fileName.'';
$usuario->save();
/**Asignamos el rol a la tabla intermedia***/
$user = User::find($usuario->id);
$user->roles()->attach(1);
return redirect('/');
}
The model
<?php namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['nif','name','cognoms','email', 'password','idempresa','id_poblacion','id_online',];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function empresa()
{
return $this->belongsTo('Empresa');
}
public function municipio()
{
return $this->belongsTo('App\Ciudad','id_poblacion');
}
public function roles()
{
return $this->belongsToMany('App\Rol')->withPivot('user_id','rol_id');
}
public function mensajes()
{
return $this->belongsToMany('App\User')->withPivot('id_emisor','id_receptor');
}
public function subastas(){
return $this->hasMany('App\Subasta','id_creador','id');
}
public function pujas(){
return $this->hasMany('App\Puja','id_subasta','id');
}
}
When I put the password , the laravel create the user andthe field password in database is white.
Please try this:
public function registro(CreateUserRequest $request){
$file = $request->file('file');
$fileName = $file->getClientOriginalName();
$file->move(public_path().'/uploads/', $fileName);
$user = User::create([
'nif' => $request->input('nif'),
'name' => $request->input('name'),
'cognoms' => $request->input('cognoms'),
'birthday' => $request->input('birthday'),
'email' => $request->input('email'),
'password' => \Hash::make($request->input('password')),
'file' => 'uploads/'.$fileName.'',
]);
/**Asignamos el rol a la tabla intermedia***/
$user = User::find($user->id);
$user->roles()->attach(1);
return redirect('/');
}
I'm making a multi select form element for updating schools and specialties pivot table school_specialty. The problem is that when I change only something in multi select not other inputs or textareas, I can't listen model events so I can't sync school_specialty table. But when I fill in any other input it's works perfect. Here's my multi select from blade:
{{Form::select('specialties[]', $specialties_data, $school->specialties, array('multiple' => 'true', 'id' => 'multi-select'))}}
This is my update method from school controller:
public function update($id)
{
$data = Input::only('name', 'type_id', 'description', 'info_specialties', 'contacts', 'specialties', 'financing_id', 'district_id', 'city_id');
$school = School::find($id);
$school->name = $data['name'];
$school->type_id = $data['type_id'];
$school->description = $data['description'];
$school->info_specialties = $data['info_specialties'];
$school->contacts = $data['contacts'];
$school->cover_photo = Input::file('cover_photo');
$school->set_specialties = $data['specialties'];
$school->financing_id = $data['financing_id'];
$school->set_district_id = $data['district_id'];
$school->city_id = $data['city_id'];
try {
$school->save();
} catch (ValidationException $errors) {
return Redirect::route('admin.schools.edit', array($id))
->withErrors($errors->getErrors())
->withInput();
}
return Redirect::route('admin.schools.edit', array($id))
->withErrors(array('mainSuccess' => 'School was created.'));
}
And here's my example school model:
<?php
class School extends Eloquent {
protected $table = 'schools';
protected $fillable = array('name', 'type_id', 'description', 'city');
protected $guarded = array('id');
protected $appends = array('specialties');
public $set_specialties;
public $set_district_id;
protected static function boot()
{
parent::boot();
static::updating(function($model)
{
$data = array(
'name' => $model->name,
'type_id' => $model->type_id,
'description' => $model->description,
'specialties' => $model->set_specialties,
'city_id' => $model->city_id
);
$rules = array(
'name' => 'required|min:3|max:50',
'type_id' => 'required|min:1|max:300000',
'description' => 'required|min:10',
'specialties' => 'required|array',
'city_id' => 'required|min:1|max:300000'
);
$validator = Validator::make($data, $rules);
if ($validator->fails()) {
throw new ValidationException(null, null, null, $validator->messages());
} else {
return true;
}
});
static::updated(function($model)
{
if ( $model->set_specialties != null )
{
$model->specialty()->sync($model->set_specialties);
}
});
}
public function specialty()
{
return $this->belongsToMany('Specialty', 'school_specialty');
}
}
?>
When updating only school specialities the School model events aren't triggered because the School model stays the same.
I think the simplest and most elegant solution is to touch the school model instance. This will modify the updated_at field for the School object and thus trigger the model events.
To do this add the following lines before the try/catch block:
if ($school->set_specialties !== null) {
$school->touch();
}
Also, validation shouldn't be handled in the model observers. Check form request validation here: https://laravel.com/docs/5.6/validation#form-request-validation.