Let's take https://symfony.com/doc/current/forms.html#building-the-form example form but only for Search in tasks list instead of save.
Goal is to allow searches on task, dueDate or both criterias (in my real case, I have 9 criterias)
Here are src/Repository/ResultRepository.php :
class ResultRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Result::class);
}
public function findMultiKeys($task, $dueDate): array
{
$qb = $this->createQueryBuilder('d')
->andWhere('d.task = :task')
->setParameter('task', $task)
->andWhere('d.dueDate = :dueDate')
->setParameter('dueDate', $dueDate)
->getQuery();
return $qb->execute();
}
}
It require both criterias to return result(s)!
I ran a lot of searches and find:
How do I use a complex criteria inside a doctrine 2 entity's
repository?
Symfony2/Doctrine QueryBuilder using
andwhere()
Doctrine2 doc - setParameters method
So I code a $where_string variable to construct my variable where.
and a $parameters to construct my variable parameters array, and my findMultiKeys becomes:
public function findMultiKeys($get_form): array
{
$where_string = '';
$parameters = [];
$task = $get_form->getTask();
if ($task !== null) {
$where_string .= "d.task = :task";
$parameters += array('task' => $task);
}
$dueDate = $get_form->getDueDate();
if ($dueDate !== null) {
if ($where_string !== '')
$where_string .= " AND ";
$where_string .= "d.dueDate = :dueDate";
$parameters += array('dueDate' => $dueDate);
}
$qb = $this->createQueryBuilder('d')
->where($where_string)
->setParameters($parameters)
->getQuery();
return $qb->execute();
}
It works, perhaps not the best way?
In my searches, I found, of course, to use ElasticSearch, perhaps to much to my simple need, or I found PetkoparaMultiSearchBundle
Bests solutions welcomes
I have a proposition :-)
You can build an task4Seach entity with your 9 criteria (without
persistance)
create a form type with this "data_class"
use it to get your datas in your repository
$qb = $this->createQueryBuilder('d');
...
if ($task4Seach ->getDueDate()) {
$qb->andWhere($qb->expr()->eq('d.dueDate', ':dueDate'));
$qb->setParameter('dueDate', $task4Seach->getDueDate());
}
Related
Hello i have 2 tables that i want to call right now, for the EDIT (part of the CRUD)
tables:
table_a
table_b
i found in youtube how to update/edit from 2 tables, i need to call bot of the tables.
here's the code for the model
public function edit_this($ID_A)
{
return $this->db->table('table_a', '*i don't know how to insert the 2nd table')->where('ID_A', $ID_A)->get()->getRowArray();
}
Here's the controller
public function this_edit($ID_A)
{
$data = [
'title' => 'Admin',
'navbartitel' => 'You know this',
'alledit' => $this->theModel->edit_this($ID_A),
'validation' => \Config\Services::validation()
];
return view('this/all/edit', $data);
}
it works but i only can accsess the tabel_a, but i need them both so i can show what i've written in the edit form, from the database
anyone can help? thank you
$this->db->table(...) returns an instance of QueryBuilder and will happily accept a single string of comma-separated tables ("table1, table2..."), or even an array for that matter (['table1', 'table2'...]), as its first parameter. You are doing neither and instead passing multiple parameters.
When you call table(), the value passed in the first parameter is used during the creation of the database-specific Builder class:
public function table($tableName)
{
if (empty($tableName))
{
throw new DatabaseException('You must set the database table to be used with your query.');
}
$className = str_replace('Connection', 'Builder', get_class($this));
return new $className($tableName, $this);
}
The DB-specific Builder class has no constructor of its own so falls back on the __construct defined in BaseBuilder, which it extends:
public function __construct($tableName, ConnectionInterface &$db, array $options = null)
{
if (empty($tableName))
{
throw new DatabaseException('A table must be specified when creating a new Query Builder.');
}
$this->db = $db;
$this->from($tableName);
...
I've truncated this for brevity because the important part is that call to $this->from, which is in the end how multiple tables get processed:
public function from($from, bool $overwrite = false)
{
if ($overwrite === true)
{
$this->QBFrom = [];
$this->db->setAliasedTables([]);
}
foreach ((array) $from as $val)
{
if (strpos($val, ',') !== false)
{
foreach (explode(',', $val) as $v)
{
$v = trim($v);
$this->trackAliases($v);
$this->QBFrom[] = $v = $this->db->protectIdentifiers($v, true, null, false);
}
}
else
{
$val = trim($val);
// Extract any aliases that might exist. We use this information
// in the protectIdentifiers to know whether to add a table prefix
$this->trackAliases($val);
$this->QBFrom[] = $this->db->protectIdentifiers($val, true, null, false);
}
}
return $this;
}
I am trying to create a function to filter different bank transactions, and trying to optimize with 2 parameters but my concatenation with the getter does not work.
Is it a way to write this good.
My entity Transactions has these properties: type ("debit" or "credit"), category (restaurant, food, etc etc), date, amount
I would like to filter with only one function: so I could filter category = restaurant
public function filter($sortOf, $search) {
$transactions = $this->getTransactions();
$transactionsFiltred =[];
foreach ($transactions as $transaction){
if ("$transaction->get . $sortOf()" === $search){
$transactionsFiltred [] = $transaction;
}
dd($transactionsFiltred);
return $transactionsFiltred;
}
}
Thanks
It works with
$getter = 'get' . ucfirst($sortOf) . '()';
if ($transaction->{"get" . $sortOf}() === $search){
}
I am new in Symfony framework And I want to use Query basis on Condition
which is using associative array and I want to use IS NOT NULL But it is not
working.
$repository = $this->getDoctrine()->getRepository('AppBundle:Order');
$order = $repository->findBy(array('status' => $last_status,'new_coloumn_id'=>"IS NOT NULL"));
How to use IS NOT NULL in array.
You should add custom function into your Order Repository file(class). Example;
public function getOrderStatus($last_status = NULL){
$query = $this->createQueryBuilder('order')
->where('order.new_column_id IS NOT NULL')
->andWhere('status = :status')
->setParameter('status', $last_status);
return $query->getQuery()->getResult();
}
And you can use it;
$order = $this->getDoctrine()->getRepository('AppBundle:Order')->getOrderStatus($last_status)
Try this in your repository class:
public function findOrder($last_status){
$qb = $this->createQueryBuilder('order');
return $qb->where($qb->expr()->isNotNull('order.new_column_id'))
->andWhere($qb->expr()->eq('order.status',':last_status'))
->setParameter('last_status',$last_status)
->getQuery()
->getOneOrNullResult();//getArrayResult,getResult()
}
hope it helps...
Alright I have a GeneralModel written in CodeIgniter and a friend asked me if I could convert it into Laravel 4.2 for him. I was working on this and I think I have most of it correct but I am getting stuck at the select statement.
In CodeIgniter I have the following:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE){
if($field != FALSE){
// WHERE in case of FIELD / VAL :)
$this->db->where($field, $val);
}
$query = $this->db->get($table);
if($multiple == 1){
// Multiple rows
return $query->result_array();
} else {
// One row
return $query->row_array();
}
}
Does anyone here knows how I can convert this function into Laravel 4.2 syntax?
I currently have:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE){
$result = DB::table($table);
}
I got stuck pretty quickly since I have no idea how I can achieve the same in Laravel 4.2 with splitting up the sections of the query like I did with CodeIgniter.
You can chain methods in the same way:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE)
{
$query = DB::table($table);
if ($field != FALSE) {
// WHERE in case of FIELD / VAL :)
$query->where($field, $val);
}
if ($multiple)
return $query->get();
else
return $query->first();
}
Laravel is similar in that you can use the Fluent Query Builder to build your queries in multiple stages prior to actually making the query. Once you know this, the translation is pretty straightforward:
public function getData($table, $multiple = 1, $field = FALSE, $val = FALSE)
{
$query = DB::table($table);
if($field){
// WHERE in case of FIELD / VAL :)
$query = $query->where($field, $val);
}
if($multiple) {
return $query->get();
}
return $query->first();
}
I don't think it's really good practice relying on Fluent though inside of an Eloquent model, but there are cases where that can't be helped. If the current objective is to convert the project to Laravel, there's probably calling code relying on the fact that this method exists. Converting the function to use Eloquent rather than Fluent will change the function's signature and cause other parts of the code to break, but it would look like this:
public function getData($multiple = true, $field = false, $val = false)
{
$query = $this;
if($field) {
$query = $query->where($field, $val);
}
if($multiple) {
return $query->get();
}
return $query->first();
}
The calling code itself can be modified to do the exact same function in Laravel like this:
// Instead of...
$result = $model->getData(1, 'field', 'value');
// You can do this:
$result = $model->where('field', 'value')->get();
// Or this if you'd rather not have multiple:
$result = $model->where('field', 'value')->first();
Using this function inside Eloquent (IMHO) in the long run doesn't really save you much, and instead is mostly just clutter.
I'm using the addColumnCondition function as I like how it forms the queries for multiple queries. But I can't find anything in the documentation to change it's comparison operation from the simple = needle to a LIKE %needle%. There is a function that does a LIKE in addSearchCondition() but then it means to get the same query formation result, I'll have to do some for loops and merge conditions which I'd like to avoid if there is a better solution.
Here's the code
foreach($query_set as $query){
foreach($attributes as $attribute=>$v){
$attributes[$attribute] = $query;
}
$criteria->addColumnCondition($attributes, 'OR', 'AND');
}
And I'm getting the condition formed like
(business_name=:ycp0 OR payment_method=:ycp1) AND (business_name=:ycp2 OR payment_method=:ycp3)
So is there a way to configure the function to use LIKE %:ycp0% instead of the simple =:ycp0.
It seems, this feature is not provided by Yii's addColumnCondition method.
therefore i would recommend a way of overriding the method of CDbCriteria class and customize it your own way.
you need to create a new class called "AppCriteria", then place it inside protected/models
The code for the new class should look like,
i.e
class AppCriteria extends CDbCriteria {
public function addColumnCondition($columns, $columnOperator = 'AND', $operator = 'AND', $like = true) {
$params = array();
foreach ($columns as $name=>$value) {
if ($value === null)
$params[] = $name.' IS NULL';
else {
if ($like)
$params[] = $name.' LIKE %'.self::PARAM_PREFIX.self::$paramCount.'%';
else
$params[] = $name.'='.self::PARAM_PREFIX.self::$paramCount;
$this->params[self::PARAM_PREFIX.self::$paramCount++] = $value;
}
}
return $this->addCondition(implode(" $columnOperator ", $params), $operator);
}
}
Note: The 4th param of addColumnCondition, $like = true. you can set it to $like = false and allow the function to work with equal conditions. (A = B)
i.e
(business_name=:ycp0 OR payment_method=:ycp1) AND (business_name=:ycp2 OR payment_method=:ycp3)
if $like = true, it will allow you to have like condition. (A like %B%)
i.e
(business_name LIKE %:ycp0% OR payment_method LIKE %:ycp1%) AND (business_name LIKE %:ycp2% OR payment_method LIKE %:ycp3%)
Now Here's the working code,
$criteria = new AppCriteria();
foreach($query_set as $query){
foreach($attributes as $attribute=>$v){
$attributes[$attribute] = $query;
}
$criteria->addColumnCondition($attributes, 'OR', 'AND');
}