I have 2 tables that are related to each other by 3rd table (where only stores the ids) now seems i can't get my data out of third table in API resource file
Logic
Product model (has many barcode)
Barcode model (belongs to product and belongs to outlet)
Outlet model (has many barcodes)
outlet_products table (stores barcode_id and outlet_id)
Code
Barcode model
class Barcode extends Model
{
public function product()
{
return $this->belongsTo(Product::class);
}
public function outlet()
{
return $this->belongsTo(Outlet::class, 'outlet_products', 'barcode_id', 'outlet_id');
}
}
Outlet model
class Outlet extends Model
{
public function barcodes()
{
return $this->hasMany(Barcode::class, 'outlet_products', 'outlet_id', 'barcode_id');
}
}
BarcodeResource
class BarcodeResource extends JsonResource
{
public function toArray($request)
{
$arrayData = [
'id' => $this->id,
'sku' => $this->sku,
'serial_number' => $this->serial_number ? (Int) $this->serial_number : null,
'price' => (Int) $this->price,
'discount' => $this->discount ? (Int) $this->discount : null,
'product' => new ProductsResource($this->whenLoaded('product')),
'outlet' => new OutletsResource($this->whenLoaded('outlet')),
];
return $arrayData;
}
}
Now I am trying to get my product barcodes and name of each barcode outlet.
Controller
$products = ProductsResource::collection(Product::orderBy('id', 'desc')->with(['barcodes', 'barcodes.outlet'])->get());
and the result is:
Any idea why i can't get my barcodes outlet?
Based on your question and comment above:
A Product has many Barcode and a Barcode belongs to a Product. They have a One To Many relationship.
An Outlet has many barcode and a Barcode has many Outlet. They have a Many To Many relationship.
Here's how to set the One To Many relationship.
In your Product class:
class Product extends Model
{
public function barcodes()
{
return $this->hasMany('App\Barcode');
}
}
In your Barcode class, set the inverse relationship:
class Barcode extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
}
Here's how to set the Many To Many relationship.
In your Outlet class:
class Outlet extends Model
{
public function barcodes()
{
return $this->belongsToMany('App\Barcode');
}
}
In your Barcode class:
class Barcode extends Model
{
public function outlets()
{
return $this->belongsToMany('App\Outlet');
}
}
With a Many to Many relationship, you also need to create an intermediate table.
In this case, your pivot table will be barcode_outlet.
Important: Per Laravel convention, the intermediate table name must be in singular form and alphabetical order of the related model names (barcode_outlet in your case).
The intermediate table must have barcode_id and outlet_id columns. I will let you modify your migrations accordingly.
After setting the relationships, you will be able to use Eloquent to retrieve your models.
Example:
$barcode->outlets;
// returns a Collection of outlets
$barecode->product;
// returns a Product
$product->barcodes;
// returns a Collection of barcodes
$outlet->barcodes;
// returns a Collection of barcodes
Related
I have two tables, work_order and project. On the project records, there is a work_order_id field. There is no project_id on the work_order records. Do I need to add one?
Or is there a way to define these relationships using hasOne/belongsTo?
I've tried:
class WorkOrder extends \Phalcon\Mvc\Model {
public function initialize() {
$this->hasOne('id', Project::class, 'work_order_id');
}
}
class Project extends \Phalcon\Mvc\Model {
public function initialize() {
$this->hasOne('work_order_id', WorkOrder::class, 'id');
}
}
I can retrieve the WorkOrder from the project like so: $project->workOrder, but I cannot retrieve a Project from a WorkOrder using $workOrder->project. I want a bidirectional relationship.
How do I do this?
Try adding the alias parameter, since the implicit retrieval might try to use the class name and it wouldn't support namespaces in your models.
I found it quite bogus in phalcon 1/2/3 to work with hasOne. I've been using belongsTo since then until I re-wrote the pre-post-save part of the phalcon relationship manager for my personal needs. Keep in mind that belongsTo will be saved before the main model you are working with, other types of relationships will be created/updated after the main record is saved. I choose to use "belongsTo" or "hasOne" depending on the order that I want the records and their relationships to be saved.
class WorkOrder extends \Phalcon\Mvc\Model {
public function initialize() {
$this->belongsTo('project_id', Project::class, 'id', ['alias' => 'Project']);
}
}
class Project extends \Phalcon\Mvc\Model {
public function initialize() {
$this->hasOne('id', WorkOrder::class, 'project_id', ['alias' => 'WorkOrder']);
$this->hasMany('id', WorkOrder::class, 'project_id', ['alias' => 'WorkOrderList']);
}
}
Implicit retrieval should start with a ucfirst camelized string of your class name, or using a get.
$workOrder = WorkOrder::findFirst();
$project = $workOrder->Project;
$project = $workOrder->getProject(['deleted <> 1']);
$workOrderList = $project->WorkOrderList;
$workOrder = $project->WorkOrder;
$workOrder = $project->getWorkOrder(['deleted <> 1', 'order' => 'projectId desc']);
Laravel version:7.0
reviews table (Model - Review) has id, product_type, product_id, rating columns.
product_type can be service, plugin, module and each value has own model App\Service, App\Plugin, App\Module. I could put model names directly in product_type but I prefer to use those values.
Here is Review model relationship.
public function plugin()
{
return $this->belongsTo(Plugin::class, "product_id")->withDefault();
}
public function module()
{
return $this->belongsTo(Module::class, "product_id")->withDefault();
}
public function service()
{
return $this->belongsTo(Service::class, "product_id")->withDefault();
}
public function getItem()
{
if($this->product_type=='module')
{
return $this->module;
}elseif($this->product_type=='service')
{
return $this->service;
}else {
return $this->plugin;
}
}
Now I want to get them with eager loading in Review Model as following:
$reviews = Review::with("getItem")->get();
Without Eager loading, I could use $review->getItem()->name // this returns name of product.
How can I get them with eager loading?
You could have implemented this easily as a polymorphic relationship. In your Reviews Model, you could do this:
Model Structure
App\Review.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
public function reviewable()
{
return $this->morphTo();
}
}
Then add reviews() method to your App\Service, App\Plugin and App\Module models
public function reviews()
{
return $this->morphMany('App\Review', 'reviewable');
}
Table Structure
You reviews table could look like this:
reviews
id - integer
body - text
reviewable_id - integer
reviewable_type - string
Note the reviewable_id and reviewable_type fields. The reviewable_id stores the id of the item reviewed and the reviewable_type stores the model related to the item.
Retrieving The Relationship
You may access the relationships via your models. For example, to access all of the reviews for a service, we can use the reviews dynamic property:
$service = App\Service::find(1);
foreach ($service->reviews as $review) {
//
}
You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to morphTo. In your case, that is the reviewable method on the Review model. So, we will access that method as a dynamic property:
$review = App\Review::find(1);
$reviewable = $review->reviewable;
The reviewable will return the model on the Review model either Service, Plugin or Module
I have 2 models:
class Order extends Model
{
protected $fillable = ['user_id','name','surname','fathers_name','phone_number','city','post_office','comment'];
public function user()
{
return $this->belongsTo('App\User');
}
public function products()
{
return $this->belongsToMany('App\Product', 'order_product');
}
}
class Product extends Model
{
public function order()
{
return $this->belongsToMany('App\Order', 'order_product');
}
public function category()
{
return $this->belongsTo('App\Category');
}
}
3 tables:
product:
id
name
...
order_product:
id
order_id
prod_id
qty
...
order
id
city
phone
...
and 2 arrays of data:
$data = $request->except('_token','submit'); - information about client
$order_content - array with info about products in cart
So, the question is how to insert all this data in DB? I tried to read about many to many insertion: sync, attach, etc.. but understood nothing :c
Imagine you have a product with id 1. And an order with id 1. The product is part of the order, so you have to attach them. You do
$product = Product::find(1);
$order = Order::find(1);
$order->products()->attach($order->id);
However, in your case, your pivot table has more data, like 'qty'. Then you do,
$order->product()->attach($order->id, ['qty' => 2]);
So far, we were only attaching a single product to an order. If you want to attach many products simultaneously, you do:
$order->products()->sync([
$product->id => ['qty' => 1],
$product2->id => ['qty' => 3]
]);
I hope this helps understand better. I recommend you read the doc again and again until it makes sense.
I have a Detail (represents order details) model that I'd like to morph to either a sales order detail or a purchase order detail. So I create a table that has a 'type' column, which would have a value of 'sale' or 'purchase'.
My question is, is there a way in Laravel that I could morph the Detail model to Sale and Purchase, so that, for example, if I call App\Sale::all() it would fetch App\Detail::all()->where('type','sale') ?
Set the database tables:
You can set up your database tables in this structure :
purchases
id - integer
price - string
sales
id - integer
price - integer
details
id - integer
description - string
detailable_id - integer
detailable_type - string
Set your models:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Detail extends Model
{
// Get all of the owning detailable models.
public function detailable()
{
return $this->morphTo();
}
}
class Sale extends Model
{
// Get all of the sales member's order details.
public function details()
{
return $this->morphMany('App\Detail', 'detailable');
}
}
class Purchase extends Model
{
// Get all of the purchase's order details.
public function details()
{
return $this->morphMany('App\Detail', 'detailable');
}
}
Retrieve data :
And then you can retrieve your sales like this :
$sales = App\Sale::find(1);
foreach ($sales->details as $order_detail) {
//
}
Same thing with purchases :
$purchases = App\Purchase::find(1);
foreach ($purchases->details as $order_detail) {
//
}
More about polymorphic relations : http://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations
Although I haven't found an "official" way to morph a single class to another. I developed the following way that could be a solution.
First, define two models Sale and Purchase that extends Detail, and use the trait that will define later.
class Sale extends Detail {
use SaleTrait;
}
Then, use GlobalScope to add constraints to query builder. Here are the steps:
Define a trait for Sale and Purchase model,
trait SaleTrait {
public static function bootSaleTrait()
{
static::addGlobalScope(new ActiveEventsScope);
}
}
Then define the scope. NOTE: here instead of implementing ScopeInterface, I extends Sofa\GlobalScope which handles remove() method for me, so I only need to define apply() in the scope.
class SaleScope extends GlobalScope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('type', 'sale');
}
}
Now I could use App\Sale::all() and App\Purchase::all() to only retrieve what I want.
I'm using Laravel as a REST API for a SPA. I have a relationship where families have multiple contributions. The contributions table has a foreign key reference to family's id. I can call on the contributions route with the hasMany/belongsTo set up, and every contribution gets the entire family model it belongs to. But I don't need all that data, I just need a single field from the family table (not the id, but a different field) with each contribution.
Here are my models and resource controller:
class Family extends Eloquent {
protected $table = 'families';
// relationships
public function contributions() {
return $this->hasMany('Contribution');
}
}
class Contribution extends Eloquent {
protected $table = 'contributions';
// relationships
public function family() {
return $this->belongsTo('Family');
}
public function other_field() {
return $this->belongsTo('Family')->select('other_field');
}
}
class ContributionController extends BaseController {
public function index()
{
// works - but returns the entire family with every contribution
$contributions = Contribution::with('family')->get();
// returns other_field == null with every contribution
$contributions = Contribution::with('other_field')->get();
return Response::json($contributions->toArray(),
200);
}
Where am I going wrong with selecting this single field from the belongsTo relationship?
You can use query constraints on the relationship if you use eager loading.
Family::with(['contributions', function($query)
{
$query->select('column');
}])->get();