Výběr dat z více tabulek (uživatelská cena k produktu)
- Ages
- Člen | 128
Zdravím,
nějak nemohu přijít na to jak co nejlépe vyřešit problém s výběrem dat
z DB, nějaké řešení mě napadlo, ale je velmi kostrbaté.
Nemohl by mi někdo prosím poradit? Potřeboval bych vybrat z DB k produktům
i uživatelskou cenu, která nemusí ale může existovat.
Tedy potřebuji z tabulky product vybrat řádky a k nim i cenu z tabulky product_price pokud má uživatel user nastaven nejaký ceník pricelist a ta cena je zadána.
Používám Database Explorer a ideálně bych to chtěl řešit na úrovni modelu abych se s tím nemusel trápit v šablonách.
user
id
name
pricelist_id
…
pricelist
id
name
…
product_price
id
price
product_id
pricelist_id
…
product
id
code
price
…
Předem děkuji za jakékoli nápady!
- mlk
- Člen | 5
Tu je nejaky pokus, avsak ako chces selectovat data?
Tento model nizsie ti zduplikuje produkty tolkokrat, kolko je (pocet cennikov *
pocet uzivatelov), preto je vhodne vyberat cennik, uzivatela a nasledne az
produkty (WHERE statement)
$user = 'user'; // u
$product = 'product'; // p
$product_price = 'product_price'; // pp
$pricelist = 'pricelist'; // pl
$product_code = 'CODE-XXX'; // vyber produktu podla code
$this->database->query('
SELECT
pl.name as pricelist_name,
u.name as user_name,
pp.price as user_price,
p.*
FROM
?name p
LEFT JOIN ?name pp ON p.id = pp.product_id' . // pocet_riadkov = (pocet_produktov * pocet_cennikov) + pocet_produktov_bez_cennika
'LEFT JOIN ?name u ON pp.pricelist_id = u.pricelist_id' . // pocet_riadkov = (pocet_produktov * pocet_cennikov * pocet_uzivatelov) + pocet_produktov_bez_cennika
'LEFT JOIN ?name pl ON pp.pricelist_id = pl.id' . // pocet_riadkov = (pocet_produktov * pocet_cennikov * pocet_uzivatelov) + pocet_produktov_bez_cennika
'WHERE p.code = ?
',$product,$product_price,$user,$pricelist,$product_code)->fetchAll();
Pri tabulkach product, user a pricelist predpokladam, ze ID je unikatne.
Ked pozuijes WHERE p.code, tak sa ti zahrnu aj produkty, ktore nemusia mat cennik, pripadne produkty s cennikom, ktore nemusia mat uzivatela.
- Ages
- Člen | 128
@mlk děkuji za reakci
Možná jsem do toho nemusel motat toho uživatele to lze vyřešit předchozím
dotazem, v podstatě potřebuji vybrat produkty a k nim cenu
z product_price ale mám k tomu dvě podmínky
product_id a pricelist_id
nyní to mám řešeno přímo v šabloně takto:
{var $customPrice = $product->related('product_price')->where('pricelist_id', $complUser->pricelist->id)->fetch()}
ale chtěl bych ty data vydolovat ideálně v jednom dotazu přímo v modelu.
Editoval Ages (15. 5. 2018 11:29)
- mlk
- Člen | 5
MODEL:
<?php
namespace App\Model;
use Nette;
use Nette\Caching;
class Repository extends Nette\Object
{
const P_TBL = 'product';
const PP_TBL = 'product_price';
const U_TBL = 'user';
const PL_TBL = 'pricelist';
/** @var Nette\Database\Context */
private $database;
/** @var Caching\Cache */
private $caching;
public function __construct(Nette\Database\Connection $database, Caching\IStorage $storage)
{
$this->database = $database;
$this->caching = new Caching\Cache($storage, 'Repository');
}
public function getData($debug = FALSE)
{
$data = NULL;
$key = 'product-pricelist-cache'
if ($debug == FALSE)
{
$data = $this->caching->load($key);
}
if ($data === null) {
$data = $this->database->query('
SELECT
u.name as user_name,
pp.pricelist_id as pricelist_id,
pp.price as new_user_price,
p.*
FROM
?name p
LEFT JOIN ?name pp ON p.id = pp.product_id' . // pocet_riadkov = (pocet_produktov * pocet_cennikov) + pocet_produktov_bez_cennika
'LEFT JOIN ?name u ON pp.pricelist_id = u.pricelist_id' . // pocet_riadkov = (pocet_produktov * pocet_cennikov * pocet_uzivatelov) + pocet_produktov_bez_cennika
'LEFT JOIN ?name pl ON pp.pricelist_id = pl.id' . // pocet_riadkov = (pocet_produktov * pocet_cennikov * pocet_uzivatelov) + pocet_produktov_bez_cennika
,self::P_TBL,self::PP_TBL,self::U_TBL,self::PL_TBL)->fetchAll();
$this->caching->save($key, $data, [Caching\Cache::EXPIRE => '20 minutes']); // refresh time
}
return $data;
}
public function getProductUserPrice($user_name, $pricelist_id, $product_id, $debug = FALSE) // FALSE = vynecha cache v getData()
{
$filter = [];
$data = $this->getData($debug);
if (!is_null($data)) {
foreach ($data as $i) {
if ($i['user_name'] == $user_name AND $i['pricelist_id'] == $pricelist_id AND $i['id'] == $product_id) {
$filter = $i;
}
}
}
return $filter;
}
}
PRESENTER:
<?php
namespace App\Presenters;
use Nette;
use App\Model\Repository as repo;
class ProductPresenter extends Nette\Application\UI\Presenter
{
/** @var repo */
protected $productpriceRepo;
public function __construct(repo $productpriceRepo)
{
parent::__construct();
$this->productpriceRepo = $productpriceRepo;
}
protected function startup()
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Home:default');
}
}
public function renderProductPrice($pricelist_id, $product_id, $debug = FALSE)
{
$user_id = $this->getUser()->getId(); // v tomto pripade je id = meno a je definovane priamo v config.neon
$data = $this->productpriceRepo->getProductUserPrice($user_id, $pricelist_id, $product_id, $debug);
$this->template->data = $data;
$this->template->user_id = $user_id;
}
}
CONFIG.NEON:
security:
users:
user_id: tazke-heslo
database:
default:
dsn: 'mysql:host=localhost;dbname=public'
user: root
password:
services:
- App\Model\Repository
LATTE:
{block content}
<h1>Renderovana tabulka cien pre {$user_id}:</h1>
{if count($data)>0}
<table>
<tr>
<td><b>PRODUCT_ID</b></td>
<td><b>PRICE</b></td>
<td><b>USER_PRICE</b></td>
{*} a tak dalej .... {*}
</tr>
{foreach $data as $i}
<tr>
<td>{$i['id']}</td>
<td>{$i['price']}</td>
<td>{$i['user_price']}</td>
{*} a tak dalej .... {*}
</tr>
{/foreach}
</table>
{else}
{/if}
{/block}
Hadam pomoze aspon trochu :)
Riesim to jednym dotazom na DB, ak to nevyhovuje, bude musiet pomoct este niekto
iny, zatial DB explorer a DiBi moc neovladam :)
Potom si iba zavolaj:
localhost/product/productprice?pricelist_id=&product_id=
pripadne pre vypnutie cacheovania:
localhost/product/productprice?pricelist_id=&product_id=&debug=1 // $debug = TRUE
PS: ak su tam chyby, tak sa ospravedlnujem, netestoval som to
- Ages
- Člen | 128
Děkuji ale také mi to přijde takové kostrbaté, to spiš složím výsledek v modelu do pole, koukal jsem že v OpenCart to řeší také takto :)
btw: v presenteru nemusíš předávat závislost přes
__construct()
stačí takto:
/** @var App\Model\Repository\ProductPriceRepo @inject */
public $repo;
- Ages
- Člen | 128
CZechBoY napsal(a):
OpenCartem bych se radši moc neinspiroval… a konstruktor ve finálních presenterech (MujPresenter) je určitě čistší řešení než inject. Inject se používá jen v abstraktních předcích (BasePresenter).
Snažím se vycházet z dokumentace kde je to uvedeno: