Call to undefined relationship [categories] on model [App\Product] - laravel-7

I have three tables (products, categories, sizes) and models (Product, Category, Size) respectively.
In my product table I saved category_id and size_id respectively.
For list view I want to fetch category_name from category table and size_name using size table respectively.
I am using relation for that purpose. Below is model structure of relationship.
Product:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
public function category()
{
return $this->belongsTo(Category::class);
}
public function size()
{
return $this->belongsTo(Size::class);
}
}
Category:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
public function product()
{
return $this->hasMany(Product::class);
}
}
Size:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Size extends Model
{
public function product()
{
return $this->hasMany(Product::class);
}
}
Below is my controller where I want fetch data with category name and size name. Then want to send data to list view with category name and size name to display:
public function productList()
{
// $product = Product::get();
$data = Product::with('categories','sizes')->get();
echo "<pre>";
//print_r($product->category->name);
// return view('admin.productlist',['productdata' => $data]);
}
Below is my migration file of product:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('product_name');
$table->string('product_category')->nullable();
$table->string('product_price');
$table->string('product_size')->nullable();
$table->string('product_stock')->nullable();
$table->string('product_description')->nullable();
$table->string('created_user_id')->nullable();
$table->timestamps();
});
Size migration:
Schema::create('sizes', function (Blueprint $table) {
$table->id();
$table->string('product_size');
$table->timestamps();
});
Category Migration :
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Anyone have any idea what I am doing wrong then please help me in that.
My list blade file is below:
#foreach ($productdata as $product)
<tr>
<td>{{$product->product_name}}</td>
<td>{{$product->product_category}}</td>
<td>{{$product->product_size}}</td>
<td>{{$product->product_price}}</td>
</tr>
#endforeach

Related

How can cart table associate with another table?

I have table table_name(id, cart_token, data , created_at, updated_at ) that wants to associate with shopware cart table using token column (table_name.cart_token = cart.token).
How can we do this association using DAL as long as cart table doesn't have a CartEntity and CartDefinition.
For example: Select * from table_name leftjoin cart on table_name.cart_token=cart.token where cart.token=null.
Without a definition and accompanying entity class you simply won't be able to retrieve the cart as a mapped object using the DAL. You could add your own definition and entity for the cart table but I wouldn't recommend it, as this would just cause problems if multiple extensions got the same idea. I would recommend injecting Doctrine\DBAL\Connection in a service of your plugin and just fetching the cart using raw SQL.
class CartFetcherService
{
private Connection $connection;
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
public function fetchCart(YourCustomEntity $entity): ?array
{
$cart = $this->connection->fetchAssociative(
'SELECT * FROM `cart` WHERE `token` = :token',
[
'token' => $entity->getToken(),
]
);
return $cart ?: null;
}
}
If you want to retrieve the Cart object directly, you could also inject the Shopware\Core\Checkout\Cart\CartPersister service to load the cart.
class CartLoaderService
{
private CartPersister $persister;
public function __construct(CartPersister $persister)
{
$this->persister = $persister;
}
public function getCart(YourCustomEntity $entity, SalesChannelContext $context): ?Cart
{
try {
$cart = $this->persister->load($entity->getToken(), $context)
} catch (\Throwable $exception) {
$cart = null;
}
return $cart;
}
}

how to make laravel export excel without model

i have already read laravel-export excel. but my project is different, where my project didn't have model. how to make export excel in laravel without make model? laravel8 and maatwebsite3
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
class ExportExcel implements FromCollection
{
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
//
}
}
what should I type in export controller, exportexcel and the download button
You could always import using DB facade.
public function collection(Collection $rows)
{
foreach ($rows as $row)
{
DB::table('users')->insert([
'email' => $row[0],
]);
}
}
Alternatively you would always create empty shell models, to do insertions. I often do this, if i have to cleanup wordpress data and want the Laravel facades for ease of use.
use Illuminate\Database\Eloquent\Model;
class User extends Model {
protected $fillable = ['name'];
}
Which would enable the following from the documentation to work.
public function model(array $row)
{
return new User([
'name' => $row[0],
]);
}

Node.js and sequelize-typescript - data access objects and business objects

I am using the sequelize-typescript in my Node.js service
I have the Category class which maps to category table
import { Model, Table, Column } from "sequelize-typescript";
#Table
export class Category extends Model<Category>{
#Column
name: string
}
I also have CategoryController and CategoryService
export class CategoryController {
...
async getAll(request: Request, response: Response) {
let categories = await this.categoryService.getCatergories();
response.json(categories)
}
}
export class CategoryService {
async getCatergories(): Promise<Category[]> {
let categories = await Category.findAll<Category>()
return categories
}
}
And everything is as it should be.
But returning a Category to the controller allows it to use the use the inherited methods from the model class like:
export class CategoryController {
...
async getAll(request: Request, response: Response) {
let categories = await this.categoryService.getCatergories();
// Remove associated row in the database
categories[0].destroy()
response.json(categories)
}
}
I was thinking to create a CategoryModel class like this:
export class CategoryModel {
id : number
name : string
}
And modify all methods in CategoryService to return CategoryModel instances instead of Category and rename Category to CategoryEntity
What is the best way to deal with such a problem?
Use toJSON() of Category instance to get "a JSON representation" of the instance.
See sequelize docs for more information: http://docs.sequelizejs.com/class/lib/model.js~Model.html#instance-method-toJSON
Additionally you could add an interface to achieve type safety for the return value of toJSON() instead of defining another class:
interface ICategory {
id: number;
name: string;
}
#Table
export class Category extends Model<Category> implements ICategory{
#Column
name: string
}
Using toJSON():
Category.findOne(result => {
const category: ICategory = result.toJSON();
});

Laravel : pivot table point to multiple tables

lets say i have an orders table that is going to have a many-to-many relation to three other tables named typings, translates and theses . I know pivot table should be somehow like many to many polymorphic relation but that is not exactly what im looking for.
how should i implement pivot table?
You would create a polymorphic relationship with orders and the other three tables through a pivot table named orderables
// TABLES NEEDED
orders
id - integer
typings
id - integer
translates
id - integer
theses
id - integer
orderables
order_id - integer
orderable_id - integer
orderable_type - string
// MODELS/RELATIONSHIPS NEEDED
class Typing extends Model
{
public function orders()
{
return $this->morphToMany('App\Order', 'orderable');
}
}
class Translate extends Model
{
public function orders()
{
return $this->morphToMany('App\Order', 'orderable');
}
}
class Thesis extends Model
{
public function orders()
{
return $this->morphToMany('App\Order', 'orderable');
}
}
class Order extends Model
{
public function typings()
{
return $this->morphedByMany('App\Typing', 'orderable');
}
public function translates()
{
return $this->morphedByMany('App\Translate', 'orderable');
}
public function theses()
{
return $this->morphedByMany('App\Thesis', 'orderable');
}
}
Then, you could get the orders of a model like this:
$thesis = Thesis::find(1);
$orders = $thesis->orders;
And the inverse:
$order = Order::find(1);
$theses = $order->theses;

Form: Avoid setting null to non submitted field

I've got a simple model (simplified of source):
class Collection
{
public $page;
public $limit;
}
And a form type:
class CollectionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('page', 'integer');
$builder->add('limit', 'integer');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'FSC\Common\Rest\Form\Model\Collection',
));
}
}
My controller:
public function getUsersAction(Request $request)
{
$collection = new Collection();
$collection->page = 1;
$collection->limit = 10;
$form = $this->createForm(new CollectionType(), $collection)
$form->bind($request);
print_r($collection);exit;
}
When i POST /users/?form[page]=2&form[limit]=20, the response is what i expect:
Collection Object
(
[page:public] => 2
[limit:public] => 20
)
Now, when i POST /users/?form[page]=3, the response is:
Collection Object
(
[page:public] => 3
[limit:public] =>
)
limit becomes null, because it was not submitted.
I wanted to get
Collection Object
(
[page:public] => 3
[limit:public] => 10 // The default value, set before the bind
)
Question: How can i change the form behaviour, so that it ignores non submitted values ?
If is only a problem of parameters (GET parameters) you can define the default value into routing file
route_name:
pattern: /users/?form[page]={page}&form[limit]={limit}
defaults: { _controller: CompanyNameBundleName:ControllerName:ActionName,
limit:10 }
An alternative way could be to use a hook (i.e. PRE_BIND) and update manually that value into this event. In that way you haven't the "logic" spreaded into multi pieces of code.
Final code - suggested by Adrien - will be
<?php
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
class IgnoreNonSubmittedFieldSubscriber implements EventSubscriberInterface
{
private $factory;
public function __construct(FormFactoryInterface $factory)
{
$this->factory = $factory;
}
public static function getSubscribedEvents()
{
return array(FormEvents::PRE_BIND => 'preBind');
}
public function preBind(FormEvent $event)
{
$submittedData = $event->getData();
$form = $event->getForm();
// We remove every child that has no data to bind, to avoid "overriding" the form default data
foreach ($form->all() as $name => $child) {
if (!isset($submittedData[$name])) {
$form->remove($name);
}
}
}
}
Here's a modification of the original answer. The most important benefit of this solution is that validators can now behave as if the form post would always be complete, which means there's no problems with error bubbling and such.
Note that object field names must be identical to form field names for this code to work.
<?php
namespace Acme\DemoBundle\Form;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;
class FillNonSubmittedFieldsWithDefaultsSubscriber implements EventSubscriberInterface
{
private $factory;
public function __construct(FormFactoryInterface $factory)
{
$this->factory = $factory;
}
public static function getSubscribedEvents()
{
return array(FormEvents::PRE_BIND => 'preBind');
}
public function preBind(FormEvent $event)
{
$submittedData = $event->getData();
$form = $event->getForm();
// We complete partial submitted data by inserting default values from object
foreach ($form->all() as $name => $child) {
if (!isset($submittedData[$name])) {
$obj = $form->getData();
$getter = "get".ucfirst($name);
$submittedData[$name] = $obj->$getter();
}
}
$event->setData($submittedData);
}
}

Resources