I have around 60 entities, all referring (manyToOne or oneToOne) to a "uber entity" called "project".
I'm developing a dashboard, so once selected the project I have to get all "children" entities referred to the project.
So I have:
class Entity1{
...
/**
* #ORM\OneToOne(targetEntity="Project")
*/
protected $project;
...
}
or
class Entity2{
...
/**
* #ORM\ManyToOne(targetEntity="Project")
*/
protected $project;
...
}
Of course I could do:
$entitiesToCheckStatusFor = ['Entity1', 'Entity2', ..., 'Entity60', ];
$entitiesStatus = [];
foreach ($entitiesToCheckStatusFor as $entityToCheckStatusFor){
$entitiesStatus[$entityToCheckStatusFor] = $em->getRepository('AppBundle:'.$entityToCheckStatusFor)->findByProject($project);
}
But it means 60 queries. It's far from elegant.
I basically need a JOIN between unrelated entities so that I can make a single query.
I tried something like:
$query = $em->createQuery('SELECT ai, pn, pb, pd p FROM AppBundle:Project p '
. 'LEFT OUTER JOIN AppBundle:ProjectNotification pn WITH p.id = pn.project '
. 'LEFT OUTER JOIN AppBundle:ProjectDetail pd WITH p.id = pd.project '
. 'LEFT OUTER JOIN AppBundle:ProjectBenefit pb WITH p.id = pb.project '
. 'LEFT OUTER JOIN AppBundle:ActionItem ai WITH p.id = ai.project '
. 'WHERE p.id = :projectid'
)->setParameter('projectid', $project->getId());
$mixedStuff = $query->getResult();
but it returns a lot of nulls when there are no entities:
array:20 [▼
0 => Project {#8285 ▶}
1 => null
2 => ProjectDetail {#3028 ▶}
3 => null
4 => ActionItem {#2978 ▶}
5 => null
6 => null
7 => ActionItem {#3191 ▶}
8 => null
9 => null
10 => ActionItem {#3200 ▶}
11 => null
12 => null
13 => ActionItem {#3205 ▶}
14 => null
15 => null
16 => ActionItem {#3210 ▶}
17 => null
18 => null
19 => ActionItem {#3214 ▶}
]
I could live with the nulls, but I was hoping to get rid of them. Besides in this case I was expecting to get 2 nulls (one for ProjectNotification and another for ProjectBenefit, while I have a lot. Why?
Any other advice?
Thank you!
I don't see the need of use LEFT OUTER JOIN. If relations are properly configured, especially in project entity you can make a simple JOIN and get not nulls.
$query = $em->createQuery('SELECT p, pn, pd,pb, pa '
. 'FROM AppBundle:Project p '
. 'JOIN p.notifications pn '
. 'JOIN p.details pd '
. 'JOIN p.benefits pb '
. 'JOIN p.actions pa '
. 'WHERE p.id = :id ')
->setParameter('id', $project->getId());
Related
I am building a query throw querybuilder objects, something like
$qb = $em->createQueryBuilder()
->select('n, t, ns1m')
->from('App\Entity\Nuclei','n')
->leftJoin('n.statistiche1M', 'ns1m', 'WITH', 'DATE_PART(\'year\', ns1m.dataora) = YEAR(CURRENT_DATE())')
->leftJoin('n.codicitag', 't')
->where('n.comune = :id_comune')
->setParameter('id_comune', $this->user->getComune()->getId());
This query return an array of entity objects "nucleo":
array:3 [▼
0 => App\Entity\Nuclei { ... }
1 => App\Entity\Nuclei { ... }
2 => App\Entity\Nuclei { ... }
I want to add another column to select
->addSelect('SUM(ns1m.totale_peso_conferimenti_indifferenziata) AS total_test')
but now the result is:
array:2 [▼
0 => array:2 [▼
0 => App\Entity\Nuclei {#1671 ▶}
"total_test" => 1520
]
1 => array:2 [▶]
]
n.codicitag is a onetomany relations and is a collections of other objects
how can to handle this? Made many tests without success
What is your requested result? Result seems fine. You get sum for every Nuclei object.
If you need total sum without changing result structure, create extra query:
$qb = $em->createQueryBuilder()
->select('SUM(ns1m.totale_peso_conferimenti_indifferenziata) AS total_test')
->from('App\Entity\Statistiche1M','s1m')
->where('DATE_PART(\'year\', ns1m.dataora) = YEAR(CURRENT_DATE())');
This query return total sum filtered by current year.
You can try:
$qb = $em->createQueryBuilder()
->select('n, t, ns1m', 'SUM(ns1m.totale_peso_conferimenti_indifferenziata) AS total_test')
->from('App\Entity\Nuclei','n')
->leftJoin('n.statistiche1M', 'ns1m', 'WITH', 'DATE_PART(\'year\', ns1m.dataora) = YEAR(CURRENT_DATE())')
->leftJoin('n.codicitag', 't')
->where('n.comune = :id_comune')
->setParameter('id_comune', $this->user->getComune()->getId());
Because addSelect() create new array.
I have a word press site with custom fields.
I need to query a repeater field as a table. It looks like that:
| param_1 | param_2 | param_2 | param_4
| 20 | 20 | 20 | 20
| 555 | 680 | 56 | 0
| 5555 | 45 | 56 | 1
| 69 | 0 | 45 | 0
I need to query this repeater to get a result only if it match the query in the same line
My meta query looks like that:
[post_type] => product
[posts_per_page] => -1
[orderby] => title
[order] => ASC
[meta_query] => Array (
[relation] => AND
[0] => Array (
[key] => BBBproduct_params_values_AAA_param_value_0
[value] => 25
[compare] => <=
[type] => NUMERIC
)
[1] => Array (
[key] => BBBproduct_params_values_AAA_param_value_1
[value] => 56
[compare] => >=
[type] => NUMERIC
)
[2] => Array (
[key] => BBBproduct_params_values_AAA_param_value_2
[value] => 56
[compare] => >=
[type] => NUMERIC
)
[3] => Array (
[key] => BBBproduct_params_values_AAA_param_value_3
[value] => 0
[compare] => =
[type] => NUMERIC
)
)
She is created trough this code:
if( $product_search_by_param_active ){
function my_posts_where( $where ){
$where = str_replace("AAA_param_value_", "%_param_value_", $where);
$where = str_replace("meta_key = 'BBBproduct_params_values_", "meta_key LIKE 'product_params_values_", $where);
return $where;
}
add_filter('posts_where', 'my_posts_where');
$range_angine_settings = get_field('param_search_range_settings');
$search_args['meta_query'] = array();
$search_args['meta_query'] ['relation'] = 'AND';
foreach( $range_angine_settings as $rangekey => $search_range ){
${'range-'.$rangekey} = $_GET['range-'.$rangekey]? $_GET['range-'.$rangekey] : '0';
if ( $_GET['range-'.$rangekey] ) $has_range_query = true;
//$pre_prama_value = 'product_params_values_'.strval($rangekey).'_param_value_AAA';
if( isset($_GET['range-'.$rangekey])){
$search_args['meta_query'][] = array(
"key" => 'BBBproduct_params_values_AAA_param_value_'.strval($rangekey),
"value" => $search_range['search_metric_ranges'][${'range-'.$rangekey}]['range_value'],
"compare" => $search_range['product_search_logic'],
'type' => 'NUMERIC'
);
}
}
}
The problem is that this because of the '%' I get result even if the query match not on the same line.
In the example above it is intended not to get any results, but as every condition is met on a different line I do get a result.
Is there a way to create this king of query to give results by line number?
For me I prefer using CMB2 for custom fields
https://github.com/CMB2/CMB2
I have the following tables in mysql with given relationships and same has been define in the symfony2. I want to achieve the following query which I wrote it down below. can some one help me how can I write it in querybuilder?
unitids(id,unitid,databaseid)
Mappaths(id,ref_unitid2(forigen key for unitids id) ,ref_unitid1 (forigen key for unitids id),nomal value)
traveltime(id,ref_map_path(forigen key for mappaths id), traveltime,noobjs,ondate)
my mysql query is like this :
SELECT t.ID,t.ondate, un.databaseid as source1,
un1.databaseid as desitnation, t.traveltime, t.noobjs
FROM test.traveltime t
left join test.mappaths p on t.ref_map_path = p.ID
left join test.unitids un on (p.ref_unitids1 = un.id )
left join test.unitids un1 on (p.ref_unitids2= un1.id)
where un.databaseid=50 and un1.databaseid =1 limit 1;
which give me each one row of source and destination of and objects etc like this :
in symfony2 when i run this query
$query = $em->createQueryBuilder();
$results = $query->select('un.databaseid,un1.databaseid')
->from('ApiMapBundle:Traveltime', 't')
->leftJoin('t.refMapPath', 'p')
->leftJoin('p.refUnitids2', 'un')
->leftJoin('p.refUnitids1', 'un1')
->where('un.databaseid = :bdatabaseid1')
->setParameter('bdatabaseid1', 2)
->andwhere('un1.databaseid = :bdatabaseid2')
->setParameter('bdatabaseid2',1)
//->setMaxResults(1)
->getQuery()
->getResult();
it give me output like
Array ( [0] => Array ( [databaseid] => 1 ) [1] => Array ( [databaseid] => 1 ))
but instead it should give me
Array ( [0] => Array ( [databaseid] => 1 ) [1] => Array ( [databaseid] => 2 ))
How can i achieved this above output?????
Assumed that you are writing code in Repository and you also defined relations in your Entities
$em = $this->getEntityManager();
$query = $em->getRepository('BUNDLE:traveltime')->createQueryBuilder('t');
$query->select('t.Id,..')
->leftJoin('t.ref_map_path','p')
->leftJoin('p.ref_unitids1','un')
->leftJoin('p.ref_unitids2','un1')
->where('un.databaseid = :bdatabaseid')
->setParameter('bdatabaseid',1)
->orWhere('un1.databaseid = :bdatabaseid1')
->setParameter('bdatabaseid1',2);
How can i get the start and end date of a DatePeriod object?
$today = new \DateTime(date('Y-m-d')); // 2012-05-30
$period = new \DatePeriod($today, new \DateInterval('P1M'), 1);
$stats = new UsageStatistics($period);
class UsageStatistics
{
protected $period, $sentEmailCount, $autoSentEmailCount;
public function __construct(\DatePeriod $period)
{
$this->period = $period;
// Current logged in user and email repository
$user = $this->getUser();
$repo = $this->getEmailRepository();
// Get the start and end date for the given period
$startDate = ...
$endDate = ...
$result = $repo->getAllSentCount($user, $startDate, $endDate);
// Assigning object properties
}
public function getSentEmailCount() { return $this->sentEmailCount; }
public function getAutoSentEmailCount() { return $this->autoSentEmailCount; }
}
DatePeriod only implements the Traversable interface and has no other methods to either access elements or retrieve them.
You can do something easy to get start/end dates:
$periodArray = iterator_to_array($period);
$startDate = reset($periodArray);
$endDate = end($periodArray);
I'm using PHP 5.6.9 and it seems that you can use the properties end and start to access your beginning and end DateTime objects:
$p = new DatePeriod($s, $i, $e);
$startTime = $p->start; //returns $s
$endTime = $p->end; //returns $e
The PHP documentation doesn't seem to reflect this. I did a print_r of a DatePeriod object and got the following output:
DatePeriod Object
(
[start] => DateTime Object
(
[date] => 2015-06-01 00:00:00.000000
[timezone_type] => 3
[timezone] => America/Los_Angeles
)
[current] => DateTime Object
(
[date] => 2015-06-08 00:00:00.000000
[timezone_type] => 3
[timezone] => America/Los_Angeles
)
[end] => DateTime Object
(
[date] => 2015-06-08 00:00:00.000000
[timezone_type] => 3
[timezone] => America/Los_Angeles
)
[interval] => DateInterval Object
(
[y] => 0
[m] => 0
[d] => 7
[h] => 0
[i] => 0
[s] => 0
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] =>
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
[recurrences] => 1
[include_start_date] => 1
)
It seems that properties current and interval are also visible.
The solution posted by #hakre and #Boby is not correct.
The $endDate is end of the period when PERIOD % INTERVAL = 0.
All other cases $endDate will be END - PERIOD.
$startingDate = new DateTime($startingDay);
$startingDate->modify('previous day');
$startingDate->modify('next Sunday');
$endingDate = new DateTime($endingDay);
$endingDate->modify('next day');
$period = new DatePeriod($startingDate, new DateInterval('P1W'), $endingDate);
I'm using drupal_execute to save a node programmatically, and for the most part, it works fine, except when it comes to a multi-value field.
What gets posted is this (I'm just including the portion that isn't working):
[alt] => Array
(
[0] => Array
(
[name] => Sam I. Am
[phone] => (650) 5553131
)
[1] => Array
(
[name] => The Lorax
[phone] => 6505553344
)
[2] => Array
(
[name] =>
[phone] =>
)
)
When I'm setting the $form_state['values'], I'm using:
for($a = 0; $a < count($_REQUEST['alt']); $a++) {
$form_state['values']['field_alternativename'][$a]['value'] = check_plain($_REQUEST['alt'][$a]['name']);
$form_state['values']['field_alternativephone'][$a]['value'] = format_phone($_REQUEST['alt'][$a]['phone']);
}
And to save the node:
drupal_execute('info_node_form', $form_state, $node);
As a test, to make sure that I'm referencing the appropriate fields, I edited an existing node using node/X/edit and printed out the $form_state['values'] upon submission. This is what it printed out:
//output of print '<pre>'; print_r($form_state['values']); print '</pre>';
[field_alternativename] => Array
(
[0] => Array
(
[value] => Sam I. Am
[_error_element] => group_alternative_contacts][0][field_alternativename][value
[_weight] => 0
[_remove] => 0
)
[1] => Array
(
[value] => The Lorax
[_error_element] => group_alternative_contacts][1][field_alternativename][value
[_weight] => 1
[_remove] => 0
)
)
[field_alternativephone] => Array
(
[0] => Array
(
[value] => (650) 5553131
[_error_element] => group_alternative_contacts][0][field_alternativephone][value
[_weight] => 0
[_remove] => 0
)
[1] => Array
(
[value] => (650) 5553344
[_error_element] => group_alternative_contacts][1][field_alternativephone][value
[_weight] => 1
[_remove] => 0
)
)
So, I'm not understanding why it isn't being saved... I'm not setting the delta, but I didn't think I'd have to? In mysql, the data is stored as:
mysql> select * from content_field_alternativename ;
+-------+-------+-------+-----------------------------+
| vid | nid | delta | field_alternativename_value |
+-------+-------+-------+-----------------------------+
| 22433 | 22433 | 0 | Sam I. Am |
+-------+-------+-------+-----------------------------+
mysql> select * from content_field_alternativephone;
+-------+-------+-------+------------------------------+
| vid | nid | delta | field_alternativephone_value |
+-------+-------+-------+------------------------------+
| 22433 | 22433 | 0 | (650) 5553131 |
+-------+-------+-------+------------------------------+
The delta is how cck stores multiple values. nid x, vid x, delta 0 is the first in the multivalue field nid x, vid x, delta 1 is the second etc. It's required so if you add deltas to your multi-values it should work.