laravel 4 pivot table save not working - php

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']);

Related

Laravel Nova doesn't find some Models

With some Models, when I make a new Nova Resource for them, seems that Nova can't find the Model because they doesn't show on sidebar (i can't reach them also by URL, giving me a 404).
But this happens only for specific Models and if I try to modify the target Model in the Resource with another one (editing the $model variable), it works and shows the Resource in the sidebar (but with the wrong model). Nova isn't throwing me any error so the debugging is getting crazy difficult.
The Models that doesn't work in my project are named "Product" and "Company".
I'm using Laravel 7.28.3, Nova 3.9.1, MariaDB 10.4.11 and PHP 7.4.1 with Homestead.
Here's the code of Product resource:
<?php
namespace App\Nova;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Http\Requests\NovaRequest;
class Product extends Resource
{
/**
* The model the resource corresponds to.
*
* #var string
*/
public static $model = \App\Product::class;
/**
* The single value that should be used to represent the resource when being displayed.
*
* #var string
*/
public static $title = 'title';
/**
* The columns that should be searched.
*
* #var array
*/
public static $search = [
'id', 'name'
];
/**
* Get the fields displayed by the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
];
}
/**
* Get the cards available for the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function cards(Request $request)
{
return [];
}
/**
* Get the filters available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function filters(Request $request)
{
return [];
}
/**
* Get the lenses available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function lenses(Request $request)
{
return [];
}
/**
* Get the actions available for the resource.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function actions(Request $request)
{
return [];
}
}
And here's the Model code:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
class Product extends Model implements HasMedia
{
use InteractsWithMedia;
public function visits()
{
return visits($this);
}
public function user() {
return $this->belongsTo('App\User');
}
public function company() {
return $this->belongsTo('App\Company');
}
public function productVariety() {
return $this->belongsTo('App\ProductVariety', 'product_variety_id');
}
public function productSpecies() {
return $this->belongsTo('App\ProductSpecies', 'product_species_id');
}
public function productNutrients() {
return $this->hasMany('App\ProductNutrient');
}
public function baseProduct() {
return $this->hasOne('App\Product', 'base_product_id');
}
public function recipes() {
return $this->hasMany('App\Recipe', 'base_product_id');
}
protected $fillable = [
'user_id', 'company_id', 'imageline_id', 'products_species_id', 'products_varieties_id', 'base_product_id',
'name', 'scientific_name', 'production_start', 'production_end', 'production_city', 'description', 'story', 'curiosities', 'advices', 'quantity_advices', 'why_good', 'who_good',
'is_base_product', 'show_related_recipes', 'show_related_products'
];
}
Check your AuthServiceProvider on app/Providers/AuthServiceProvider.php if there is a Policy set to this model. Then on your policy class (probably ProductPolicy which is bind to Product model, check view and viewAny methods, these methods must return true or conditional true.

Specify selected columns in Eloquent model class rather than querybuilder

Whenever I use an eloquent model, it will select *, unless I specify it in a querybuilder object. However, I want to specify allowed fields in the class. This would be useful for ensuring the correct user level gets the details they are entitled to, so it property live with the class.
I want to be able to do it as a member variable, like $with:
/**
* #property mixed id
*/
class Attribute extends Model
{
protected $fillable = ["id", "business_id", "attribute_name"];
protected $with = ["attributeDetail", "business"];
protected $selectedFieldsThatMeanSelectStarDoesntHappen = ["id", "business_id", "attribute_name"];
}
So any query using the above class will do SELECT id, business_id, attribute_name whenever the class is used, and not SELECT *.
Does the above functionality exist? The closest I can get is with a global scope:
class Attribute extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::addGlobalScope('selectFields', function (Builder $builder) {
$builder->select("id", "business_id", "attribute_name");
});
}
}
You can try it:
Create a new builder and a trait to use this new builder:
class BuilderWithSpecifiedColumns extends Builder
{
public $selectedColumns = [];
public function __construct(ConnectionInterface $connection, Grammar $grammar = null, Processor $processor = null, array $selectedColumns = ['*'])
{
parent::__construct($connection, $grammar, $processor);
$this->selectedColumns = $selectedColumns;
}
/**
* #param string[] $columns
* #return \Illuminate\Support\Collection
*/
public function get($columns = ['*'])
{
return parent::get($this->selectedColumns ? $this->selectedColumns : $columns);
}
}
trait HasSelectedColumns
{
protected function newBaseQueryBuilder()
{
$connection = $this->getConnection();
return new BuilderWithSpecifiedColumns(
$connection,
$connection->getQueryGrammar(),
$connection->getPostProcessor(),
$this->selectedFieldsThatMeanSelectStarDoesntHappen,
);
}
}
Use above trait
/**
* #property mixed id
*/
class Attribute extends Model
{
use HasSelectedColumns;
protected $fillable = ["id", "business_id", "attribute_name"];
protected $with = ["attributeDetail", "business"];
protected $selectedFieldsThatMeanSelectStarDoesntHappen = ["id", "business_id", "attribute_name"];
}

Accessing Properties from Classes inside of traits

I'm trying to write a unit test for the startedAt() method using mocks however the problem I'm facing is that I don't think I can access the builder instance from inside that startedAt() method.
To test the startedAt() method I created a fixture class called ExampleFilters and had it extend the parent class of Filters. Inside of the ExampleFilters class I import the FiltersByStartDate trait.
Does anyone have any suggestions on how I can access the builder property from the FiltersByStartDate trait?
Any ideas on this?
<?php
namespace App\Filters\Concerns;
trait FiltersByStartDate
{
/**
* Filter a query to include models of a specific date started.
*
* #param array $startedAt
* #return \Illuminate\Database\Eloquent\Builder
*/
public function startedAt($startedAt)
{
if (isset($startedAt[1])) {
$this->builder->whereHas('currentEmployment', function ($query) use ($startedAt) {
$query->whereBetween('started_at', [
$startedAt[0],
$startedAt[1]
]);
});
} else {
$this->builder->whereHas('currentEmployment', function ($query) use ($startedAt) {
$query->whereDate('started_at', $startedAt[0]);
});
}
return $this->builder;
}
}
<?php
namespace Tests\Fixtures;
use App\Filters\Concerns\FiltersByStartDate;
use App\Filters\Filters;
class ExampleFilters extends Filters
{
use FiltersByStartDate;
}
<?php
namespace App\Filters;
use Illuminate\Http\Request;
abstract class Filters
{
/**
* #var \Illuminate\Http\Request
*/
protected $request;
/**
* The Eloquent builder.
*
* #var \Illuminate\Database\Eloquent\Builder
*/
protected $builder;
/**
* Registered filters to operate upon
*
* #var array
*/
protected $filters = [];
/**
* Create a new class instance.
*
* #param \Illuminate\Http\Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Apply the filters.
*
* #param \Illuminate\Database\Eloquent\Builder $builder
* #return \Illuminate\Database\Eloquent\Builder
*/
public function apply($builder)
{
$this->builder = $builder;
foreach ($this->getFilters() as $filter => $value) {
if (method_exists($this, $filter)) {
$this->$filter($value);
}
}
return $this->builder;
}
/**
* Fetch all relevant filters from the request.
*
* #return array
*/
public function getFilters()
{
return array_filter($this->request->only($this->filters));
}
}
<?php
namespace Tests\Unit\Filters\Concerns;
use Illuminate\Database\Query\Builder;
use Tests\Fixtures\ExampleFilters;
use Tests\TestCase;
/*
* #group filters
*/
class FiltersByStartDateTest extends TestCase
{
/* #var Tests\Fixtures\ExampleFilters */
protected $subject;
public function setUp(): void
{
$this->subject = app(ExampleFilters::class);
}
/** #test */
public function models_can_be_filtered_by_their_start_date()
{
// $this->markTestIncomplete();
$dateSet = ['2020-01-01 00:00:00'];
$mock = \Mockery::mock(Builder::class)
->shouldReceive('whereHas', \Mockery::any())
->shouldReceive('whereDate')
->withArgs(['started_at', $dateSet])
->once()
->andReturn(true)
->getMock();
dd($this->subject->startedAt($dateSet));
$builderMockFromDate = $this->subject->startedAt($dateSet);
$this->assertSame($builderMockFromDate, $mock);
}
}

In Laravel 5.3 Eloquent how to retrieve 3rd table data with where condition

I have 3 Models(each associated with a table separately) which associated with each other I have attached the table structure below
Models are,
Doctor Model associated with doctor_profile_master
<?php
namespace App\TblModels;
use Illuminate\Database\Eloquent\Model;
class Doctor extends Model
{
/**
* #var string
*/
protected $table = 'DOCTOR_PROFILE_MASTER';
/**
* #var string
*/
protected $primaryKey = 'doctor_profile_master_id';
/**
* #var array
*/
protected $fillable = ['doctor_id', 'user_master_id', 'doctor_first_name', 'doctor_last_name', 'doctor_isactive'];
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hospitalDoctorAssociateMasters(){
return $this->hasMany('App\TblModels\HospitalDoctorAssociateMaster','doctor_profile_master_id');
}
}
HospitalDoctorAssociateMaster Model associated with hospital_doctor_associate_master
<?php
namespace App\TblModels;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
class HospitalDoctorAssociateMaster extends Model
{
/**
* #var string
*/
protected $table = 'HOSPITAL_DOCTOR_ASSOCIATE_MASTER';
/**
* #var string
*/
protected $primaryKey = 'hospital_doctor_associate_master_id';
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function doctor(){
return $this->belongsTo('App\TblModels\Doctor','doctor_profile_master_id');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function hospital(){
return $this->belongsTo('App\TblModels\Hospital','hospital_profile_master_id');
}
}
HospitalDoctorRecurringSchedule Model associated with hospital_doctor_recurring_schedule
<?php
namespace App\TblModels;
use Illuminate\Database\Eloquent\Model;
class HospitalDoctorRecurringSchedule extends Model
{
/**
* #var string
*/
protected $table = 'HOSPITAL_DOCTOR_RECURRING_SCH_MASTER';
/**
* #var string
*/
protected $primaryKey = 'hospital_doctor_recurring_sch_master_id';
public function hospitalDoctorAssociateMaster(){
return $this->belongsTo('App\TblModels\HospitalDoctorAssociateMaster','hospital_doctor_associate_master_id');
}
}
Thing i want to do is,
How to retrieve the hospital_doctor_recurring_sch_master table data using specific doctor_id(doctor_profile_master)
I tried some methods but cant able to retrieve those values.
Thanks in advance.
You could use something like this:
$hospitalDoctors = HospitalDoctorRecurringSchedule::with(['hospitalDoctorAssociateMaster', 'hospitalDoctorAssociateMaster.doctor', 'hospitalDoctorAssociateMaster.hospital'])->all();
To search by fields in related tables:
$hospitalDoctors = HospitalDoctorRecurringSchedule::with([
'hospitalDoctorAssociateMaster',
'hospitalDoctorAssociateMaster.doctor',
'hospitalDoctorAssociateMaster.hospital'])
->whereHas('hospitalDoctorAssociateMaster.doctor', function ($query) use ($doctorId) {
$query->where('doctor_id', '=', $doctorId);
})
->all();
For hospitalDoctorAssociateMaster.hospital:
Define Hospital Model and try

Laravel PHP: Creating default object from empty value error

I'm using a controller to call up a form defined in one of my views. Within the controller, I have a simple 'create()' method that I just want to use to call up a form while using the 'Video' model I've defined. The problem is when I try to call this function, I keep getting a 'Creating default object from empty value' error.
Controller(app\VideosController.php):
<?php
use Acme\repositories\VideoRepository;
use Models\Video;
use Models\Validators as Validators;
class VideosController extends BaseController {
/**
* The video model
*
* #var \Models\Video
**/
protected $video;
/* The value defined from my repository
*/
protected $videoRepo;
/**
* Instantiate the controller
*
* #param Models\Video $video
* #return void
**/
public function __construct(VideoRepository $videoRepo)
{
$this->videoRepo = $videoRepo;
/* Old code below
$this->video = \App::make('Repositories\VideoRepository');
*/
}
/* Create a new video by passing in a sub view
Of the form for creating a new video */
public function create()
{
$data = array('type' => 'video');
$this->layout->content = \View::make('forms.new-video', $data);
}
}
Model(app/models/video.php):
<?php
class Video extends Eloquent {
/**
* The table used by this model
*
* #var string
**/
protected $table = 'videos';
/**
* The primary key
*
* #var string
**/
protected $primaryKey = 'video_id';
/**
* The fields that are guarded cannot be mass assigned
*
* #var array
**/
protected $guarded = array();
/**
* Enabling soft deleting
*
* #var boolean
**/
protected $softDelete = true;
}
The view for my form is located at 'app\views\forms\new-video.blade.php'.
Am I not defining my 'create()' method properly or is a matter of not placing files in their correct location?
I believe you are missing the declaration of the $layout property in your controller, so it has no idea what view to use as the template:
/**
* The layout that should be used for responses.
*/
protected $layout = 'layouts.master';
See http://laravel.com/docs/4.2/templates#controller-layouts.

Categories