Return collection with custom resolver/data provider on ApiPlatform with GraphQL - api-platform.com

I work with PHP - Symfony 5.
I would like to return a collection with graphQL on Api Platform but I have a problem :
"debugMessage": "Service \"App\\DataProvider\\CompaniesCollectionDataProvider\" not found: the container inside \"Symfony\\Component\\DependencyInjection\\Argument\\ServiceLocator\" is a smaller service locator that only knows about the \"App\\Resolver\\CheckRecruiterQueryResolver\", \"App\\Resolver\\ForgotRecruiterQueryResolver\" and \"App\\Resolver\\JobBoard\\FindOffersByCompanyQueryResolver\" services.",
First I had created a resolver but looking at the documentation, I realized that it was necessary to make a data provider.
Unfortunately that did not solve the problem, I still have the same error message...
My custom data Provider :
namespace App\DataProvider;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use App\Entity\Candidate;
use App\Entity\Company;
use Doctrine\Persistence\ManagerRegistry;
class CompaniesCollectionDataProvider implements CollectionDataProviderInterface
{
private $doctrine;
public function __construct(ManagerRegistry $doctrine)
{
$this->doctrine = $doctrine;
}
public function getCollection
(string $resourceClass, string $operationName = null, array $context = [])
{
$candidateId = $context['filters']['candidate_id'];
$candidate = $this->doctrine->getRepository(Candidate::class)
->findOneBy(['id' => $candidateId]);
if(empty($candidate->getPosition()))
{
$companies = $this->doctrine->getRepository(Company::class)
->findByStoreIsNational();
// return companies where stores related = is_national
// getCollection doit retourner un array
return $companies;
}
$companies = $this->doctrine->getRepository(Company::class)
->findByStoreIsNational();
return $companies;
}
}
My entity :
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\DataProvider\CompaniesCollectionDataProvider;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ApiResource(graphql={
* "search"={
* "collection_query"=CompaniesCollectionDataProvider::class,
* "args"={
* "candidate_id"={"type"="Int!", "description"="Candidate_id"}
* }
* },
* "create", "update", "delete", "collection_query", "item_query"
* })
*
* #Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false)
* #ORM\Entity(repositoryClass="App\Repository\CompanyRepository")
* #ORM\Table(name="companies")
* #UniqueEntity("name")
*/
class Company
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Media", mappedBy="company")
*/
private $logo;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $createdAt;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $updatedAt;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $deletedAt;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Store", mappedBy="company")
*/
private $stores;
public function __construct()
{
$this->stores = new ArrayCollection();
$this->stories = new ArrayCollection();
$this->logo = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getLogo(): ?string
{
return $this->logo[0];
}
public function setLogo(string $logo): self
{
$this->logo = $logo;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getDeletedAt(): ?\DateTimeInterface
{
return $this->deletedAt;
}
public function setDeletedAt(?\DateTimeInterface $deletedAt): self
{
$this->deletedAt = $deletedAt;
return $this;
}
/**
* #return Collection|Store[]
*/
public function getStores(): Collection
{
return $this->stores;
}
public function addStore(Store $store): self
{
if (!$this->stores->contains($store)) {
$this->stores[] = $store;
$store->setCompany($this);
}
return $this;
}
public function removeStore(Store $store): self
{
if ($this->stores->contains($store)) {
$this->stores->removeElement($store);
// set the owning side to null (unless already changed)
if ($store->getCompany() === $this) {
$store->setCompany(null);
}
}
return $this;
}
public function addLogo(Media $logo): self
{
if (!$this->logo->contains($logo)) {
$this->logo[] = $logo;
$logo->setCompany($this);
}
return $this;
}
public function removeLogo(Media $logo): self
{
if ($this->logo->contains($logo)) {
$this->logo->removeElement($logo);
// set the owning side to null (unless already changed)
if ($logo->getCompany() === $this) {
$logo->setCompany(null);
}
}
return $this;
}
}
My repository :
class CompanyRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Company::class);
}
public function findByStoreIsNational() {
return $this->createQueryBuilder('c')
->leftJoin('c.stores', 's')
->where('s.isNational = true')
->getQuery()
->getResult();
}
I thank you in advance for your help,
Regards,
Romain

As stated in the documentation for custom queries, you need to create a custom resolver, not a custom data provider.
CompaniesCollectionDataProvider should become CompanyCollectionResolver and should implement QueryCollectionResolverInterface.

Related

How to refactor two Model classes implementing same method

Given two classes that extend Model which is an extension of Eloquent\Model that have the exact same copy-pasted method. What is the recommended way to extract this duplicate method? An abstract class with the method that extends Model that both classes can then extend or a Trait to sprinkle in the functionality? Both classes are named quite similar but different in their uses for our system. Naming recommendations are also appreciated.
Below are the classes but only pasted with the similarities. The SQL view class uses a SQL view to remove the need for the attributes, it allows it to play nice with other parts of the system.
getExpirationMessageAttribute
<?php
class SupplierDocument extends Model {
use HasFactory, Taskable;
protected $appends = ['days_till_expiry', 'expiration_status', 'expiration_message'];
public function owner() {
return $this->belongsTo(User::class, 'owner_id');
}
public function facilities() {
return $this->belongsToMany(Facility::class, 'supplier_document_facilities');
}
/**
* Document expiration status.
*
* #return string
*/
public function getExpirationStatusAttribute() {
if (! $this->load('type')->type->is_expirable) {
return DocumentStatusEnum::NotExpirable;
}
if (Carbon::parse($this->expires_at)->isPast()) {
return DocumentStatusEnum::Expired;
}
if (Carbon::parse($this->expires_at)->diffInDays(now()) <= $this->type->expiration_window) {
return DocumentStatusEnum::ExpiringSoon;
}
return DocumentStatusEnum::Active;
}
/**
* Document days till expiration.
*
* #return string
*/
public function getDaysTillExpiryAttribute() {
if ($this->expires_at) {
return Carbon::parse($this->expires_at)->diffInDays(Carbon::now()->toDateString());
}
}
/**
* Document expiration message.
*
* #return string
*/
public function getExpirationMessageAttribute() {
if ($this->expiration_status === DocumentStatusEnum::ExpiringSoon) {
if ($this->days_till_expiry > 1) {
return "Expiring in $this->days_till_expiry days";
} elseif ($this->days_till_expiry === 1) {
return 'Expiring in 1 day';
} else {
return 'Expires today';
}
}
if ($this->expiration_status === DocumentStatusEnum::Expired) {
return "Expired $this->days_till_expiry days ago";
} elseif ($this->expiration_status === DocumentStatusEnum::NotExpirable) {
return DocumentStatusEnum::NotExpirable;
}
return DocumentStatusEnum::Active;
}
}
<?php
class SupplierDocumentView extends Model {
protected $appends = ['expiration_message'];
protected $table = 'supplier_documents_view';
public function owner() {
return $this->belongsTo(User::class, 'owner_id');
}
public function facilities() {
return $this->belongsToMany(Facility::class, 'supplier_document_facilities', 'supplier_document_id');
}
/**
* Document expiration message.
*
* #return string
*/
public function getExpirationMessageAttribute() {
if ($this->expiration_status === DocumentStatusEnum::ExpiringSoon) {
if ($this->days_till_expiry > 1) {
return "Expiring in $this->days_till_expiry days";
} elseif ($this->days_till_expiry === 1) {
return 'Expiring in 1 day';
} else {
return 'Expires today';
}
}
if ($this->expiration_status === DocumentStatusEnum::Expired) {
return "Expired $this->days_till_expiry days ago";
} elseif ($this->expiration_status === DocumentStatusEnum::NotExpirable) {
return DocumentStatusEnum::NotExpirable;
}
return DocumentStatusEnum::Active;
}
}
Just move this to trait:
trait ExpirationAwareTrait
{
public abstract function getExpirationStatusAttribute(): string;
public function getExpirationMessageAttribute()
{
if ($this->expiration_status === DocumentStatusEnum::ExpiringSoon) {
if ($this->days_till_expiry > 1) {
return "Expiring in $this->days_till_expiry days";
} elseif ($this->days_till_expiry === 1) {
return 'Expiring in 1 day';
} else {
return 'Expires today';
}
}
if ($this->expiration_status === DocumentStatusEnum::Expired) {
return "Expired $this->days_till_expiry days ago";
} elseif ($this->expiration_status === DocumentStatusEnum::NotExpirable) {
return DocumentStatusEnum::NotExpirable;
}
return DocumentStatusEnum::Active;
}
}
When you use this trait - you will MUST realise getExpirationStatusAttribute method.

How To Display Product API by categories using laravel

My expected JSON format:
This is my expected JSON format, I have a product table along with products related table. I want to show products in categories wise.
Product Table:
Category Table:
Here is my product model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
/**
* The attributes that aren't mass assignable.
*
* #var array
*/
protected $guarded = ['id'];
private $minimum_price;
/**
* Get the products image.
*
* #return string
*/
public function getImageUrlAttribute()
{
if (!empty($this->image)) {
$image_url = asset('/storage/img/product/' . $this->image);
} else {
$image_url = asset('/img/default.png');
}
return $image_url;
}
public function product_variations()
{
return $this->hasMany(\App\ProductVariation::class);
}
/**
* Get the brand associated with the product.
*/
public function brand()
{
return $this->belongsTo(\App\Brands::class);
}
/**
* Get the unit associated with the product.
*/
public function unit()
{
return $this->belongsTo(\App\Unit::class);
}
/**
* Get category associated with the product.
*/
public function category()
{
return $this->belongsTo(\App\Category::class);
}
/**
* Get sub-category associated with the product.
*/
public function sub_category()
{
return $this->belongsTo(\App\Category::class, 'sub_category_id', 'id');
}
/**
* Get the brand associated with the product.
*/
public function product_tax()
{
return $this->belongsTo(\App\TaxRate::class, 'tax', 'id');
}
/**
* Get the variations associated with the product.
*/
public function variations()
{
return $this->hasMany(\App\Variation::class);
}
/**
* If product type is modifier get products associated with it.
*/
public function modifier_products()
{
return $this->belongsToMany(\App\Product::class, 'res_product_modifier_sets', 'modifier_set_id', 'product_id');
}
/**
* If product type is modifier get products associated with it.
*/
public function modifier_sets()
{
return $this->belongsToMany(\App\Product::class, 'res_product_modifier_sets', 'product_id', 'modifier_set_id');
}
/**
* Get the purchases associated with the product.
*/
public function purchase_lines()
{
return $this->hasMany(\App\PurchaseLine::class);
}
public function images()
{
return $this->hasMany(ProductImage::class);
}
public function attributes()
{
return $this->hasMany(ProductAttribute::class);
}
public function attributesWithoutDefault()
{
return $this->hasMany(ProductAttribute::class)->where('attribute_id', '>', 4);
}
public function vendor_product()
{
return $this->hasMany(VendorProduct::class, 'product_id', 'id');
}
public function origin()
{
return $this->belongsTo(ProductOrigin::class);
}
public function defaultAttributes()
{
return $this->hasMany(ProductAttribute::class)->where('attribute_id', '<=', 4);
}
public function notes()
{
return $this->hasMany(ProductNote::class);
}
public function additionalCategory()
{
return $this->belongsTo(\App\Category::class, 'additional_category', 'id');
}
public function getAdditionalCategoryNameAttribute()
{
$additional_category = $this->additionalCategory;
return $additional_category ? $additional_category->name : null;
}
public function industries()
{
return $this->belongsToMany(Industry::class, 'product_industries');
}
public function getCatalogUrlAttribute()
{
return asset('/uploads/'. constants('product_catalog_path') . '/' . $this->catalog_brusher);
}
public function getSpecSheetUrlAttribute()
{
return asset('/uploads/'. constants('product_spec_sheet_path') . '/' . $this->spec_sheet);
}
public function relatedProducts()
{
return $this->belongsToMany(Product::class, 'related_products', 'product_id', 'related_product_id');
}
private function setMinPrice()
{
if (is_null($this->minimum_price)) {
$this->minimum_price = $this->vendor_product->min('price');
}
return $this->minimum_price;
}
public function getMinPriceAttribute()
{
return $this->setMinPrice();
}
public function getMinPriceVendorAttribute()
{
$min_price = $this->setMinPrice();
if (is_null($min_price)) return null;
$min_vendor_product = $this->vendor_product->firstWhere('price', $min_price);
return Contact::find($min_vendor_product->vendor_id);
}
/**
* Get the unit quantity associated with the product.
*/
public function unitQuantity()
{
return $this->belongsTo(\App\UnitQuantity::class);
}
}
you should join the same table more than once, every time you join,
you join with suitable alias name:
$list = Product::
leftJoin('categories as mainCategory','products.category_id','mainCategory.id')
->leftJoin('categories as subCategory','products.sub_category_id','subCategory.id')
->leftJoin('categories as additionalCategory','products.additional_category','additionalCategory.id')
->select(['products.*','mainCategory.name as mainCategoryName','subCategory.name as subCategoryName','additionalCategory.name as additionalCategoryName'])->get();
please note that your column 'products.additional_category' should be named
products.additional_category_id
see:
https://stackoverflow.com/a/21835059/10573560

Argument 1 passed to Illuminate\\Database\\Eloquent\\Model::__construct() must be of the type array, object given

I want to add product to wishlist and following repository pattern to store product id and user id of the user who wants to add product to his wishlist but when i run my code i get
Argument 1 passed to
Illuminate\Database\Eloquent\Model::__construct() must be of the
type array, object given, called in .... WishlistRepository.php
This is my Code:
WishlistController.php
namespace App\Http\Controllers\Site;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Contracts\WishlistContract;
class WishlistController extends Controller
{
protected $wishlistRepository;
public function __construct(WishlistContract $wishlistRepository)
{
$this->wishlistRepository = $wishlistRepository;
}
public function show()
{
$wishlist = $this->wishlistRepository->listWishlist();
return view('site.pages.wishlist', compact('wishlist'));
}
public function addToWishlist(Request $request)
{
$productID=$request->p_id;
$userID=auth()->user()->id;
$data=array('product_id'=>$productID,'user_id'=>$userID);
$wishlist = $this->wishlistRepository->addToWishlist($data);
}
}
WishlistContract.php
<?php
namespace App\Contracts;
/**
* Interface WishlistContract
* #package App\Contracts
*/
interface WishlistContract
{
/**
* #param string $order
* #param string $sort
* #param array $columns
* #return mixed
*/
public function listWishlist(string $order = 'id', string $sort = 'desc', array $columns = ['*']);
/**
* #param array $params
* #return mixed
*/
public function addToWishlist(array $params);
/**
* #param $id
* #return mixed
*/
//public function deleteFromWishlist($id);
/**
* #param array $params
* #return bool
*/
//public function updateWishlist(array $params);
}
?>
WishlistRepository.php
<?php
namespace App\Repositories;
use App\Models\Wishlist;
use App\Traits\UploadAble;
use Illuminate\Http\UploadedFile;
use App\Contracts\WishlistContract;
use Illuminate\Database\QueryException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
/**
* Class WishlistRepository
*
* #package \App\Repositories
*/
class WishlistRepository extends BaseRepository implements WishlistContract
{
use UploadAble;
public function __construct(Wishlist $model)
{
parent::__construct($model);
$this->model = $model;
}
public function listWishlist(string $order = 'id', string $sort = 'desc', array $columns = ['*'])
{
return $this->all($columns, $order, $sort);
}
public function addToWishlist(array $params)
{
try {
$collection = collect($params);
$wishlist = new Wishlist($collection);
$wishlist->save();
return $wishlist;
} catch (QueryException $exception) {
throw new InvalidArgumentException($exception->getMessage());
}
}
public function removefromWishlist($id)
{
$wishlist = $this->findAttributeById($id);
$wishlist->delete();
return $wishlist;
}
public function updateToWishlist(array $params)
{
$wishlist = $this->findWishlistById($params['id']);
$collection = collect($params)->except('_token');
$is_filterable = $collection->has('is_filterable') ? 1 : 0;
$is_required = $collection->has('is_required') ? 1 : 0;
$merge = $collection->merge(compact('is_filterable', 'is_required'));
$wishlist->update($merge->all());
return $wishlist;
}
}
?>
view (script):
$('body').on('click', '.wishlist', function(e){
e.preventDefault();
var product_id=$(this).attr('data-wishlist');
jQuery.ajax({
url: "{{ url('/add-wishlist') }}",
method: 'post',
data: {
"p_id": product_id,"_token": "{{ csrf_token() }}",
},
success: function(result){
// input.val(result.status);
}});
});
You may fix it by removing this line
$collection = collect($params);
You don't need it : because collect will convert your array to Illuminate\Support\Collection object.
Class WishlistRepository
public function addToWishlist(array $params) {
try {
$wishlist = new Wishlist($params);
// OR
// $wishlist = new Wishlist();
// $wishlist->column = $params['column'];
//...
$wishlist->save();
return $wishlist;
} catch (QueryException $exception) {
throw new InvalidArgumentException($exception->getMessage());
}
}
public function addToWishlist(array $params)
{
try {
$collection = collect($params);
$wishlist = new Wishlist($collection);
$wishlist->save();
return $wishlist;
} catch (QueryException $exception) {
throw new InvalidArgumentException($exception->getMessage());
}
}
You are passing $collection to a model whe it's expecting array with values.
When you are making the new instance of Wishlist pass in the array as it is, instead of creating and passing a collection
public function addToWishlist(array $params)
{
try {
return (new Wishlist($params))->save();
} catch (QueryException $exception) {
throw new InvalidArgumentException($exception->getMessage());
}
}

The "Parent" property does not appear in "Example Value" with the denormalizationContext group

I use api-platform v3 and symfony v5. I have problem with displayed properties.
For examle we have simple entity class Category:
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource()
* #ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
*/
class Category
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="children")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Category", mappedBy="parent")
*/
private $children;
public function __construct()
{
$this->children = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getParent(): ?self
{
return $this->parent;
}
public function setParent(?self $parent): self
{
$this->parent = $parent;
return $this;
}
/**
* #return Collection|self[]
*/
public function getChildren(): Collection
{
return $this->children;
}
public function addChild(self $child): self
{
if (!$this->children->contains($child)) {
$this->children[] = $child;
$child->setParent($this);
}
return $this;
}
public function removeChild(self $child): self
{
if ($this->children->contains($child)) {
$this->children->removeElement($child);
// set the owning side to null (unless already changed)
if ($child->getParent() === $this) {
$child->setParent(null);
}
}
return $this;
}
}
So far, we see the correct and logical "Example Value":
Now I want to display the title and parent properties for reading and writing. To do this, I enter group annotations:
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* normalizationContext={"groups" = {"category:read"}},
* denormalizationContext={"groups" = {"category:write"}}
* )
* #ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
*/
class Category
{
//...
/**
* #ORM\Column(type="string", length=255)
* #Groups({"category:read", "category:write"})
*/
private $title;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="children")
* #Groups({"category:read", "category:write"})
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Category", mappedBy="parent")
*/
private $children;
//...
}
After that, we see the "title" property in the swagger documentation. But the "parent" property is not visible:
Why can't I see the "parent" property in the "Example value" section?
As temporary solution I describe the documentation swagger:
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource(
* collectionOperations={
* "get",
* "post" = {
* "sequrity" = "is_granted('ROLE_ADMIN')",
* "openapi_context" = {
* "requestBody" = {
* "content" = {
* "application/json" = {
* "schema" = {
* "type" = "object",
* "required" = {
* "title"
* },
* "properties" = {
* "title" = {
* "type" = "string"
* },
* "parent" = {
* "type" = "string"
* }
* }
* }
* }
* }
* }
* }
* }
* },
* normalizationContext={"groups" = {"category:read"}},
* denormalizationContext={"groups" = {"category:write"}}
* )
* #ORM\Entity(repositoryClass="App\Repository\CategoryRepository")
*/
class Category
{
//...
}
I want to know how to do it right.
Why groups do not work for "parent" property?
Had the same issue right now. Try to use annotation #ApiProperty(readableLink=false) for $parent property.
/**
* #ORM\ManyToOne(targetEntity=CounterpartCategory::class, inversedBy="children")
* #ORM\JoinColumn(nullable=true, onDelete="CASCADE")
* #Groups({"category:read", "category:write"})
* #ApiProperty(readableLink=false)
*/
private ?self $parent;

laravel pivot table column not found while try to update

Problem is when I try to update the book table, it shows error
unknown column 'publisher'
I have a book_publisher pivot table.
What code do I have to write and where do I have to write it?
class Book extends Model
{
// protected table='book';
public function authors()
{
return $this->belongsToMany(Author::class)->withPivot('type');
}
// public function author($type)
// {
//
// return $this->authors()->where('type', $type)->first();
// }
public function author()
{
return $this->authors()->where('type', 'Author')->first();
}
public function illustrator()
{
return $this->authors()->where('type', 'Illustrator')->first();
}
public function translator()
{
return $this->authors()->where('type', 'Translator')->first();
}
public function editor()
{
return $this->authors()->where('type', 'Editor')->first();
}
// foreach ($book->authors as $author)
// {
// $author->type;
// }
public function publishers()
{
return $this->belongsToMany(Publisher::class);
}
}
bookcontroller
public function edit($id)
{
$book=Book::findOrFail($id);
$category=Category::pluck('name', 'id');
$publishers=Publisher::all();
foreach($publishers as $publisher)
{
$publisher->id=$publisher->name;
}
return view('books.edit', compact('book','category','publishers'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
$book=Book::findOrFail($id);
$book->Update($request->all());
Book::find($id)->publisher()->updateExistingPivot($request->only('publisher_id'));
return redirect('books');
}
Please also tell if I have to edit edit.blade.php as well.
Check these ways
$books = Book::find($id);
$books->publisher()->updateExistingPivot('publisher_id',
['publisher_id' => publisher_id],false));
or something like this
$books = Book::find($id);
$publisher = $books->publisher;
$publisher->pivot->publisher_id = $request->publisher_id;
$publisher->pivot->save();

Resources