Field 'identifier' doesn't have a default value - Laravel [duplicate] - php

This question already has answers here:
Laravel 5.4 field doesn't have a default value
(10 answers)
Closed 1 year ago.
Good afternoon to y'all!
Somewhere in the past week, I changed something in the website that caused the following error:
SQLSTATE[HY000]: General error: 1364 Field 'identifier' doesn't have a default value (SQL: insert into `classifieds` (`vehicle_id`, `vehicle_type`, `updated_at`, `created_at`) values (19983, App\Models\Car, 2021-04-27 16:27:56, 2021-04-27 16:27:56))
It's is very weird, because the $fillable is set (and it worked before).
This is the content being used:
Classified Model:
<?php
namespace App\Models;
use App\Http\Controllers\Controller;
use App\Rules\FileUploader;
use App\Rules\VehicleRegDate;
use Auth;
use Cache;
use CyrildeWit\EloquentViewable\Contracts\Viewable;
use CyrildeWit\EloquentViewable\InteractsWithViews;
use Eloquent;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Rennokki\QueryCache\Traits\QueryCacheable;
use ShiftOneLabs\LaravelCascadeDeletes\CascadesDeletes;
use Throwable;
/**
* App\Models\Classified
*
* #property int $id
* #property string $identifier
* #property int|null $vehicle_id
* #property string|null $vehicle_type
* #property int $proprietor_id
* #property string $proprietor_type
* #property float $price
* #property Carbon|null $created_at
* #property Carbon|null $updated_at
* #property-read Collection|Equipment[] $equipments
* #property-read int|null $equipments_count
* #property-read Collection|Media[] $medias
* #property-read int|null $medias_count
* #property-read Model|Eloquent $proprietor
* #property-read Model|Eloquent $vehicle
* #method static Builder|Classified newModelQuery()
* #method static Builder|Classified newQuery()
* #method static Builder|Classified query()
* #method static Builder|Classified whereCreatedAt($value)
* #method static Builder|Classified whereId($value)
* #method static Builder|Classified whereIdentifier($value)
* #method static Builder|Classified wherePrice($value)
* #method static Builder|Classified whereProprietorId($value)
* #method static Builder|Classified whereProprietorType($value)
* #method static Builder|Classified whereUpdatedAt($value)
* #method static Builder|Classified whereVehicleId($value)
* #method static Builder|Classified whereVehicleType($value)
* #mixin Eloquent
* #property string|null $identifier_old
* #property float $lat
* #property float $lng
* #property string|null $video_embed
* #property int|null $phone
* #property int|null $type
* #property int $status
* #property-read Collection|Advertising[] $adverts
* #property-read int|null $adverts_count
* #property-read Collection|Feature[] $features
* #property-read int|null $features_count
* #property-read Collection|Message[] $messages
* #property-read int|null $messages_count
* #property-read Collection|PriceOption[] $price_options
* #property-read int|null $price_options_count
* #property-read Sharing|null $sharing
* #method static Builder|Classified whereIdentifierOld($value)
* #method static Builder|Classified whereLat($value)
* #method static Builder|Classified whereLng($value)
* #method static Builder|Classified wherePhone($value)
* #method static Builder|Classified whereStatus($value)
* #method static Builder|Classified whereType($value)
* #method static Builder|Classified whereVideoEmbed($value)
*/
class Classified extends Model implements Viewable
{
use CascadesDeletes, QueryCacheable, InteractsWithViews;
const STATUS_INACTIVE = 0;
const STATUS_ACTIVE = 1;
const STATUS_PENDING = 2;
const STATUS_RETOUCH = 3;
const STATUS_ARCHIVED = 4;
const STATUS_REFUSED = 5;
const STATUS_EXPIRED = 6;
protected static $flushCacheOnUpdate = true;
public $cacheFor = 86400;
protected $fillable = [
'identifier',
'identifier_old',
'proprietor_id',
'proprietor_type',
'price',
'lat',
'lng',
'video_embed',
'phone',
'type',
'status',
'created_at',
'updated_at'
];
protected $hidden = [
'id',
'identifier_old',
'proprietor_id',
'proprietor_type',
'vehicle_id',
'vehicle_type',
'lat',
'lng',
'phone',
];
protected array $cascadeDeletes = ['medias', 'equipments', 'features', 'price_options', 'messages', 'adverts', 'sharing'];
public array $rules = [
'classified',
'car',
'motorcycle',
'bike'
];
public function __construct()
{
$this->rules['classified'] = [
'vehicle_type' => 'required|alpha|in:car,motorcycle,bike',
'type' => 'required|integer|exists:vehicle_data,id',
'price' => 'required|numeric|min:1',
'price_options.*' => 'nullable|integer|min:1',
'features.*' => 'nullable|integer|exists:vehicle_data,id',
'equipments.*' => 'nullable|integer|exists:vehicle_data,id',
'fileuploader-list-files' => ['required', 'json', new FileUploader],
'phone' => 'nullable|numeric|digits:9',
'address' => 'nullable|string',
'terms' => 'required|boolean',
];
$this->rules['car'] = [
'make' => 'required|integer|exists:vehicle_data,id',
'model' => 'required|integer|exists:vehicle_data,id',
'version' => 'nullable|string',
'fuel' => 'required|integer|exists:vehicle_data,id',
'firstRegDate' => ['required', new VehicleRegDate()],
'mileage' => 'required|integer|min:0',
'displacement' => 'required|integer|min:1',
'power_kw' => 'nullable|integer|min:1',
'power_hp' => 'nullable|integer|min:1',
'bodyType' => 'required|integer|exists:vehicle_data,id',
'bodyColour' => 'required|integer|exists:vehicle_data,id',
'vin' => 'nullable|string|min:17|max:17',
'annotations' => 'nullable|string',
'transmission' => 'nullable|integer|exists:vehicle_data,id',
'gears' => 'nullable|integer|exists:vehicle_data,id',
'doors' => 'nullable|integer|exists:vehicle_data,id',
'seats' => 'nullable|integer|exists:vehicle_data,id',
'vehicle_class' => 'nullable|integer|exists:vehicle_data,id',
'driveTrainType' => 'nullable|integer|exists:vehicle_data,id',
'maxFuelRange' => 'nullable|numeric|min:1',
'emission' => 'nullable|numeric|min:0.01',
'iuc' => 'nullable|numeric|min:1',
'particleFilter' => 'nullable|boolean',
'warrantyDate' => 'nullable|date_format:d-m-Y',
'warrantyKM' => 'nullable|integer|min:1',
'inspectionDate' => 'nullable|date_format:d-m-Y',
'registries' => 'nullable|integer|exists:vehicle_data,id',
'origin' => 'nullable|integer|exists:vehicle_data,id',
'license' => 'nullable|string',
'fuelConsumptionCity' => 'nullable|numeric|min:1',
'fuelConsumptionHighway' => 'nullable|numeric|min:1',
'fuelConsumptionAverage' => 'nullable|numeric|min:1',
'vintage' => 'nullable|boolean',
'video_embed' => 'nullable|string'
];
$this->rules['bike'] = [
'framework' => 'nullable|string',
'wheel-size' => 'nullable|numeric|min:1',
'material' => 'nullable|string',
'suspension' => 'nullable|string',
'suspension-travel' => 'nullable|string',
'shock-absorber' => 'nullable|string',
'damping-travel' => 'nullable|string',
'type-of-brake' => 'nullable|string',
'brakes' => 'nullable|string',
'speeds' => 'nullable|string',
'gearshift-lever' => 'nullable|string',
'rear-change' => 'nullable|string',
'casset' => 'nullable|string',
'chain' => 'nullable|string',
'pedal' => 'nullable|string',
'roses' => 'nullable|string',
'cubes' => 'nullable|string',
'tires' => 'nullable|string',
'steering-gearbox' => 'nullable|string',
'advance' => 'nullable|string',
'guideline' => 'nullable|string',
'fingers' => 'nullable|string',
'saddle' => 'nullable|string',
'seat-post' => 'nullable|string',
'brand' => 'nullable|string',
'warranty' => 'nullable|string',
'hard-tail-full-suspension' => 'nullable|string',
'year' => 'nullable|integer|min:1990|max:' . date('Y'),
'engine' => 'nullable|string',
'battery' => 'nullable|string',
];
parent::__construct();
}
public function proprietor(): MorphTo
{
return $this->morphTo();
}
public function vehicle(): MorphTo
{
return $this->morphTo();
}
public function equipments(): BelongsToMany
{
return $this->belongsToMany(VehicleData::class, 'classified_equipment', 'classified_id', 'equipment_id');
}
public function features(): BelongsToMany
{
return $this->belongsToMany(VehicleData::class, 'classified_feature', 'classified_id', 'feature_id');
}
public function price_options(): BelongsToMany
{
return $this->belongsToMany(VehicleData::class, 'classified_price_option', 'classified_id', 'price_option_id');
}
public function messages(): HasMany
{
return $this->hasMany(Message::class);
}
public function adverts(): HasMany
{
return $this->hasMany(Advertising::class);
}
public function sharing(): MorphOne
{
return $this->morphOne(Sharing::class, 'object');
}
public function medias(): MorphMany
{
return $this->morphMany(Media::class, 'mediable');
}
public function getFeaturedMedia($size = null): string
{
try {
if ($media = $this->medias()->orderBy('index', 'ASC')->first())
return $media->getMediaRoute($size);
if ($this->video_embed)
return sprintf("https://i.ytimg.com/vi/%s/hqdefault.jpg", $this->video_embed);
throw new Exception();
} catch (Throwable $exception) {
return asset_cdn('assets/img/default_listing.jpg');
}
}
public function getRoute(): string
{
return route("classified.show", [$this->identifier, $this->getSlug()]);
}
public function getSlug(): string
{
return Str::slug($this->getTitle());
}
public function getTitle($size = null)
{
try {
if ($this->isOtherMake() && $this->isOtherModel())
$title = $this->vehicle->version;
elseif ($this->isOtherMake())
$title = $this->getModelName() . " " . $this->vehicle->version;
else
$title = $this->getMakeName() . " " . $this->getModelName() . " " . $this->vehicle->version;
if ($size)
return Str::limit($title, $size);
return $title;
} catch (Throwable $exception) {
return $this->vehicle->version;
}
}
public function getVehicleType(): ?string
{
try {
return strtolower(explode("\\", $this->vehicle_type)[2]);
} catch (Throwable $exception) {
return null;
}
}
public function getMakeName()
{
try {
return (new Controller())->getVehicleMakeByAttr($this->getVehicleType(), $this->vehicle->make, 'id', 'value');
} catch (Throwable $exception) {
return null;
}
}
public function getMakeNameOld()
{
try {
return config('constants.' . $this->getVehicleType() . '.makes.' . $this->vehicle->make);
} catch (Throwable $exception) {
return null;
}
}
public function getModelName()
{
try {
return (new Controller())->getVehicleModelByModelAttr($this->getVehicleType(), $this->vehicle->make, $this->vehicle->model, 'id', 'value');
} catch (Throwable $exception) {
return null;
}
}
public function getModelNameOld()
{
try {
return config('constants.' . $this->getVehicleType() . '.models.' . $this->vehicle->make . '.' . $this->vehicle->model);
} catch (Throwable $exception) {
return null;
}
}
public function getFirstRegDate()
{
try {
return Carbon::parse($this->vehicle->firstRegDate);
} catch (Throwable $exception) {
return Carbon::parse($this->vehicle->firstRegDate);
}
}
public function getFuelType()
{
$fuelType = Cache::get(sprintf("vehicle_data_%s_%s_%s_leaf", "classified", "fuel", $this->vehicle->fuel));
try {
return $fuelType->value;
} catch (Throwable $exception) {
return "Outro";
}
}
public function getVersion($size = null)
{
try {
if ($size)
return Str::limit($this->vehicle->version, $size);
else
return $this->vehicle->version;
} catch (Throwable $exception) {
return null;
}
}
public function getFormattedNumber($number, $decimal = 0)
{
return number_format($number, $decimal, ',', ' ');
}
public function getBodyTypeName()
{
try {
$bodyType = Cache::get(sprintf("vehicle_data_%s_%s_%s", $this->getVehicleType(), "bodyTypes", $this->vehicle->bodyType));
return $bodyType->first()->value;
} catch (Throwable $exception) {
return "Outro";
}
}
public function getBodyColourName() // Fix
{
try {
$object = VehicleData::findOrFail($this->vehicle->bodyColour);
return $object->value;
} catch (Throwable $exception) {
return "Outro";
}
}
public function getTransmissionName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->transmission);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getGearsNumber()
{
try {
$object = VehicleData::findOrFail($this->vehicle->gears);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getDoorsNumber()
{
try {
$object = VehicleData::findOrFail($this->vehicle->doors);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getClassName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->vehicle_class);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getOriginName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->origin);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getLicenseFormated()
{
try {
$license = strtoupper($this->vehicle->license);
if (strlen($license) == 6) {
$parts = str_split($license, 2);
return implode('-', $parts);
}
return $license;
} catch (Throwable $exception) {
return "00-00-00";
}
}
public function getDriveTrainTypeName()
{
try {
$object = VehicleData::findOrFail($this->vehicle->driveTrainType);
return $object->value;
} catch (Throwable $exception) {
return null;
}
}
public function getDateFormated($date)
{
return Carbon::parse($date)->format('d-m-Y');
}
public function getDateStatus($date)
{
if (Carbon::parse($this->vehicle->$date) >= Carbon::today()->addDays(30))
return "warning";
elseif (Carbon::parse($this->vehicle->$date) < Carbon::today())
return "danger";
else
return "info";
}
public function getVehicleTypeClassByName($name, $class = null)
{
switch ($name) {
case "car":
if (!$class)
return "App\Models\Car";
else
return Car::class;
case "motorcycle":
if (!$class)
return "App\Models\Motorcycle";
else
return Motorcycle::class;
default:
return null;
}
}
public function getVehicleTypeByClass()
{
switch ($this->vehicle_type) {
case Car::class:
return 'car';
case Motorcycle::class:
return 'motorcycle';
default:
return null;
}
}
public function getVehicleTypeNameByClass()
{
switch ($this->vehicle_type) {
case Car::class:
return 'Carro';
case Motorcycle::class:
return 'Moto';
default:
return null;
}
}
public function getPhoneViews()
{
return 0;
}
public function getStatusElements()
{
return config('constants.status.' . $this->status);
}
public function getAddress()
{
try {
return (new Controller())->getAddressFromGeoPosition($this->lat, $this->lng, 'city');
} catch (Throwable $exception) {
return "";
}
}
public function getArticleCategory()
{
switch ($this->vehicle_type) {
case Car::class:
return 1;
case Motorcycle::class:
return 2;
default:
return null;
}
}
public function isOtherMake(): bool
{
try {
$controller = new Controller();
if ($this->vehicle->make == $controller->getVehicleMakeOtherByVTypeAttr($this->getVehicleType(), 'slug', 'id'))
return true;
return false;
} catch (Throwable $exception) {
return false;
}
}
public function isOtherModel(): bool
{
try {
if ($this->vehicle->model == 0)
return true;
return false;
} catch (Throwable $exception) {
return false;
}
}
public function flushCache()
{
try {
Cache::forget('classified_' . $this->identifier);
Cache::forget('medias_classified_' . $this->identifier);
Cache::remember('classified_' . $this->identifier, 33600, function () {
return $this;
});
Cache::remember('medias_classified_' . $this->identifier, 33600, function () {
return $this->medias()->orderBy('index', 'ASC')->get();
});
} catch (Throwable $exception) {
}
}
public function isProprietor()
{
try {
if (Auth::check()) {
if (session()->has('professional_user') && $this->proprietor_type == Branch::class && $this->proprietor_id == session()->get('professional_user'))
return true;
elseif ($this->proprietor_type == User::class && $this->proprietor_id == Auth::id())
return true;
elseif (Auth::user()->isAdmin())
return true;
}
} catch (Throwable $exception) {
return false;
}
}
public function getFavourites()
{
try {
return $this->favourites->count();
} catch (Throwable $exception) {
return 0;
}
}
public function isMyFavourite(): bool
{
try {
$controller = new Controller();
if ($this->favourites()->where([
'proprietor_id' => $controller->getProprietorId(),
'proprietor_type' => $controller->getProprietorType()
])->count() > 0)
return true;
} catch (Throwable $exception) {
}
return false;
}
public function favourites()
{
return $this->hasMany(ClassifiedFavourite::class);
}
}
store method:
public function store(Request $request): JsonResponse
{
$rules = (new Classified)->rules;
$request->validate($rules['classified']);
$request->validate($rules[$request->input('vehicle_type')]);
DB::beginTransaction();
try {
$vehicleData = $request->all();
$vehicleData['firstRegDate'] = Carbon::createFromFormat('m-Y', $vehicleData['firstRegDate'])->toDateString();
$vehicle = (new Classified())->getVehicleTypeClassByName($request->input('vehicle_type'))::create($vehicleData);
if ($request->has('address'))
$geoData = $this->getGeoPositionFromAddress($request->input('address'));
else
$geoData = (object)[
"lat" => 0,
"lng" => 0
];
$formData = $request->all();
$formData['identifier'] = $this->generateIdentifier();
$formData['proprietor_id'] = $this->getProprietorId();
$formData['proprietor_type'] = $this->getProprietorType();
$formData['lat'] = $geoData->lat;
$formData['lng'] = $geoData->lng;
$formData['video_embed'] = $this->getYoutubeVideoID($request->input('video_embed'));
$formData['status'] = Classified::STATUS_PENDING;
$classified = $vehicle->classified()->create($formData);
$vehicle->classified->price_options()->attach($request->input('price_options'));
$vehicle->classified->features()->attach($request->input('features'));
$vehicle->classified->equipments()->attach($request->input('equipments'));
$medias = json_decode($request->{'fileuploader-list-files'}, true);
foreach ($medias as $media) {
$file = Media::where('name', $media->file)->first();
if ($file) {
$file->mediable_id = $vehicle->classified->id;
$file->saveOrFail();
}
}
if ($formData['proprietor_type'] == User::class && $request->has('phone') && $request->has('address'))
$this->updateUserPhoneAndAddress($formData['phone'], $formData['address']);
$classified->sharing()->create([
'status' => Sharing::STATUS_PENDING,
]);
if ($classified->status == Classified::STATUS_PENDING)
$this->adminAlert($classified);
DB::commit();
toastr()->success("Anúncio submetido para aprovação.");
return response()->json([
'redirect_url' => route('classified.feature', $vehicle->classified->identifier),
]);
} catch (Throwable $exception) {
DB::rollBack();
return response()->json([
'errors' => [trans('custom.error_occurred'), $exception->getMessage()]
], 500);
}
}
Stack Error: https://pastebin.com/jPypBG8P
Anyone has any idea on may be causing this?

Apparently it was the constructor in the Classified Model that was preventing.
A special Thanks to #Tim Lewis !

Related

Empty data table symfony 3.4 to 4.4

I currently have a big problem on my Symfony project since I switched to version 4.4. My versioning was correctly done but I have a "Project" page that displays all the projects created in the website database. The problem is that the project creation is feasible and the projects are well displayed in the database but the site does not display them. I checked the code of my ProjectController and everything seems to be normal. However, I changed one line of it because the syntax for calling classes through the getRepository has changed between versions 3.4 and 4.4. Before, I used to call my classes by doing getRepository('App::$className') with a className variable whose value changed depending on the classes that were called on my page. Now a getRepository doesn't accept the 'App::' and so I had to define the path of my classes by setting getRepository('App::$className'). And I have the impression that the problem can come from here because maybe it only retrieves the first class called and doesn't go to the next one.
I can't solve the problem because it's not an error message, so I'm looking for a needle in a haystack. I don't have a lot of experience with symfony because I've never used this framework before, so I came up with this project that just needed an upgrade.
I put the code of my ProjectController just below to better understand my explanation.
<?php
namespace App\Controller;
use App\Entity\Advancement;
use App\Entity\Alert;
use App\Entity\Project;
use App\Entity\State;
use App\Form\Search\ProjectSearchType;
use App\Form\Type\AdvancementType;
use App\Form\Type\AlertType;
use App\Form\Type\ProjectType;
use App\Model\ProjectSearch;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ProjectController extends BaseController
{
protected function listAction($className, $params = array())
{
return array_merge(array(
'title' => 'title.' . $className . '.list',
'pagetitle' => 'title.' . $className . '.list',
$className . 's' => $this->getRepository('App\\Entity\\' . $className)->getList(),
), $params);
}
protected function createAction($request, $project, $form, $className)
{
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$entity = $form->getData();
$entity->setCreatedBy($this->getUser());
$entity->setCreatedAt(new \DateTime());
$this->persist($entity);
$this->flush();
$this->addFlash('success', 'flash.success.created.' . $className);
return $this->redirect($this->generateUrl('project_edit', array('id' => $project->getId())) . '#tab-' . $className);
}
return array(
'form' => $form->createView(),
'title' => $this->trans('title.' . $className . '.create'),
'pagetitle' => $this->trans('title.' . $className . '.create'),
'projectLink' => $this->generateUrl('project_edit', array('id' => $project->getId())),
);
}
protected function editAction($request, $project, $form, $className, $class)
{
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$entity = $form->getData();
$entity->setUpdatedBy($this->getUser());
$entity->setUpdatedAt(new \DateTime());
$this->flush();
$this->addFlash('success', 'flash.success.updated.' . $className);
return $this->redirect($this->generateUrl('project_edit', array('id' => $project->getId())) . '#tab-' . $className);
}
return array(
'form' => $form->createView(),
'title' => $this->trans('title.' . $className . '.edit', array('%name%' => $class)),
'pagetitle' => $this->trans('title.' . $className . '.edit', array('%name%' => $class)),
'projectLink' => $this->generateUrl('project_edit', array('id' => $project->getId())),
);
}
protected function deleteAction($class, $className)
{
try {
$this->remove($class);
$this->flush();
$this->addFlash('success', 'flash.success.deleted.' . $className);
} catch (ForeignKeyConstraintViolationException $e) {
$this->addFlash('error', 'flash.error.deleted.' . $className);
}
if ($className != 'project') {
$id = $class->getProject()->getId();
$route = $this->generateUrl('project_edit', array('id' => $id)) . '#tab-' . $className;
} else {
$route = $this->generateUrl('project_list');
}
return $this->redirect($route);
}
/**
* #Route("/projects/{page}", defaults={"page":1}, name="project_list")
* #Template("Project\listProject.html.twig")
* #Security("has_role('ROLE_READER')")
*/
public function projectListAction(Request $request, $page = 1)
{
$searchModel = new ProjectSearch();
if (!$this->isGranted('ROLE_READER')) {
$searchModel->setCompany($this->getUser()->getCompany());
}
$searched = $searchModel;
$searchForm = $this->get('form.factory')->createNamed('', ProjectSearchType::class, $searchModel, array(
'method' => 'GET',
'action' => $this->generateUrl('project_list') . '#results',
));
$searchForm->handleRequest($request);
if ($searchForm->isSubmitted() && $searchForm->isValid()) {
$searched = $searchForm->getData();
}
$pager = $this->getPager($page, $this->getRepository(Project::class)->getSearchQuery($searched), $searchModel->getPerPage());
return $this->listAction('project', array(
'pager' => $pager,
'projects' => $pager->getCurrentPageResults(),
'searchForm' => $searchForm->createView(),
));
}
/**
* #Route("/project/new",name="project_create")
* #Template("Project\createProject.html.twig")
* #Security("has_role('ROLE_READER')")
*/
public function projectCreateAction(Request $request)
{
$project = new Project();
$project->setBeginAt(new \DateTime());
$project->setState($this->getRepository(State::class)->find(State::INITIALIZED));
$project->setCompany($this->getUser()->getCompany());
$form = $this->createForm(ProjectType::class, $project, array(
'mode' => 'create',
'display_company_select' => $this->isGranted('ROLE_SUPERADMIN'),
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$project = $form->getData();
$project->setCreatedBy($this->getUser());
$this->persist($project);
$this->flush();
$this->addFlash('success', 'flash.success.created.project');
return $this->redirect($this->generateUrl('project_list'));
}
return array(
'modeEdit' => false,
'form' => $form->createView(),
'title' => $this->trans('title.project.create'),
'pagetitle' => $this->trans('title.project.create'),
'project' => $project,
);
}
/**
* #Route("/project/edit/{id}", name="project_edit")
* #Template("Project\createProject.html.twig")
* #Security("is_granted('edit', project)")
*/
public function projectEditAction(Request $request, Project $project)
{
$project = $this->getManager(Project::class)->initForEdition($project);
$form = $this->createForm(ProjectType::class, $project, array(
'display_company_select' => $this->isGranted('ROLE_SUPERADMIN'),
));
try {
$alerts = $this->getRepository(Alert::class)->getAlertsByProject($project);
} catch (Exception $e) {
$alerts = array(new Alert());
}
try {
$advancements = $this->getRepository(Advancement::class)->getAdvancementsByProject($project);
} catch (Exception $e) {
$advancements = array(new Advancement());
}
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$project = $this->getManager(Project::class)->updateProject($form->getData());
$this->flush();
$this->addFlash('success', 'flash.success.updated.project');
return $this->redirect($this->generateUrl('project_list'));
}
return array(
'modeEdit' => true,
'form' => $form->createView(),
'advancements' => $advancements,
'alerts' => $alerts,
'title' => $this->trans('title.project.edit', array('%name%' => $project)),
'pagetitle' => $this->trans('title.project.edit', array('%name%' => $project)),
'project' => $project,
);
}
/**
* #Route("/project/view/{id}", name="project_view")
* #Template("viewProject.html.twig")
* #Security("is_granted('view', project)")
*/
public function projectViewAction(Request $request, Project $project)
{
return $this->projectEditAction($request, $project);
}
/**
* #Route("/project/delete/{id}", name="project_delete")
*/
public function projectDeleteAction(Request $request, Project $project)
{
// #todo : voir le delete en cascade
return $this->deleteAction($project, 'project');
}
/**
* #Route("/project/print", name="project_print")
*/
public function projectPrintAction(Request $request)
{
$projects = $this->getRepository(Project::class)->findById(array_keys($request->request->all()));
$html = '';
foreach ($projects as $project) {
$html .= $this->renderView('resume.html.twig', array(
'project' => $project,
));
}
if ($html == '') {
$this->addFlash('error', 'warn.project.check');
return $this->redirect($this->generateUrl('project_list'));
}
// Génération du pdf
$html2pdf = $this->get('html2pdf_factory')->create();
$html2pdf->WriteHTML($html);
return new Response(
$html2pdf->Output(),
200,
array(
'Content-Type' => 'application/pdf; charset=utf-8',
)
);
}
/**
* #Route("/advancements",name="advancement_list")
* #Template("listAdvancement.html.twig")
*/
public function advancementListAction(Request $request)
{
return $this->listAction('advancement');
}
/**
* #Route("/advancement/new/{id}",name="advancement_create")
* #Template("createAdvancement.html.twig")
*/
public function advancementCreateAction(Request $request, Project $project)
{
$avancement = new Advancement();
$avancement->setProject($project);
$form = $this->createForm(AdvancementType::class, $avancement, array());
return $this->createAction($request, $project, $form, 'advancement');
}
/**
* #Route("/advancement/edit/{id}", name="advancement_edit")
* #Template("createAdvancement.html.twig")
*/
public function advancementEditAction(Request $request, Advancement $advancement)
{
$form = $this->createForm(AdvancementType::class, $advancement, array());
return $this->editAction($request, $advancement->getProject(), $form, 'advancement', $advancement);
}
/**
* #Route("/advancement/delete/{id}", name="advancement_delete")
*/
public function advancementDeleteAction(Request $request, Advancement $advancement)
{
return $this->deleteAction($advancement, 'advancement');
}
/**
* #Route("/alerts",name="alert_list")
* #Template("listAlert.html.twig")
*/
public function alertListAction(Request $request)
{
return $this->listAction('alert');
}
/**
* #Route("/alert/new/{id}",name="alert_create")
* #Template("createAlert.html.twig")
*/
public function alertCreateAction(Request $request, Project $project)
{
$alerte = new Alert();
$alerte->setProject($project);
$form = $this->createForm(AlertType::class, $alerte, array());
return $this->createAction($request, $project, $form, 'alert');
}
/**
* #Route("/alert/edit/{projectid}/{alertid}", name="alert_edit")
* #ParamConverter("project", class="Project", options={"id" = "projectid"})
* #ParamConverter("alert", class="Alert", options={"id" = "alertid"})
* #Template("createAlert.html.twig")
*/
public function alertEditAction(Request $request, Project $project, Alert $alert)
{
$form = $this->createForm(AlertType::class, $alert, array());
return $this->editAction($request, $project, $form, 'alert', $alert);
}
/**
* #Route("/alert/delete/{id}", name="alert_delete")
*/
public function alertDeleteAction(Request $request, Alert $alert)
{
return $this->deleteAction($alert, 'alert');
}
/**
* #Template("_projectLoads.html.twig")
*/
public function projectLoadsAction(Request $request, $projectId)
{
$project = $this->getManager(Project::class)->getProject($projectId);
$slippingCalendar = $this->get('date.handler')->slippingCalendar();
// Returned loads can be outside start-end, so we limit to this year
$validLoads = array();
foreach ($project->getLoads() as $l) {
$id = $l->getUser()->getId();
$year = $l->getYear();
if (!array_key_exists($id, $validLoads)) {
$validLoads[$id] = array('user' => $l->getUser());
}
$validLoads[$id][$year][] = $l;
}
$activities = $this->getActivitiesByMonth($project);
return array(
'project' => $project,
'loads' => $validLoads,
'activities' => $activities,
'slippingCalendar' => $slippingCalendar, // yyyy-11-01, yyyy-12-01, yyyy-01-01,...
);
}
/**
* Build an array with the project activies spread by month and year
* #param Project $project
* #return array
*/
protected function getActivitiesByMonth(Project $project)
{
$validActivities = array();
foreach ($project->getActivities() as $a) {
$id = $a->getUser()->getId();
$date = $a->getMondayDate();
$i = 0;
do {
$year = $date->format('Y');
$month = $date->format('m');
if (!array_key_exists($id, $validActivities)) {
$validActivities[$id] = array('user' => $a->getUser());
}
if (!array_key_exists($year, $validActivities[$id])) {
$validActivities[$id][$year] = array();
}
$validActivities[$id][$year][$month][] = $a->getTimeDay($i);
$date->modify('+1 day');
$i++;
} while ($i < 7);
}
return $validActivities;
}
}
I am looking to see the projects in the database reappear on my web page.
The table is empty, although it should be populated by the projects in the DB.

Decrypt data from database in my Index page with EasyAdminBundle3 and Symfony5

I create a service to encrypt and decrypt my data in my database.
So when I create a new Fiche or update one, I encrypt the name and the surname
Here my subscriber FicheEntitySubscriber :
class FicheEntitySubscriber implements EventSubscriberInterface
{
private $security;
private $encryptionService;
public function __construct(Security $security, EncryptionService $encryptionService)
{
$this->security = $security;
$this->encryptionService = $encryptionService;
}
public static function getSubscribedEvents(): array
{
return [
BeforeEntityPersistedEvent::class => ['setFicheEntity', 10],
BeforeEntityUpdatedEvent::class => ['setFicheEntity', 10]
];
}
/**
* #throws Exception
*/
public function setFicheEntity(AbstractLifecycleEvent $event)
{
$entity = $event->getEntityInstance();
if (!($entity instanceof FicheEntity)) {
return;
}
if ($event instanceof BeforeEntityPersistedEvent) {
$entity->setUtilisateur($this->security->getUser());
}
$entity->setNom($this->encryptionService->encrypt_decrypt('encrypt', mb_strtoupper($entity->getNom())));
$entity->setPrenom($this->encryptionService->encrypt_decrypt('encrypt', mb_strtoupper($entity->getPrenom())));
}
}
Here my FicheController :
class FicheEntityCrudController extends AbstractCrudController
{
private $_adminContextFactory;
private $encryptService;
private $ficheEntityRepo;
public function __construct(AdminContextFactory $adminContextFactory, EncryptionService $encryptionService, FicheEntityRepository $ficheEntityRepo)
{
$this->_adminContextFactory = $adminContextFactory;
$this->encryptService = $encryptionService;
$this->ficheEntityRepo = $ficheEntityRepo;
}
public static function getEntityFqcn(): string
{
return FicheEntity::class;
}
public function configureCrud(Crud $crud): Crud
{
return $crud
->setEntityLabelInPlural('Fiches')
->setEntityLabelInSingular('Fiche informative')
->setSearchFields(['nom', 'prenom', 'nomAntibio'])
->setPaginatorPageSize(10)
->setPaginatorRangeSize(2);
}
public function configureFilters(Filters $filters): Filters
{
return $filters
->add(TextFilter::new('nomAntibio')->setLabel('Nom ATB'))
->add(DateTimeFilter::new('dateDebut')->setLabel('Date Debut'))
->add(DateTimeFilter::new('dateRappel3Jour')->setLabel('Rappel 3e Jour'))
->add(DateTimeFilter::new('dateRappel7Jour')->setLabel('Rappel 7e Jours'));
}
public function configureActions(Actions $actions): Actions
{
$export = Action::new('exportAction', 'Export')
->setIcon('fa fa-download')
->linkToCrudAction('exportAction')
->setCssClass('btn')
->createAsGlobalAction();
return $actions
->add(Crud::PAGE_INDEX, $export);
}
public function exportAction(Request $request): Response
{
$context = $this->_getEasyAdminRefererContext($request);
$searchDto = $this->_adminContextFactory->getSearchDto($request, $context->getCrud());
$fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX));
$filters = $this->get(FilterFactory::class)->create($context->getCrud()->getFiltersConfig(), $fields, $context->getEntity());
$result = $this->createIndexQueryBuilder(
$searchDto, $context->getEntity(), $fields, $filters
)
->getQuery()->getResult();
$data = [];
/**
* #var $record FicheEntity
*/
foreach ($result as $record) {
$data[] = [
'Nom Complet' => $record->getFullname(),
'Chambre' => $record->getChambre(),
'Date Debut' => $record->getDateDebut()->format('y-m-d'),
'Duree ATB' => $record->getDureeJour(),
'Nom ATB' => $record->getNomAntibio(),
'Rappel 3e Jour' => ($record->getDateRappel3Jour() !== null ? $record->getDateRappel3Jour()->format('y-m-d') : $record->getDateRappel3Jour()),
'Réévalué' => ($record->getDateRappel3Jour() !== null ? ($record->getReevalue() === true ? 'oui' : 'non') : ''),
'Rappel 7e Jour' => ($record->getDateRappel7Jour() !== null ? $record->getDateRappel7Jour()->format('y-m-d') : $record->getDateRappel7Jour()),
'Justifié' => ($record->getDateRappel7Jour() !== null ? ($record->getJustifie() === true ? 'oui' : 'non') : ''),
'Pathologie' => $record->getPathologie(),
'Hospitalier' => ($record->getHospitalier() === true ? 'oui' : '')
];
}
$filename = 'export_fiche_' . date_create()->format('d-m-y H:i:s') . '.csv';
$serializer = new Serializer([new ObjectNormalizer()], [new CsvEncoder()]);
$response = new Response($serializer->encode($data, CsvEncoder::FORMAT));
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
$response->headers->set('Content-Disposition', "attachment; filename=\"$filename\"");
return $response;
}
private function _getEasyAdminRefererContext(Request $request)
{
\parse_str(\parse_url($request->query->get(EA::REFERRER))[EA::QUERY], $referrerQuery);
if (array_key_exists(EA::FILTERS, $referrerQuery)) {
$request->query->set(EA::FILTERS, $referrerQuery);
}
return $request->attributes->get(EA::CONTEXT_REQUEST_ATTRIBUTE);
}
public function configureFields(string $pageName): iterable
{
return [
IntegerField::new('id')->hideOnForm()->hideOnIndex(),
TextField::new('nom')->hideOnIndex()->setColumns(6),
TextField::new('prenom')->hideOnIndex()->setColumns(6),
TextField::new('fullname')->setLabel('Nom complet')->hideOnForm(),
IntegerField::new('chambre')->setColumns(4),
TextField::new('nomAntibio')->setLabel('Nom ATB')->setColumns(4),
IntegerField::new('dureeJour')->setLabel('Durée ATB TTT')->setColumns(4),
DateField::new('dateDebut'),
DateField::new('dateRappel3Jour')->setLabel('Rappel 3e Jour')->hideOnForm(),
BooleanField::new('reevalue')->setLabel('Réévalué')->hideOnForm(),
DateField::new('dateRappel7Jour')->setLabel('Rappel 7e Jour')->hideOnForm(),
BooleanField::new('justifie')->setLabel('Justifié')->hideOnForm(),
TextField::new('pathologie'),
AssociationField::new('utilisateur', 'Admin')->setLabel('Utilisateur')->hideOnForm(),
BooleanField::new('hospitalier')
];
}
My issue is that when I display my list of fiches, I want to decrypt the encrypted data, for now I try :
use the AfterEntityBuiltEvent (did not working)
listen on Event postLoad
create an custom action
but none of these are working. Does someone try something similar ?
Thanks in advance

Multi tenant multi DB can't login to sub domain

I have a multi Tenant / multi DB application & each Tenant has it's own Subdomain with Laravel 7.2
When I go to rootdomain.com/super-admin I can login.
When I go to demo.rootdomain.com/login I can login (default database).
When I go to tenant1.rootdomain.com/login I can NOT login.
I'm using Laravels Auth scaffolding.
I have narrowed it down to the ValidatesRequests trait. If I add the email/password manually I can login to tenant1.rootdomain.com/login
So it looks like this:
public function validate(Request $request, array $rules,
array $messages = [], array $customAttributes = [])
{
return [
"email" => "tenant1#rootdomain.com",
"password" => "#Abc123"
];
return $this->getValidationFactory()->make(
$request->all(), $rules, $messages, $customAttributes
)->validate();
}
Here is my TenantProvider to switch connection for each DB
public function register()
{
if($this->app->runningInConsole()){
return;
}
$host = request()->getHttpHost();
$new_host = explode('.', str_replace('www.', '', $host));
//host must contain at least 3
if(count($new_host) == 3 && $new_host[0] != 'dev'){
config(['database.connections.mysql.database' => 'c4_'.$new_host[0].'_app']);
DB::purge('mysql');
DB::reconnect('mysql');
try {
DB::connection()->getPdo();
if(!DB::connection()->getDatabaseName()){
//reset to default
config(['database.connections.mysql.database' => 'c4_app']);
DB::purge('mysql');
DB::reconnect('mysql');
die("Could not find the database OR Subdomain. Please check your configuration.");
}
} catch (\Exception $e) {
//reset to default
config(['database.connections.mysql.database' => 'c4_app']);
DB::purge('mysql');
DB::reconnect('mysql');
die("Could not open connection to database server. Please check your configuration OR subdomain.");
}
}
// dump('DB Connected...ready to go c4_mvp_app ',DB::connection()->getDatabaseName());
}//end function
And my LoginController
namespace App\Http\Controllers\Auth;
use App\Models\GlobalSetting;
use App\Http\Controllers\Front\FrontBaseController;
use App\Models\Social;
use App\Traits\SocialAuthSettings;
use App\Models\User;
use Carbon\Carbon;
use Froiden\Envato\Traits\AppBoot;
use GuzzleHttp\Client;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Laravel\Socialite\Facades\Socialite;
class LoginController extends FrontBaseController
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers, AppBoot, SocialAuthSettings;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/admin/dashboard';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
// dd('Base Login', $this->redirectTo);
parent::__construct();
$this->middleware('guest', ['except' => 'logout']);
}
public function showLoginForm()
{
if (!$this->isLegal()) {
// return redirect('verify-purchase');
}
if ($this->setting->front_design == 1 && $this->setting->login_ui == 1) {
return view('saas.login', $this->data);
}
$this->pageTitle = 'Login Page';
return view('auth.login', $this->data);
}
protected function validateLogin(\Illuminate\Http\Request $request)
{
$setting = GlobalSetting::first();
$rules = [
$this->username() => 'required|string',
'password' => 'required|string'
];
// User type from email/username
$user_email = $request->{$this->username()};
$user = User::where('email', $user_email)->first();
if (!is_null($setting->google_recaptcha_key) && (is_null($user) || ($user && !$user->super_admin))) {
$rules['g-recaptcha-response'] = 'required';
}
if (module_enabled('Subdomain')) {
$rules = $this->rulesValidate($user);
}
$this->validate($request, $rules);
}
public function googleRecaptchaMessage()
{
throw ValidationException::withMessages([
'g-recaptcha-response' => [trans('auth.recaptchaFailed')],
]);
}
public function companyInactiveMessage()
{
throw ValidationException::withMessages([
$this->username() => [trans('auth.companyStatusInactive')],
]);
}
public function validateGoogleRecaptcha($googleRecaptchaResponse)
{
$setting = GlobalSetting::first();
$client = new Client();
$response = $client->post(
'https://www.google.com/recaptcha/api/siteverify',
[
'form_params' =>
[
'secret' => $setting->google_recaptcha_secret,
'response' => $googleRecaptchaResponse,
'remoteip' => $_SERVER['REMOTE_ADDR']
]
]
);
$body = json_decode((string) $response->getBody());
return $body->success;
}
public function login(\Illuminate\Http\Request $request)
{
$setting = GlobalSetting::first();
$this->validateLogin($request);
// User type from email/username
$user = User::where($this->username(), $request->{$this->username()})->first();
// dd('LoginController login 140', $user);
if ($user && !$user->super_admin && $user->company->status == 'inactive' && !$user->hasRole('client')) {
return $this->companyInactiveMessage();
}
// Check google recaptcha if setting is enabled
if (!is_null($setting->google_recaptcha_key) && (is_null($user) || ($user && !$user->super_admin))) {
// Checking is google recaptcha is valid
$gRecaptchaResponseInput = 'g-recaptcha-response';
$gRecaptchaResponse = $request->{$gRecaptchaResponseInput};
$validateRecaptcha = $this->validateGoogleRecaptcha($gRecaptchaResponse);
if (!$validateRecaptcha) {
return $this->googleRecaptchaMessage();
}
}
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (
method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)
) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
protected function credentials(\Illuminate\Http\Request $request)
{
//return $request->only($this->username(), 'password');
// dd('credentials 185',$request->{$this->username()});
return [
'email' => $request->{$this->username()},
'password' => $request->password,
'status' => 'active',
'login' => 'enable'
];
}
protected function redirectTo()
{
$user = auth()->user();
if ($user->super_admin == '1') {
return 'super-admin/dashboard';
} elseif ($user->hasRole('admin')) {
$user->company()->update([
'last_login' => Carbon::now()->format('Y-m-d H:i:s')
]);
return 'admin/dashboard';
}
if ($user->hasRole('employee')) {
return 'member/dashboard';
}
if ($user->hasRole('client')) {
return 'client/dashboard';
}
}
/**
* Log the user out of the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$user = auth()->user();
$this->guard()->logout();
$request->session()->invalidate();
if (module_enabled('Subdomain')) {
if ($user->super_admin == 1) {
return $this->loggedOut($request) ?: redirect(route('front.super-admin-login'));
}
}
return $this->loggedOut($request) ?: redirect('/login');
}
private function rulesValidate($user)
{
if (Str::contains(url()->previous(), 'super-admin-login')) {
$rules = [
$this->username() => [
'required',
'string',
Rule::exists('users', 'email')->where(function ($query) {
$query->where('super_admin', '1');
})
],
'password' => 'required|string',
];
} else {
$company = getCompanyBySubDomain();
$client = false;
$companies = [];
if ($user && User::isClient($user->id)) {
$client = true;
foreach ($user->client as $item) {
$companies[] = $item->company_id;
}
}
$rules = [
$this->username() => [
'required',
'string',
Rule::exists('users', 'email')->where(function ($query) use ($company, $companies, $client) {
if ($client) {
$query->whereIn('company_id', $companies);
} else {
$query->where('company_id', $company->id);
}
})
],
'password' => 'required|string',
];
}
// dd('rulesValidate 281',$rules);
return $rules;
}
public function redirect($provider)
{
$this->setSocailAuthConfigs();
return Socialite::driver($provider)->redirect();
}
public function callback(Request $request, $provider)
{
$this->setSocailAuthConfigs();
$redirectRoute = module_enabled('Subdomain') ? 'front.workspace' : 'login';
try {
if ($provider != 'twitter') {
$data = Socialite::driver($provider)->stateless()->user();
} else {
$data = Socialite::driver($provider)->user();
}
} catch (\Exception $e) {
if ($request->has('error_description') || $request->has('denied')) {
return redirect()->route($redirectRoute)->withErrors([$this->username() => 'The user cancelled ' . $provider . ' login']);
}
throw ValidationException::withMessages([
$this->username() => [$e->getMessage()],
])->status(Response::HTTP_TOO_MANY_REQUESTS);
}
$user = User::where('email', '=', $data->email)->first();
if ($user) {
// User found
\DB::beginTransaction();
Social::updateOrCreate(['user_id' => $user->id], [
'social_id' => $data->id,
'social_service' => $provider,
]);
if ($user->super_admin == 1) {
\Auth::login($user);
return redirect()->intended($this->redirectPath());
}
\DB::commit();
$user->social_token = Str::random(60);
$user->save();
if (module_enabled('Subdomain')) {
return redirect()->to(str_replace(request()->getHost(), $user->company->sub_domain, route('login')) . '?token=' . $user->social_token);
}
\Auth::login($user);
return redirect()->intended($this->redirectPath());
}
if (module_enabled('Subdomain')) {
return redirect()->route($redirectRoute)->withErrors(['sub_domain' => Lang::get('auth.sociaLoginFail')]);
}
throw ValidationException::withMessages([
$this->username() => [Lang::get('auth.sociaLoginFail')],
])->status(Response::HTTP_TOO_MANY_REQUESTS);
}
}
Let me know if you need any other code...thank you!
The code works fine....turns out it was a caching issue.

Laravel return response() not stop the execution

I can't find an explanation of why a return response() inside a catch is not stopping the execution, i guess im missing something.
In this example the request have an error so the try-catch on the service receive ValidationException. This goes to ValidationErrorResponder and here is where the execution should finish and return a json with the errors. But it continues and return the json error response through $this->updateUserResponder->respond()
I have a defined route which execute the __invoke() method on UpdateUserAction
class UpdateUserAction
{
protected $updateUserService;
protected $updateUserResponder;
public function __construct(UpdateUserService $updateUserService, UpdateUserResponder $updateUserResponder)
{
$this->updateUserService = $updateUserService;
$this->updateUserResponder = $updateUserResponder;
}
public function __invoke(Request $request, $userId)
{
$serviceData = [
'id' => $userId,
'commandPayload' => $request->only('name')
];
return $this->updateUserResponder->respond($this->updateUserService->execute($serviceData));
}
}
class UpdateUserService extends BaseService
{
public function execute(array $data = [])
{
try {
$this->bus->addHandler(UpdateUserCommand::class, UpdateUserHandler::class);
return $this->bus->dispatch(UpdateUserCommand::class, $data, [UpdateUserValidator::class]);
} catch (ValidationException $e) {
return $this->validationErrorResponder->respond($e);
}
}
}
class UpdateUserValidator implements Middleware
{
protected $rules = [
'id' => 'uuid',
'commandPayload.name' => 'max:256'
];
protected $messages = [];
public function execute($command, callable $next)
{
$validator = Validator::make((array) $command, $this->rules, $this->messages);
if ($validator->fails()) {
throw new ValidationException($validator);
}
return $next($command);
}
}
This shoudl return the final response wiht the errors in a JSON but
class ValidationErrorResponder
{
public function respond($validator)
{
$messages = $validator->getValidator()->getMessageBag()->messages();
return response()->json(['errors' => $messages], 422);
}
}
Maybe the error it's another and the catch does not working because only are catching ValidationException.
So try catching all exception to see what happens:
class UpdateUserService extends BaseService
{
public function execute(array $data = [])
{
try {
$this->bus->addHandler(UpdateUserCommand::class, UpdateUserHandler::class);
return $this->bus->dispatch(UpdateUserCommand::class, $data, [UpdateUserValidator::class]);
} catch (\Exception $e) {
return $this->validationErrorResponder->respond($e);
}
}
}

Laravel Policy (Too few arguments to function App\Policy)

I am trying to setup my policy for users. However I keep on getting an error of:
Too few arguments to function App\Policies\UserPolicy::update(), 1 passed in /vendor/laravel/framework/src/Illuminate/Auth/Access/Gate.php on line 481 and exactly 2 expected (View: /resources/views/users/index.blade.php)
ErrorException /app/Policies/UserPolicy.php 20
which is on the UserPolicy#update function
When I am logged in as super_admin, it works fine but it throws this error whenever I am logged in as a user of different role.
Below is my current implementation:
UserPolicy
class UserPolicy
{
use HandlesAuthorization;
public function update(User $user, User $userEdit) {
if ($user->id == $userEdit->id) {
return true;
}
return $user->can('update_user');
}
public function before($user, $ability) {
if ($user->hasRole('super_admin')) {
return true;
}
}
}
UsersController
class UsersController extends Controller {
public function __construct() {
$this->middleware('auth');
}
public function edit(User $user) {
$this->authorize('update', $user);
return view('users.edit', [
'user' => User::with('roles', 'level')->find($user->id),
'surveys' => \App\Survey::all(),
]);
}
public function update(UserRequest $request, User $user) {
$this->authorize('update', $user);
$request->save();
session()->flash('success', 'User successfully updated');
// means user is editing his own profile
if (auth()->id() == $user->id) {
return redirect('/dashboard');
} else {
return redirect('/users');
}
}
}
UserRequest
class UserRequest extends FormRequest {
public function authorize() {
return true;
}
public function rules() {
switch ($this->method()) {
case 'POST':
return [
'name' => 'required|string',
'email' => 'required|string|email|max:255|unique:users',
'role' => 'required|exists:roles,id',
'level' => 'required|string',
];
break;
case 'PATCH':
return [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users,email,'.$this->user->id,
'role' => 'sometimes|exists:roles,id',
'level' => 'sometimes|string',
'password' => 'nullable|sometimes|string|min:6|confirmed'
];
break;
default:
break;
}
}
public function save() {
switch (request()->method()) {
case 'POST':
$this->createUser();
break;
case 'PATCH':
$this->updateUser();
break;
default:
break;
}
}
protected function createUser() {
// random generate password
$password = str_random(8);
$user = User::create([
'name' => request('name'),
'email' => request('email'),
'level_id' => request('level'),
'password' => Hash::make($password),
]);
$user->assignRoleById(request('role'));
Mail::to($user)->send(new WelcomeMail($user, $password));
}
protected function updateUser() {
$user = User::findOrFail($this->user->id);
$user->name = request('name');
$user->email = request('email');
if (request('password') != '') {
$user->password = Hash::make(request('password'));
}
if (request('level') != '') {
$user->level_id = request('level');
}
$user->update();
if (request('role') != '') {
$user->roles()->sync([request('role')]);
}
}
}
AuthServiceProvider
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
\App\User::class => \App\Policies\UserPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
foreach ($this->getPermissions() as $permission) {
Gate::define($permission->name, function($user) use ($permission) {
return $user->hasRole($permission->roles);
});
}
}
protected function getPermissions() {
return Permission::with('roles')->get();
}
}
In my views file I'm calling
#can('update', App\User::class)
<!-- html code --!>
#endcan
instead of
#can('update', $user)
<!-- html code --!>
#endcan
I was not passing the user instance into the function which was causing the error.
In UserRequest you haven't given any parameters when you call $user->update();. The update() function requires for a UserRequest instance, as well as a User.
Give this a try: $user->update(request()->all(), $user)
Edit:
I would just move the following...
$this->authorize('update', $user);
$request->save();
session()->flash('success', 'User successfully updated');
// means user is editing his own profile
if (auth()->id() == $user->id) {
return redirect('/dashboard');
} else {
return redirect('/users');
}
...to the updateUser() function.

Categories