Laravel model with custom generated id - laravel

In my Demande model, for the ID I have not used the default incremental id, not even the ulid. I have customized the generation of the id. But the issue is that when you call it in route, that id is not recognized and the item cannot be found.
The snippet of my model is :
class Demande extends Model
{
protected static function boot()
{
parent::boot();
static::creating(function (Demande $demande) {
$demande->id = self::generateCode($demande->matricule);
});
}
}
Where the generateCode() function is :
public static function generateCode(string $matricule): string
{
// {$this->matricule}-{increment} for example: 2021020061-01
// make sure the code is unique
$count = self::where('matricule', $matricule)->count() + 1;
return $matricule . Str::padLeft($count, 2, '0');
}
With the snippet of the route call :
Route::resource('demandes', DemandeController::class);
In DemandeController, if i do this in the show function :
public function show(Demande $demande)
{
$title = $demande->code;
$etudiant = $demande->etudiant;
....
return view('admin.demandes.show', compact('demande', 'title', 'etudiant'));
}
This throws an error that $demande object is not found. And I am oblidged to change into :
public function show($demande)
{
$demande = Demande::find($demande);
$title = $demande->code;
$etudiant = $demande->etudiant;
....
return view('admin.demandes.show', compact('demande', 'title', 'etudiant'));
}
where I get that $demande param as ID and manually do the find.
Is there a setting inside Demande model or anywhere that needs to be set so that the custom generated id be recognized ?

Related

Laravel - Instantiate object and keep it within all controller's methods

I'm working with this case where I need to instantiate an object after a form is submitted in a controller. Everything's working fine until I call this object (as a property) from another method. It appears to be null.
If I intentiate the object from constructor method, I have no problem at all.
I can't keep this object in session because of closure.
Here's what i got so far.
// Version with the object iniate within the constructor that's working
class SearchConsoleController extends Controller
{
private $console;
protected function __construct() {
$callback = route('searchconsole.callback') ;
$this->console = $this->setConsole(env('CLIENT_ID'), env('CLIENT_SECRET'), $callback);
}
private function setConsole($cliendId, $cliendSecret, $callback){
$console = new Console(new Google_Client(), $cliendId, $cliendSecret, $callback);
return $console;
}
public function index(Request $request) {
return view('searchconsole.index')->with('authUrl', $this->console->getAuthUrl());
}
public function callback(Request $request){
if ($request->has('code')) {
$this->console->acceptCode($request->get('code'));
return redirect()->action('SearchConsoleController#listSites', [$request]);
}
else{
die('error');
}
}
Now the version which i'm stucked wih
class SearchConsoleController extends Controller
{
private $console;
private $callback;
protected function __construct() {
$this->callback = route('searchconsole.callback') ;
}
private function setConsole($cliendId, $cliendSecret, $callback){
$console = new Console(new Google_Client(), $cliendId, $cliendSecret, $this->callback);
return $console;
}
public function index(Request $request) {
// VIEW WITH A FORM FROM WHICH I GET CLIENT_SECRET & CLIENT_ID var
return view('searchconsole.index');
}
public function getAuthUrl(Request $request) {
// FORM FROM INDEX IS SUBMITTED
$clientId = ($request->has('google-client-id')) ?
$request->get('google-client-id') :
null
;
$clientSecret = ($request->has('google-client-secret')) ?
$request->get('google-client-secret') :
null
;
$this->console = $this->setConsole($clientId, $clientSecret, $this->callback);
return $this->console->getAuthUrl();
}
public function callback(Request $request){
if ($request->has('code')) {
// ***** MY PROBLEM *********
$this->console->acceptCode($request->get('code')); // HERE $this->console IS NULL;
// *******************
return redirect()->action('SearchConsoleController#listSites', [$request]);
}
else{
die('error');
}
}
I just can't figure out how I can do this so console is still available
UPDATE :
following #iamab.in advice, i looked into Service Provider but i just dont know how i can instante the Console Object within the service provider.
Here's what i've done.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Helpers\Console;
use Google_Client;
use Illuminate\Support\Facades\Route;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(Console::class, function() {
$request = app(\Illuminate\Http\Request::class);
$clientId = ($request->has('google-client-id')) ?
$request->get('google-client-id') :
null
;
$clientSecret = ($request->has('google-client-secret')) ?
$request->get('google-client-secret') :
null
;
$callback = Route::get()->name('searchconsole.callback');
return new Console(new Google_Client(), $clientId, $clientSecret, $callback);
});
}
public function boot(){}
....
I just dont know how and where to implement it.
Thanks again
Update#2 :
okay my solution was working, I just didnt launch the correct app ..... 😅

How to change image directory in spatie media library?

I'm new to this package since I usually use the image intervention. So the problem is whenever I save an image, it is saving in storage directory instead of in public directory. I tried to review the documentation and did some research and didn't see any answer. Please see my code below for saving.
$user->addMediaFromRequest('avatar')->toMediaCollection('avatars');
Package:
https://spatie.be/docs/laravel-medialibrary/v7/introduction
you can simply define the filesystem config with $user->addMediaFromRequest('avatar')->toMediaCollection('avatars', 'disk');
here is how im using the package(simple usage), if you need it later
on my model:
use Spatie\MediaLibrary\HasMedia\HasMedia;
use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Spatie\MediaLibrary\Models\Media;
class User extends Model implements HasMedia
{
use HasMediaTrait;
public function registerMediaCollections()
{
$this
->addMediaCollection('avatar')
->singleFile()
->useDisk('public');
->useFallbackUrl(asset('/images/default-user.png'))
->useFallbackPath(public_path('/images/default-user.png'));
}
public function registerMediaConversions(Media $media = null)
{
$this->addMediaConversion('avatar-thumb')->width(120)->height(120);
}
...
to get the file-url im using model accessor, added this function in my model:
public function getAvatarAttribute()
{
$file = $this->getMedia('avatar')->first();
if($file) {
$file->url = $file->getUrl();
$file->thumbnail = $file->getUrl('avatar-thumb'));
$file->alternate = $file->getCustomProperty('alternate') ?: $file->file_name;
}else{
$file = new \StdClass;
$file->url = $this->getFallbackMediaUrl('avatar');
$file->thumbnail = public_path('/images/default-user-thumb.png');
$file->alternate = 'avatar.png';
}
return $file;
}
also using custom path, in config\medialibrary.php set this array 'path_generator' => Path\To\Your\Class::class,
then the class :
use Spatie\MediaLibrary\Models\Media;
use Spatie\MediaLibrary\PathGenerator\PathGenerator as PathGenerators;
class PathGenerator implements PathGenerators
{
public function getPath(Media $media): string
{
return $this->getBasePath($media).'/';
}
public function getPathForConversions(Media $media): string
{
return $this->getBasePath($media).'/conversions/';
}
public function getPathForResponsiveImages(Media $media): string
{
return $this->getBasePath($media).'/responsive-images/';
}
protected function getBasePath(Media $media): string
{
//here im using trait to generate default path, e.g: path/mimes/avatar/media->id
//its up to you to define folder structure, just make sure each folder
//for conversions has unique name, or else it will be deleted
$base_folder = $this->get_base_folder($media->mime_type);
return "{$base_folder}/{$media->collection_name}/{$media->getKey()}";
}
}

Passing shared variable after login with Laravel 5.5

i created a method in order to share datas with all views of my application.
For this i created a class EntityRepository where i store the datas I want to share with all views.
Those data are displayed in the layout NOT the view.
class EntityRepository
{
use App\Valuechain;
public function getEntities()
{
$vcs = Valuechain::select('valuechains.id', 'lang_valuechain.vcname', 'lang_valuechain.vcshortname')
->join('lang_valuechain', 'valuechains.id', '=', 'lang_valuechain.valuechain_id')
->join('langs', 'lang_valuechain.lang_id', '=', 'langs.id')
->where('langs.isMainlanguage', '=', '1')
->whereNull('valuechains.deleted_at')
->get();
return $vcs;
}
}
When I want to send datas to the methods I simply call the getEntities() method... For example :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
// My code here ...
return view('admin.pages.maps.sectors.index', compact('entitiesLists', 'myVars'));
}
In this specific case it works fine and i don't have issue. My issue concerns the landing page after login.
In the loginController :
I defined the redirectTo variable this way :
public $redirectTo = '/admin/home';
For specific reasons I had to override the authentificated() method in the LoginController in order to check if my app is configured or need to be setup ...
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
//return redirect()->to('admin/home');
return redirect()->action('BackOffice\StatsController#index');
}
}
The concerned index() method is sending the variable onto the view :
public function index(EntityRepository $vcs)
{
$entitiesLists = $vcs->getEntities();
return view('admin.home', compact('entitiesLists'));
}
Whatever the return i make i have error message...
Undefined variable: entitiesLists (View: C:\wamp64\www\network-dev\resources\views\admin\partials\header-hor-menu.blade.php)
I finally solved this issue by changing my routes :
Route::group(['prefix' => 'admin'], function () {
Route::get('/', function (){
$checkAuth = Auth::guard('admin')->user();
if ($checkAuth) {
return redirect('/admin/main');
}
else {
return redirect('admin/login');
}
});
});
In my loginController i changed :
public $redirectTo = '/admin/home';
to :
public $redirectTo = '/admin/main';
Finally :
protected function authenticated(Request $request, $user)
{
$langCount = Lang::count();
if ($langCount == 0) {
return redirect()->to('admin/setup/lang');
}
else {
return redirect()->to('admin/main');
}
}

Laravel one-to-many save Carbon error

I have a class called SubjectData:
class SubjectData extends Model
{
protected $table = 'subject_datas';
protected $fillable = ['firstname','lastname','birthdate','birthcity','months'];
protected $dates = ['birthdate'];
public function setBirthdateAttribute($date)
{
// So we can add the time, not just he php date
$this->attributes['birthdate'] = Carbon::createFromFormat('d/m/Y', $date);
}
public function anamnesis() {
return $this->belongsTo('App\Anamnesis');
}
}
And I have a class called Anamnesis:
class Anamnesis extends Model
{
public function meetingTest() {
return $this->belongsTo('App\MeetingTest');
}
public function subject() {
return $this->belongsTo('App\Subject','subject_id','id');
}
public function subjectData() {
return $this->hasOne('App\SubjectData');
}
public function scholarHistory() {
return $this->hasOne('App\ScholarHistory');
}
public function familyHistory() {
return $this->hasOne('App\FamilyHistory');
}
public function psicodiagnosis() {
return $this->hasOne('App\Psicodiagnosis');
}
}
The store function of the SubjectController class works like this:
public function store(CreateSubjectRequest $request)
{
$input = $request->all();
// Let's generate the anamnesis of the subject
$anamnesis = Anamnesis::create();
$anamnesis->save();
$newSubjectData = $this->saveSubjectData($input);
$anamnesis->subjectData()->save($newSubjectData);
......
......
}
where the function called is:
public function saveSubjectData($input)
{
$subjectData['firstname'] = $input['firstname'];
$subjectData['lastname'] = $input['lastname'];
$subjectData['birthcity'] = $input['birthcity'];
$subjectData['birthdate'] = $input['birthdate'];
return SubjectData::create($subjectData);
}
The problem is with the "birthdate" property.
If i check the value of $newSubjectData (dd($newSubjectdata)) after the call $this->saveSubjectData($input) the value of the birthdate is exactly the one i set on the calendar in the frontside (and also in the db the value is correct)
If I put the dd($anamnesis->subjectData) after the call $anamnesis->subjectData()->save($newSubjectData) the result is the "today" date and also in the DB the value is not the one I set but the date of today.
I can't find the error
P.S. The calendar is inside a Vue template
I think the problem is that, the date must be an instance of Carbon or is properly formatted according to your database table. Try the following inside your saveSubjectData() method
$subjectData['birthdate'] = Carbon\Carbon::parse($input['birthdate']
I write down the answer but i thank John Aldrin that guided me in the right direction.
You have to put the timestamp('birthdate') AFTER the default timestamps of the migration table (so at the end of the migration table)
I don't know why. If someone knows please explain !

Datamapper in Code Igniter deals with a relationship as many to many

I have a very confusing problem..
I configured data mapper and started to use it with code igniter.. I have this class:
class FamilyMemberDetail extends DataMapper {
var $table = "family_members_details";
var $has_one = array('gender', 'maritalstate');
public function __toString() {
return is_string($this->id) ? $this->id : "";
}
}
For gender it is working fine..
class Gender extends DataMapper {
var $table = "genders";
var $has_many = array("familymemberdetail");
public function __toString() {
return is_string($this->gender_label) ? $this->gender_label : "";
}
}
But with marital status:
class MaritalState extends DataMapper {
var $table = "marital_state";
var $has_many = array("familymemberdetail");
public function __toString() {
return is_string($this->marital_state_label) ? $this->marital_state_label : "";
}
}
I get this error!
Error Number: 1146
Table 'elkhoudary_family.kh_family_members_details_marital_state' doesn't exist
SELECT `kh_marital_state`.* FROM (`kh_marital_state`) LEFT OUTER JOIN `kh_family_members_details_marital_state` kh_family_members_details_marital_state ON `kh_marital_state`.`id` = `kh_family_members_details_marital_state`.`maritalstate_id` WHERE `kh_family_members_details_marital_state`.`familymemberdetail_id` = 1
Filename: C:\AppServ\www\elkhoudary\system\database\DB_driver.php
Line Number: 330
The problem is that I didn't specify this relationship to need a join table and yet.. CI insists that it needs a table in between.. isn't it supposed to work like gender.. what am I missing here?
Ok I found out why and it is really stupid.. the relation column should be named [className]_id not [tableName]_id and since I have my class named "MaritalState" and my table name "marital_state".
So I changed all entities to '_'s instead of Camel cases and everything went fine..
class Family_member_detail extends DataMapper {
var $table = "family_members_details";
var $has_one = array('gender', 'marital_state');
public function __toString() {
return is_string($this->id) ? $this->id : "";
}
}
Gender:
class Gender extends DataMapper {
var $table = "genders";
var $has_many = array("family_member_detail");
public function __toString() {
return is_string($this->gender_label) ? $this->gender_label : "";
}
}
Marital State:
class Marital_state extends DataMapper {
var $table = "marital_state";
var $has_many = array("family_member_detail");
public function __toString() {
return is_string($this->marital_state_label) ? $this->marital_state_label : "";
}
}

Resources