I have a php laravel projekt where I need to add a field to one/more models (Eloquent). I don't have much experience in php and never tried laravel before.
The class looks like this now
class Player extends Eloquent
{
use GenderTrait;
use VisibilityTrait;
use PlayerPhotoTrait;
use PlayerActionTrait;
const GENDER_MALE = 2;
const GENDER_FEMALE = 1;
/**
* The database table used by model.
*
* #var string
*/
protected $table = 'players';
/**
* Parameters for `actions` relation.
*
* #see PlayerActionTrait::actions()
* #var array
*/
protected $actionModel = [
'name' => 'PlayerAction',
'foreignKey' => 'player_id',
];
/**
* The list of mass-assignable attributes.
*
* #var array
*/
protected $fillable = [
'name',
'start_value',
'gender',
'is_visible',
'nation',
];
/**
* The list of validation rules.
*
* #var array
*/
public static $rules = [
'name' => 'required',
'nation' => 'required|numeric',
'start_value' => 'required|numeric',
];
/**
* #inheritdoc
*/
protected static function boot()
{
parent::boot();
}
/**
* Players country.
*
* #return Country
*/
public function country()
{
return $this->belongsTo('Country', 'nation');
}
/**
* Player videos.
*
* #return mixed
*/
public function videos()
{
return $this->morphMany('YoutubeLink', 'owner');
}
}
I would like to add a string field called "level" but I have no idea how to go about it. If I create the field in MySQL first and then the models get updated, if I update the models and then Laravel update MySQL for me?
Im looking forward to hearing what I can do :)
You need to add migration:
php artisan make:migration add_fields_to_players_table --table=players
Open in /database/migrations new migration and write
Schema::table('players', function ($table) {
$table->string('new_string_field');
});
Now you need to run migrations
php artisan migrate
More info and available column types here
Related
I'm creating a user management in Laravel using Backpack package, the main functionallity works well, I mean, you can create new users and then log in with them and deleteor edit them. But there is an aspect that dosent works as I want it. The problem is that when you edit it you must insert a password too to save the edits, this is not correct because you can not modify the password. To solve this, following the BackPack documentation I separate the UserRequest, so now I have two: UserRequest & EditUserRequest.
Nevertheless, the form still mark as required the password field, it seems that it pass trhough the setupCreateOperation function even if I click on edit the user.
I upload some images with the code and what appears me in the screen:
UserCrudController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Requests\UserRequest;
use App\Http\Requests\EditUserRequest;
use Illuminate\Support\Facades\Hash;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;
/**
* Class UserCrudController
* #package App\Http\Controllers\Admin
* #property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
*/
class UserCrudController extends CrudController
{
use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
/**
* Configure the CrudPanel object. Apply settings to all operations.
*
* #return void
*/
public function setup()
{
CRUD::setModel(\App\Models\User::class);
CRUD::setRoute(config('backpack.base.route_prefix') . '/user');
CRUD::setEntityNameStrings('user', 'users');
}
/**
* Define what happens when the List operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-list-entries
* #return void
*/
protected function setupListOperation()
{
CRUD::column('name');
CRUD::column('email');
CRUD::column('password');
/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
}
/**
* Define what happens when the Create operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-create
* #return void
*/
protected function setupCreateOperation()
{
CRUD::setValidation(UserRequest::class);
//dd('setupCreateOperation');
CRUD::field('name');
CRUD::field('email');
CRUD::field('password');
/**
* Fields can be defined using the fluent syntax or array syntax:
* - CRUD::field('price')->type('number');
* - CRUD::addField(['name' => 'price', 'type' => 'number']));
*/
}
/**
* Define what happens when the Update operation is loaded.
*
* #see https://backpackforlaravel.com/docs/crud-operation-update
* #return void
*/
protected function setupUpdateOperation()
{
//dd('setupUpdateOperation');
$this->crud->setValidation(EditUserRequest::class);
$this->crud->setRequest($this->handlePasswordInput($this->crud->getRequest()));
$this->crud->unsetValidation(); // validation has already been run
$this->setupCreateOperation();
}
/**
* Handle password input fields.
*/
protected function handlePasswordInput($request)
{
// Encrypt password if specified.
if ($request->input('password')) {
//dd($request->input('password'));
$request->request->set('password', Hash::make($request->input('password')));
} else {
//si no lo mete el usuario que no lo tenga en cuenta
$request->request->remove('password');
}
return $request;
}
}
UserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['required', 'string', 'min:8'], // This is the diference
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
EditUserRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class EditUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
// only allow updates if the user is logged in
return backpack_auth()->check();
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => ['required','min:5','max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => ['nullable', 'string', 'min:8'], // this is the difference
];
}
/**
* Get the validation attributes that apply to the request.
*
* #return array
*/
public function attributes()
{
return [
//
];
}
/**
* Get the validation messages that apply to the request.
*
* #return array
*/
public function messages()
{
return [
//
];
}
}
If you call setupCreateOperation() at the end of your setupUpdateOperation() then the CreateRequest will override the UpdateRequest. What you can do instead is do that first:
protected function setupUpdateOperation()
{
$this->setupCreateOperation();
$this->crud->setValidation(EditUserRequest::class);
}
I am new with Laravel and of course also with backpack.
I am using laravel 7.x and backpack 4.1 with both MySql and MongoDb.
The situation I am facing is that I have a company model with some attributes which are in MySql (both save and update working great with for the attributes stored in MySql) and other attributes that should be stored in MongoDb.
I have a CompanyPropertyCollection model for the attributes which I want to be stored in MongoDb
All these company will have a variable number of other arbitrary properties, which I want to save in mongo.
These properties may be simple scalar values or more complex values too (think arrays of objects), hence the idea to save them in mongo.
MySql Company table:
My question is the following:
What is the best practice to save attributes of an entity in two distinct databases from BackPack? I override the CreateOperation, UpdateOperation with the store() and update() functions something like this:
Company model:
class Company extends Model
{
use \Backpack\CRUD\app\Models\Traits\CrudTrait;
use SoftDeletes;
use HybridRelations;
protected $connection = 'mysql';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'company_type',
'is_active',
'package_id',
'certification_id',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'is_active' => 'boolean',
'package_id' => 'integer',
'certification_id' => 'integer',
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function users()
{
return $this->belongsToMany(\App\Models\User::class);
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function package()
{
return $this->belongsTo(\App\Models\Package::class);
}
public function certification()
{
return $this->hasMany(\App\Models\Certification::class);
}
public function properties()
{
return $this->hasOne(\App\Models\CompanyPropertyCollection::class);
}
}
CompanyPropertyCollection model:
class CompanyPropertyCollection extends Model
{
use SoftDeletes;
protected $connection = 'mongodb';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
//'company_id',
'email',
'big_news_id',
'phone.number',
'phone.country_prefix',
'phone.area_prefix',
'phone.postfix',
'year_of_foundation',
'nr_of_employees',
'nr_of_branches',
'company_size',
'subtitle',
'homepage',
'country_code',
'city',
'street',
'post_code',
'uid_nr',
'registration_nr',
'total_sales_area',
'total_annual_bisuness_volume',
'short_portrait',
'long_portrait',
'embedded_video',
'certificates',
'gallery',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'gallery' => 'array',
];
public function company()
{
return $this->belongsTo(\App\Models\Company::class);
}
}
CompanyCrudController :
public function update()
{
//$this->update( $company->properties);
$response = $this->traitUpdate();
// do something after save
//use registered observer
return $response;
}
Currently I am trying to use a CompanyObserver and on saving to store the data for mongo from the Request.
class CompanyObserver {
public function saving(Company $company)
{
//dd(request()->request);
$request = request()->request;
dd($company->properties());
//save to MongoDb
dd('saving methond on the observer');
}
}
If you need to perform some action after saving a model, like saving some user data in another db with a different type. You can override the model's save method.
Inside your model, add a method like the below
public function save(array $options = array())
{
if (parent::save($options)) {
// Model has been saved in mysql, now save in mongoDB
}
}
I'm experiencing my first Laravel project and I implemented a resource collection API, where I fetch data via passport. Data seems to be retrieved correctly from model, except for relations. Here's the situation:
item.php (Model)
<?php
// Definizione Namespace
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Classe Item
*/
class Item extends Model
{
use SoftDeletes;
// Dichiarazione ProprietĂ
protected $table = 'item';
protected $dateformat = 'Y-m-d';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'data_acquisto',
'labeled',
'estensione_garanzia',
'stato',
'data_dismissione',
'note'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'codice',
'serial',
'componente_id',
'tipologia_id',
'condizione_id',
'locazione_id',
'fornitore_id',
'parent_id'
];
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = [
'data_acquisto',
'data_dismissione',
'deleted_at'
];
/**
* All of the relationships to be touched.
*
* #var array
*/
protected $touches = [
'componenti',
'condizioni',
'fornitori',
'locazioni',
'tipologie'
];
/**
* Scope query item figli
* Getter
* #param array $query Query
* #return array Query
*/
public function scopeFigli($query)
{
return $query->where('parent_id', '!=', null);
}
/**
* Componenti Correlati
* Getter
* #return object Componenti
*/
public function componenti()
{
// Definizione relazione
return $this->belongsTo('App\Componente');
}
/**
* Condizioni Correlate
* Getter
* #return object Condizioni
*/
public function condizioni()
{
// Definizione relazione
return $this->belongsTo('App\Condizione');
}
/**
* Fornitori Correlati
* Getter
* #return object Fornitori
*/
public function fornitori()
{
// Definizione relazione
return $this->belongsTo('App\Fornitore');
}
/**
* Locazioni Correlate
* Getter
* #return object Locazioni
*/
public function locazioni()
{
// Definizione relazione
return $this->belongsTo('App\Locazione');
}
/**
* Tipologie Correlate
* Getter
* #return object Tipologie
*/
public function tipologie()
{
// Definizione relazione
return $this->belongsTo('App\Tipologia');
}
}
item.php (Resource)
<?php
// Definizione Namespace
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources\Componente as ComponenteResource;
use App\Http\Resources\Condizione as CondizioneResource;
use App\Http\Resources\Fornitore as FornitoreResource;
use App\Http\Resources\Locazione as LocazioneResource;
use App\Http\Resources\Tipologia as TipologiaResource;
class Item extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
parent::toArray($request);
return [
'id' => $this->id,
'codice' => $this->codice,
'data_acquisto' => $this->data_acqisto,
'serial' => $this->serial,
'labeled' => $this->labeled,
'estensione_garanzia' => $this->estensione_garanzia,
'stato' => $this->stato,
'data_dismissione' => $this->data_dismissione,
'note' => $this->note,
'parent_id' => $this->parent_id,
// Includi associazioni se caricate
'componenti' => ComponenteResource::collection($this->whenLoaded('componenti')),
'condizioni' => CondizioneResource::collection($this->whenLoaded('condizioni')),
'fornitori' => FornitoreResource::collection($this->whenLoaded('fornitori')),
'locazioni' => LocazioneResource::collection($this->whenLoaded('locazioni')),
'tipologie' => TipologiaResource::collection($this->whenLoaded('tipologie'))
];
}
}
This is the screen about an example of data fetched:
As showed above there's no trace of relations. By googling around and changing code as suggested like this:
// Resoruce - Straight including relations instead of lazy load
[...]
'componenti' => ComponenteResource::collection($this->componenti),
[...]
or by expliciting the foreign key in model:
/**
* Componenti Correlati
* Getter
* #return object Componenti
*/
public function componenti()
{
// Definizione relazione
return $this->belongsTo('App\Componente', 'componente_id');
}
I'm still not retrieving relations.
Could anyone give me a little help/tip to solve this problem?
Thanks in advance for help.
The code below will only show Tipologie when it is explicitly loaded to avoid N+1 query problems.
'tipologie' => TipologiaResource::collection($this->whenLoaded('tipologia'))
To load Tipologie for Resource to show it, you need to explicitly load it as:
$itemResource = new ItemResource($item->load('tipologia', ... other relationships...);
See Eager Loading for more information about this.
Edit
Sorry for not understanding the type of relationship, just like #luca-cattide said, collection should not be used for belongsTo, and the correct one is to use:
TipologiaResource::make($this->tipologia);
Or also:
new TipologiaResource($this->topologia);
But I advise you to use "load" method to load the information before, otherwise you perform a search in the database for "item", another by "typologie" and so on until loading all your relationships.
There's another way you load information without having to load the item, see below:
new ItemResource(App\Item::find(1)->with(['tipologie', ... other relationships ... ])->get());
See more about N+1 query problems here.
Thanks #vinicius, but googling around a bit more, as suggested from this post by #CamiloManrique, I noticed that in these relations, I'm trying to fetch data from belongs_to side (so actually from Item and not from Componente, Tipologia and so on). As is ::collection simply doesn't work except if called by hasMany relation side
So, instead using ::collection in conjunction with whenLoaded I refactored like this:
// Includi associazioni se caricate
'componente' => ComponenteResource::make($this->componente),
'condizione' => CondizioneResource::make($this->condizione),
'fornitore' => FornitoreResource::make($this->fornitore),
'locazione' => LocazioneResource::make($this->locazione),
'tipologia' => TipologiaResource::make($this->tipologia)
In this way data being fetched with no error.
Thanks again for your tips.
I'm trying to create a link in between 2 objects using NeoEloquent. Unfortunately i get the following error.
Class 'Permission' not found
I tried pretty much everything but i can't get it to work unfortunately.
I submit the permission objects I want to link to as an integer representing the id of the label.
The relationship between the labels is a Many to Many relation. As far as i can see i've done everything correctly. I've checked with the GitHub page, it looks good to me.
Thanks in advance!
Controller method:
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param Role $role
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Role $role)
{
//dd($request);
$this->validate($request, [
'title' => 'required',
]);
foreach($request['permission'] as $perm){
$role->permissions()->attach($perm);
}
$role->title = request('title');
$role->save();
return redirect("/roles");
}
Role Model:
<?php
namespace App;
use Vinelab\NeoEloquent\Eloquent\Model as NeoEloquent;
class Role extends NeoEloquent
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'title',
];
protected $label = "Role";
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
public function permissions(){
return $this->hasMany('Permission', 'Has_Permission');
}
}
Permission Model:
<?php
namespace App;
use Vinelab\NeoEloquent\Eloquent\Model as NeoEloquent;
class Permission extends NeoEloquent
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'title',
];
protected $label = "Permission";
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
}
I am having trouble saving(creating new row) with extra data to a pivot table.
I am having to use a legacy db schema (that is still working on a live site). I am currently redoing the site in Laravel.
<?php namespace Carepilot\Repositories\Organizations;
use Carepilot\Repositories\EloquentRepositoryAbstract;
/*
* This class is the Eloquent Implementation of the Organization Repository
*/
class OrganizationRepositoryEloquent extends EloquentRepositoryAbstract implements OrganizationRepositoryInterface {
/*
* Define Eloquent Organization Type Relation.
*
*/
public function orgtypes()
{
return $this->belongsToMany('Carepilot\Repositories\OrganizationTypes\OrganizationTypesRepositoryEloquent', 'organizations_orgtypes', 'organization_id', 'orgtype_id')
->withPivot('objectstate_id');
}
}
<?php namespace Carepilot\Repositories\OrganizationTypes;
use Carepilot\Repositories\EloquentRepositoryAbstract;
/*
* This class is the Eloquent Implementation of the Organization Repository
*/
class OrganizationTypesRepositoryEloquent extends EloquentRepositoryAbstract implements OrganizationTypesRepositoryInterface {
protected $table = 'orgtypes';
/*
* Define Eloquent Organization Type Relation.
*
*/
public function organizations()
{
return $this->belongsToMany('Carepilot\Repositories\Organizations\OrganizationRepositoryEloquent', 'organizations_orgtypes', 'organization_id', 'orgtype_id')
->withPivot('objectstate_id');
}
}
Here in the Orgaizations controller I try to save a new organization but get an error in the pivot table.
<?php
use \Carepilot\Repositories\Organizations\OrganizationRepositoryInterface;
use \Carepilot\Repositories\Procedures\ProcedureRepositoryInterface;
use \Carepilot\Helpers\StatesHelper;
class OrganizationsController extends BaseController {
/**
* Organization Repository
*
* #var organization_repo
*/
protected $organization_repo;
protected $procedures;
protected $states;
public function __construct(OrganizationRepositoryInterface $organization_repo,
ProcedureRepositoryInterface $procedures,
StatesHelper $states)
{
$this->organization_repo = $organization_repo;
$this->procedures = $procedures;
$this->states = $states;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
return View::make('organizations.index');
}
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
$supportedStates = ['' => 'Choose'] + $this->states->supportedStates();
$procedures = $this->procedures->getDropDown();
return View::make('organizations.create', compact('supportedStates', 'procedures'));
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
$input = Input::all();
// validation here
$new_organization = $this->organization_repo->create(array_only($input, ['organization_name']));
$input['objectstate_id'] = 27;
$input['orgtype_id'] = 1;
$new_organization->orgtypes->pivot->create(array_only($input, ['objectstate_id', 'orgtype_id']));
$new_organization->addresses()->create(array_only($input, ['street1', 'zip', 'city', 'state_code']));
$input['objectstate_id'] = 4;
$new_organization->users()->create(array_only($input, ['first_name', 'last_name', 'email', 'password', 'objectstate_id']));
return "completed";
}
This returns "Undefined property: Illuminate\Database\Eloquent\Collection::$pivot” because the pivot has not been created yet. What am I missing?
I found that the 'attach' method does what I want with something like
$new_organization->orgtypes()->attach(1, ['objectstate_id' => '27']);