I am using bundle omines/datatables-bundle to create tables in my Symfony application. When I create custom query that left joins with a field that has Many to Many relationship it returns too many rows.
I am using Symfony 4.2 and omines/datatables-bundle bundle. The end result it that I have wrong number of total results found and many blank pages in my table.
This is how my table is being created
class TestTableType implements DataTableTypeInterface
{
public function configure(DataTable $dataTable, array $options)
{
$dataTable
->add('id',
NumberColumn::class,
array(
'label' => 'ID',
'globalSearchable' => false
)
)
->createAdapter(ORMAdapter::class,
array(
'entity' => Test::class,
'query' => function (QueryBuilder $builder)
{
$builder
->distinct()
->select('t')
->from(Test::class, 't')
->leftJoin('t.products', 'prod');
}
)
)
;
}
}
and this is how Many to Many relationship is defined in my entity class.
**
* #ORM\ManyToMany(targetEntity="App\Entity\Product", inversedBy="tests")
* #ORM\JoinTable(name="product_has_test")
*/
private $products;
public function __construct()
{
$this->products = new \Doctrine\Common\Collections\ArrayCollection();
}
along with getters and setters
public function addProduct(\App\Entity\Product $product)
{
$this->products[] = $product;
return $this;
}
public function removeProduct(\App\Entity\Product $product)
{
$this->products->removeElement($product);
}
public function getProducts()
{
return $this->products;
}
What might be the cause of it? And how can I fix it?
Related
When I run the code I get no error but the data I am trying to display is not displaying it's just blank.. can someone tell me what I'm doing wrong?
My controller:
public function openingPage($id) {
$this->getGames();
$games = $this->getGames();
return view('caseopener')->with('games',$games);
}
private function getGames() {
$games = array();
foreach ($this->data->items as $item) {
$game = new Game($item);
$games[] = array(
'id' => $game['id'],
'name' => $game['name'],
'price' => $game['price'],
'image' => $game['image'],
);
}
return $games;
}
The 'Game' Model that is used in 'getGames function':
class Game extends Model
{
private $id;
public $data;
public function __construct($id) {
parent::__construct();
$this->id = $id;
$this->data = $this->getData();
}
private function getData() {
$game = DB::table('products')->where('id', 1)->first();
if(empty($game)) return array();
return $game;
}
}
The view:
#foreach ($games as $game)
<div class="gold">$ {{ $game['price'] }}</div>
#endforeach
I think you are over-complicating things. You could simplify your flow like this:
Given your provided code, it seems like you are using a custom table name ('products') in your Game model. So we'll address this first:
Game.php
class Game extends Model
{
protected $table = 'products'; //
}
Now, it seems like you're searching an array of Game ids ($this->data->items). If so, you could make use of Eloquent for your query, specially the whereIn() method:
YourController.php
public function openingPage($id)
{
$games = Game::whereIn('id', $this->data->items)->get();
return view('caseopener')->with('games', $games);
}
Optionally, if you want to make sure of just returning the id, name, price and image of each Game/product, you could format the response with API Resources:
php artisan make:resource GameResource
Then in your newly created class:
app/Http/Resources/GameResource.php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class GameResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'price' => $this->price,
'image' => $this->image,
];
}
}
So now just update your controller:
YourController.php
use App\Http\Resources\GameResource;
public function openingPage($id)
{
$games = Game::whereIn('id', $this->data->items)->get();
return view('caseopener')->with('games', GameResource::collection($games));
} // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
thank you view my question.
I would like to retrieve information on the tag table relation with the store with many-to-many when searching for a category
I created Store-table, Category-table, Tag-table.
The store-table and the category-table are connected by a many-to-many relation. The tag-table is the same.
I was able to search for categories and get information on businesses that are relation- ed, but I do not know how to get information on tags that are relations with stores.
So, I try this idea. search categories → get storeID from relation data→ storeID search → return shop data that hit.
However, I do not know how to get storeID in the store data acquired by category search
How can I write the code?
please help me.
sorry, bat my English.
App\Store
use Illuminate\Database\Eloquent\Model;
class Store extends Model
{
protected $fillable = ['name','location', 'price', 'open_time',
'closed_day'];
protected $table = 'stores';
public function photos(){
return $this->hasMany(StorePhoto::class);
}
public function categories(){
return $this->belongsToMany(Category::class,'category_store','category_id','store_id');
}
public function tags(){
return $this->belongsToMany(Tag::class, 'store_tag', 'tag_id', 'store_id');
}
}
App\Category
protected $fillable = ['store_id', 'category_id'];
public function stores()
{
return $this->belongsToMany(Store::class,'category_store','store_id','category_id');
}
App\Tag
protected $fillable = ['store_id', 'tag_id'];
public function stores()
{
return $this->belongsToMany(Store::class, 'store_tag', 'store_id', 'tag_id');
}
Resource/Category
class Category extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'store' => $this->stores,
];
}
}
web.php
use App\Category;
use App\Http\Resources\Category as CategoryResource;
Route::get("/store/api/category", function (Request $request) {
$search_category = $request->get('category_id');
return new CategoryResource(Category::find($search_category));
});
You can use dot notation to eager load nested relations:
$category = Category::with('stores.tags')->find($request->get('category_id'));
The tags will then be accessible on each Store model related to the Category:
// create a single flattened array of all the tags
$tags = $category->stores->flatMap->tags;
I have two entities Categories and Criteria that are linked by ManyToMany relationship. It generated a new table named as criteria_categories in the database.
What i want to do is to use fixture to populate the entity Criteria and the table criteria_categories.
The categories table has already data in the database.
So my problem is, how to get the data from categories and insert them using fixtures into the criteria_categories table?
My code is as follow:
Criteria
class Criteria
{
/**
* #ORM\ManyToMany(targetEntity="Categories", inversedBy="criteria", cascade={"persist"})
* #ORM\JoinTable(name="criteria_categories")
**/
private $categories;
}
Categories
class Categories
{
/**
* #ORM\ManyToMany(targetEntity="Criteria", mappedBy="categories")
**/
private $criteria;
}
DataFixtures
class LoadCriteria extends Fixture
{
public function load(ObjectManager $manager)
{
$criteria = array(
array(
'label' => 'Test1'
),
array(
'label' => 'Test2'
)
);
$cat = new Categories();
foreach ($criteria as $critere) {
$ctr = new Criteria();
$ctr->setCriteriaLabel($critere['label']);
$manager->persist($ctr);
}
$manager->flush();
}
}
So the real question is how to get the data from categories and use them here in this fixture to populate the table criteria_categories?
Thanks in advance for your answer.
In doctrine you can forget on criteria_categories table. The class criteria has a collection of categories. Don't need to worry about additional tables used behind the scenes.
But to your question. To get all categories from the db, you have to define this fixture as a service and then inject an entity manager or your "wrapper" service.
class LoadCriteria extends Fixture
{
/**
* #var CategoriesRepository
*/
private $repository;
public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository(Categories::class);
}
public function load(ObjectManager $manager)
{
$this->categories = $repository->findAll();
$criteria = array(
array(
'label' => 'Test1'
),
array(
'label' => 'Test2'
)
);
$cat = new Categories();
foreach ($criteria as $critere) {
$ctr = new Criteria();
$ctr->setCriteriaLabel($critere['label']);
$manager->persist($ctr);
}
$manager->flush();
}
}
If you use default service configuration from symfony 3.3+, your fixture is already a service.
If you don't use default service configuration, you have to define the fixture as service manually by.
#services.yml
App\DataFixtures\ORM\CriteriaFixture:
tags: [doctrine.fixture.orm]
last couple of days I've been busy making a form using Doctrine and MongoDB. Companies should be able to reserve tables, chairs, .. at a certain event by use of this form. The snippet below shows the controller for this form.
The 'ObjectMap' object maps the amount of a certain object to the object itself. The controller creates all the 'ObjectMap' objects, and adds them to the company object. However, the 'ObjectMap' objects are persisted by Doctrine (they show up in the database) but the company object isn't modified at all, there is no database request made by MongoDB. The persist() function seems to have no effect at all.
public function logisticsAction(Company $company)
{
$form = $this->createForm(new LogisticsForm($this->getDoctrine()->getManager()), $company);
if ($this->getRequest()->isMethod('POST')) {
$form->bind($this->getRequest());
if ($form->isValid()) {
$formData = $this->getRequest()->request->get('_company_logistics_edit');
$objects = $this->getDoctrine()->getManager()
->getRepository('Jobfair\AppBundle\Document\Company\Logistics\Object')
->findAll();
foreach($objects as $object) {
$requirement = $formData['objectRequirement_'.$object->getId()];
$map = new ObjectMap($requirement, $object);
$this->getDoctrine()->getManager()->persist($map);
$company->addObjectMap($map);
//print_r($company->getObjectMaps());
}
$this->getDoctrine()->getManager()->persist($company);
$this->getDoctrine()->getManager()->flush();
$this->getRequest()->getSession()->getFlashBag()->add(
'success',
'The information was successfully updated!'
);
return $this->redirect(
$this->generateUrl(
'_company_settings_logistics',
array(
'company' => $company->getId(),
)
)
);
}
}
The Company object is defined here:
class Company{
/**
* #ODM\Id
*/
private $id;
/*
* #ODM\ReferenceMany(targetDocument="Jobfair\AppBundle\Document\Company\Logistics\ObjectMap", cascade={"persist", "remove"})
*/
private $objectMaps;
public function __construct($name = null, $description = null)
{
$this->objectMaps = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getObjectMaps()
{
return $this->objectMaps;
}
public function getObjectsArray()
{
$objects = array();
foreach($this->objectMaps as $map)
$objects[] = array(
'name' => $map->getObject()->getName(),
'amount' => $map->getRequirement()
);
return $objects;
}
public function addObjectMap(ObjectMapDocument $objectMap)
{
$this->objectMaps[] = $objectMap;
}
public function removeObject(ObjectMapDocument $objectMap)
{
$this->objectMaps->removeElement($objectMap);
}
}
I'm trying to use Moltin Cart in my Laravel 4 app:
I installed Moltin Cart through composer,
then added the Service Provider ('Moltin\Cart\CartServiceProvider')
and added the aliases ('Cart' => 'Moltin\Cart\Facade').
Now I want only logged in users to access the cart so I added
$this->beforeFilter('auth', array('only' => 'postAddToCart', 'getCart', 'getRemoveItem'));
in my storeController.
But I get this error when I try to access
Declaration of Moltin\Cart\Storage\LaravelSession::insertUpdate() must be compatible with Moltin\Cart\StorageInterface::insertUpdate(Moltin\Cart\Item\Line $item)
My Store Controller is :
<?php
class StoresController extends \BaseController {
public function __construct()
{
parent::__construct();
$this->beforeFilter('csrf', array('on' => 'post'));
$this->beforeFilter('auth', array('only' => 'postAddToCart', 'getCart', 'getRemoveItem'));
}
public function getIndex()
{
return View::make('stores.index')
->with('products', Product::take(4)->orderBy('created_at', 'DESC')->get());
}
public function getView($id)
{
return View::make('stores.view')
->with('product', Product::find($id));
}
public function getCategory($category_id)
{
return View::make('stores.category')
->with('products', Product::where('category_id', '=', $category_id)->paginate(6))
->with('category', Category::find($category_id));
}
public function getSearch()
{
$keyword = Input::get('keyword');
return View::make('stores.search')
->with('products', Product::where('title', 'LIKE', '%'. $keyword . '%')->get())
->with('keyword', $keyword);
}
public function postAddToCart()
{
$product = Product::find(Input::get('id'));
$qunatity = Input::get('qunatity');
Cart::insert(array(
'id' => $product->id,
'name' => $product->name,
'price' => $product->price,
'qunatity' => $qunatity,
'image' => $product->image
));
return Redirect::to('store/cart');
}
public function getCart()
{
return View::make('stores.cart')->with('products', Cart::contents());
}
public function getRemoveItem($identifier)
{
$product = Cart::item($identifier);
$product->remove();
return Redirect::to('store/cart');
}
}
The short answer:
Resume your installation assuming that moltin/cart and moltin/laravel-cart repositories are in sync.
The long answer:
As the error message states:
Moltin\Cart\StorageInterface::insertUpdate(Moltin\Cart\Item\Line $item)
Moltin\Cart\Storage\LaravelSession::insertUpdate()
don't have the same signature.
They should be in sync! The issue has nothing to do at all with your StoresController.
I checked:
https://github.com/moltin/cart/blob/master/src/Moltin/Cart/StorageInterface.php and
https://github.com/moltin/laravel-cart/blob/master/src/Moltin/Cart/Storage/LaravelSession.php
I find out that the signatures are OK as the time of my answer post.
namespace Moltin\Cart;
interface StorageInterface
{
/**
* Add or update an item in the cart
*
* #param Item $item The item to insert or update
* #return void
*/
public function insertUpdate(Item $item); // <<<< This is it!
...
}
namespace Moltin\Cart\Storage;
use Moltin\Cart\Item;
...
class LaravelSession implements \Moltin\Cart\StorageInterface
{
...
/**
* Add or update an item in the cart
*
* #param Item $item The item to insert or update
* #return void
*/
public function insertUpdate(Item $item) // <<<< This is it!
{
...
}
...
}
My guess is that you did your install when the repositories (knowing that moltin/cart is a dependency of moltin/laravel-cart) were not in sync for some reason.