I am building a REST API on Laravel. I currently have a Model ( Project ) which has 2 Dynamic Methods ( liveindexes and totalindexes ).
I want the API (/projects) to return the values of both those methods as well.
Project Controller
public function index()
{
return Project::paginate();
}
Project Model
class Project extends Model
{
protected $table = 'projects';
protected $fillable = [
'target'
];
public function indexes()
{
return $this->hasMany('App\indexes','project_id','id');
}
public function totalindexes()
{
return $this->indexes()->count();
}
public function liveindexes()
{
return $this->indexes()->whereNotNull('anchor')->count();
}
}
To include these items with your Project model, add them to your model's attributes, attributes are appended when to model is transformed into an array, or it's JSON form.
Add this to your code:
protected $appends = ['live_indexes', 'total_indexes'];
public function getLiveIndexesAttribute() {
return $this->attributes['live_indexes'] = $this->liveIndexes();
}
public function getTotalIndexes() {
return $this->attributes['total_indexes'] = $this->totalindexes();
}
Related
this is my first post. I have a problem with my Laravel application.
I need to modify the serialization of the data for my endpoint to get the data of a specific bike.
The endpoint return this:
{"bike":{"id":32,
"unlock_code":2342,
"rack": {"id":3,
"available_stands":10,
"latitude":"46.754",
"longitude":"8.5732",
"available_bikes":10
},
"bike_state":{"description":"Available"}
}
}
but i want to have this:
{"bike":{"id":32,
"unlock_code":2342,
"rack":{"id":3,
"available_stands":10,
"latitude":"46.754",
"longitude":"8.5732",
"available_bikes":10
},
"bike_state":{"Available"}
}
}
the field name ('description') must be hidden. It's the first time i use laravel and i don't know if it's possible to do this.
This is the model
class BikeState extends Model
{
protected $hidden = ['id'];
public function bikes()
{
return $this->hasMany('App\Bike');
}
}
this is the repository with the method to retrieve the data:
class BikeRepository
{
public function findBikeById($id)
{
return Bike::with('rack','bikeState')->findOrFail($id);
}
}
and this is the controller
class BikeController extends Controller
{
private $bikeRepository;
public function __construct(BikeRepository $bikeRepository)
{
$this->bikeRepository = $bikeRepository;
}
public function getBike($id)
{
return response() ->json(['bike' => $this -> bikeRepository ->
findBikeByid($id)], 200);
}
}
Thank you
Create an accessor on your Bike model like this:
public function getBikeStateAttribute($value)
{
return json_encode($this->attributes['description']);
}
Then add accessor to Bike model's array like this:
protected $appends = ['bike_state'];
I have three models, Advertiser, PtcAd, and PtcCampaign. When deleting a Advertiser I want to delete all related PtcAds and PtcCampaigns. The Advertiser has many PtcCampaigns through PtcAds.
Advertiser Model
use SoftDeletes;
protected $dates = ['deleted_at'];
public function ptcAds()
{
return $this->hasMany('App\PtcAd');
}
public function ptcCampaigns()
{
return $this->hasManyThrough('App\PtcCampaign', 'App\PtcAd');
}
public function delete()
{
$this->ptcAds()->delete();
// I'VE TRIED WITH AND WITHOUT THIS
$this->ptcCampaigns()->delete();
return parent::delete();
}
PtcAd Model
use SoftDeletes;
protected $fillable = ['advertiser_id', 'title'];
protected $dates = ['deleted_at'];
public function advertiser()
{
return $this->belongsTo('App\Advertiser');
}
public function ptcCampaigns()
{
return $this->hasMany('App\ptcCampaign');
}
public function delete()
{
$this->ptcCampaigns()->delete();
return parent::delete();
}
PtcCampaign Model
use SoftDeletes;
public $timestamps = false;
protected $fillable = ['ptc_ad_id', 'clicks'];
protected $dates = ['paused_at', 'deleted_at'];
public function ptcAd()
{
return $this->belongsTo('App\PtcAd');
}
My tests:
public function test_delete_advertiser()
{
$advertiser = factory(Advertiser::class)->create();
$ptcAd = factory(PtcAd::class)->create(['advertiser_id' => $advertiser->id]);
$ptcCampaign = factory(PtcCampaign::class)->create(['ptc_ad_id' => $ptcAd->id]);
$this->assertTrue($advertiser->delete());
$this->assertFalse(Advertiser::all()->contains($advertiser));
$this->assertFalse(PtcAd::all()->contains($ptcAd));
// THE FOLLOWING TEST DOESN'T WORK!
$this->assertFalse(PtcCampaign::all()->contains($ptcCampaign));
}
// ALL OF THE FOLLOWING TESTS WORK!
public function test_delete_ad()
{
$ptcAd = factory(PtcAd::class)->create();
$ptcCampaign = factory(PtcCampaign::class)->create(['ptc_ad_id' => $ptcAd->id]);
$this->assertTrue($ptcAd->delete());
$this->assertFalse(PtcAd::all()->contains($ptcAd));
$this->assertFalse(PtcCampaign::all()->contains($ptcCampaign));
}
The $this->assertFalse(PtcCampaign::all()->contains($ptcCampaign)) in the test_delete_advertiser() test fails, why?
I have more tests to make sure all the relationships work so I really don't know what could possibly be wrong. My next attempt would be to make foreach in the Advertiser's delete() method but maybe there's something simpler and I want to understand why this doesn't work.
It looks the problem is with the sequence of delete statement.
Try by changing the sequence like below:
public function delete()
{
$this->ptcCampaigns()->delete();
$this->ptcAds()->delete();
return parent::delete();
}
You can use Laravel's Model Events (deleting) to delete related models like this:
class Advertiser extends Eloquent
{
public function ptcAds()
{
return $this->hasMany('PtcAd');
}
// this is a recommended way to declare event handlers
protected static function boot() {
parent::boot();
static::deleting(function($adv) { // before delete() method call this
$adv->ptcAds()->delete();
// do the rest of the cleanup...
});
}
}
// Same for PtcCompaigns
class PtcAd extends Eloquent
{
public function ptcCompaigns()
{
return $this->hasMany('PtcCompaigns');
}
// this is a recommended way to declare event handlers
protected static function boot() {
parent::boot();
static::deleting(function($ptc_ad) { // before delete() method call this
$ptc_ad->ptcCompaigns()->delete();
// do the rest of the cleanup...
});
}
}
Hope this helps!
For some reason, I cannot chain model objects. I'm trying to eager load 'Location' for an 'Order' and would prefer the logic to be contained in the models themselves. But past one chain, it does not work.
class Order extends Eloquent {
protected $table = 'orders';
public function customer() {
return $this->belongsTo('Customer');
public function location() {
return $this->customer()->location(); // this does not work
}
}
class Customer extends Eloquent {
protected $table = 'customers';
public function user() {
return $this->belongsTo('User');
}
public function orders() {
return $this->hasMany('Order');
}
public function location() {
return $this->user()->location();
// return $this->user(); // WORKS!!
}
}
class User extends Eloquent {
protected $table = 'users';
public function locations() {
return $this->hasMany('Location');
}
public function location() {
return $this->locations()->first();
}
}
I eventually want to do this:
class ChefController extends BaseController {
public function get_orders() {
$chef = $this->get_user_chef(); // this already works
return $chef->orders()->with('location')->get(); // does not work
}
}
Try to reference relation (user table) by adding user_id as second argument, like this:
public function user() {
return $this->belongsTo('User',"user_id");
}
Maybe you called that id field different, but you know what I mean.
I hope I can explain this clearly, apologies in advance if it is confusing. I have a goals table which hasOne of each of bodyGoalDescs, strengthGoalDescs and distanceGoalDescs as shown below
goals.php
class Goal extends BaseModel
{
protected $guarded = array();
public static $rules = array();
//define relationships
public function user()
{
return $this->belongsTo('User', 'id', 'userId');
}
public function goalStatus()
{
return $this->hasOne('GoalStatus', 'id', 'goalStatus');
}
public function bodyGoalDesc()
{
return $this->hasOne('BodyGoalDesc', 'id', 'bodyGoalId');
}
public function distanceGoalDesc()
{
return $this->hasOne('DistanceGoalDesc', 'id', 'distanceGoalId');
}
public function strengthGoalDesc()
{
return $this->hasOne('StrengthGoalDesc', 'id', 'strengthGoalId');
}
//goal specific functions
public static function yourGoals()
{
return static::where('userId', '=', Auth::user()->id)->paginate();
}
}
each of the three tables looks like this with the function details changed
class BodyGoalDesc extends BaseModel
{
protected $guarded = array();
public static $rules = array();
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'bodyGoalDescs';
//define relationships
public function goal()
{
return $this->belongsTo('Goal', 'bodyGoalId', 'id');
}
}
a goal has either a body goal, a strength goal, or a distance goal. I am having a problem with this method in the controller function
<?php
class GoalsController extends BaseController
{
protected $goal;
public function __construct(Goal $goal)
{
$this->goal = $goal;
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
$thisgoal = $this->goal->find($id);
foreach ($this->goal->with('distanceGoalDesc')->get() as $distancegoaldesc) {
dd($distancegoaldesc->DistanceGoalDesc);
}
}
}
when I pass through goal 1 which has a distance goal the above method dies and dumps the Goal object with the details of goal 1 and an array of its relations including an object with DistanceGoalDes.
when I pass through goal 2 it passes through exactly the same as if I had passed through goal 1
if I dd() $thisgoal i get the goal that was passed through
what I want ultimately is a method that returns the goal object with its relevant goal description object to the view but this wont even show me the correct goal details not too mind with the correct relations
this function is now doing what I want it to do, I am sure there is a better way (besides the fact that its happening in the controller right now) and I would love to hear it.
public function show($id)
{
$thisgoal = $this->goal->find($id);
if (!$thisgoal->bodyGoalDesc == null) {
$goaldesc = $thisgoal->bodyGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('bodygoaldesc', $goaldesc);
} elseif (!$thisgoal->strengthGoalDesc == null) {
$goaldesc = $thisgoal->strengthGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('strengthgoaldesc', $goaldesc);
} elseif (!$thisgoal->distanceGoalDesc == null) {
$goaldesc = $thisgoal->distanceGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('distancegoaldesc', $goaldesc);
}
}
I'm pretty new to Laravel and Eloquent, so this could easily be something trivial but anyways I've been missing a good solution so far. So heres my problem:
I have a main gallery and i want the user to be able to upload any images or videos that he needs into that main gallery and select images/videos from that gallery to be shown elsewhere on the website (basically what i'm doing is centralising multimedia content all in one place).
Using deduction (with all my poor knowledge of Eloquent) i found this as best solution for me:
//Gallery Model
class Gallery extends Eloquent {
protected $table = 'gallery';
protected $guarded = array();
public static $rules = array();
public function images() {
return $this->morphMany('Image', 'imageable');
}
public function videos() {
return $this->morphMany('Video', 'videoable');
}
}
//About Orchestra Model
class OrchestraAbout extends Eloquent {
protected $table = 'orchestra_about';
protected $guarded = array();
public static $rules = array();
public function images() {
return $this->morphMany('Image', 'imageable');
}
public function videos() {
return $this->morphMany('Video', 'videoable');
}
}
//Image Model
class Image extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function imageable()
{
return $this->morphTo();
}
}
//Video Model
class Video extends Eloquent {
protected $guarded = array();
public static $rules = array();
public function videoable()
{
return $this->morphTo();
}
}
And when inserting into database i simply duplicate the row and only change the imageable_id /videoable_id and imageable_type/videoable_type to match the OrchestraAbout Model.
Anyone here knows of a better solution for this?
Thanks for all the smart answers! Cheers!