Symfony2 + doctrine's query builder - where != 1 - php

I have a function that creates a query to my db, like this:
public function getList($u, $t, $ls, $lf) {
return $this->getEntityManager()
->createQuery('
SELECT
o,
u,
g,
r,
t,
p
FROM GameShelfUsersBundle:Own o
LEFT JOIN o.user u
LEFT JOIN o.game g
LEFT JOIN o.rate r
LEFT JOIN o.typo t
LEFT JOIN o.platforms p
WHERE u.id = :user
AND o.typo = :type
ORDER BY o.updated DESC
')
->setParameters(array(
'user' => $u,
'type' => $t
))
->setMaxResults($lf)
->setFirstResult($ls)
->getResult();
}
My problem is, how to set :type to be not in? I mean, I wanted to use it like this:
$type = '!= 1'
...
AND o.typo :type
...
'type' => $type
But it didn't worked at all. Using $type = -1 doesn't help either. Is there any way, other than creating if/else statement and duplicating query?

Why don't you use a query builder??
In that way you can easily customize your query, depending on some condition.
This is an example:
$q = $this
->createQueryBuilder('foo')
->select('foo')
->leftJoin('foo.bar', 'foobar')
->leftJoin('foobar.bar', 'foobarbar')
;
if($myVar > 0)
{
$q->where('foobarbar.var = :myVar');
}
else
{
$q->where('foobarbar.var = :staticValue');
}
[...]
Remember to call return $q->getResult(); at the end

Related

mysql query to check a field exist in an array in codeigniter

I post an array of skills from the form and i need to fetch list of candidates list related to the elements in array in codeigniter.
Controller
$data = array(
"mode" => $this->input->post("mode"),
"designation" => $this->input->post("designation"),
"notice_period" => $this->input->post("notice_period"),
"skill" => $this->input->post("skills"),
"cities" => $this->input->post("city")
);
$this->load->model("search_model");
$this->load->model("candidate_model");
$data["candidate"] = $this->search_model->fetch_candidate($data);
$data["designation"] = $this->candidate_model->fetch_designation();
$this->load->view('candidate_profiles', $data);
model
function fetch_candidate($data)
{
$mode = $data['mode'];
$designation = $data['designation'];
$notice_period = $data['notice_period'];
$skill = $data['skill'];
$skills = join(",",$skill);
$city = $data['cities'];
$query = $this->db->query("SELECT DISTINCT(U.user_id), U.firstname, U.lastname, U.username, U.usertype, U.email, U.phone, U.address, U.profile_image, C.name AS country,C.id AS countryid, S.name AS state,S.id AS stateid, A.housename, A.street, A.area, A.po, A.city, CJ.designation, CJ.resume, CJ.biography, CJ.hiring_mode, CJ.notice_period, CJ.current_CTC, CJ.expected_CTC, D.designation_id AS desig, D.designation AS desig_name
FROM users AS U
LEFT JOIN address AS A ON U.user_id=A.cand_id
LEFT JOIN cand_job_details AS CJ ON CJ.cand_id=U.user_id
LEFT JOIN designations AS D ON D.designation_id=CJ.designation
LEFT JOIN countries AS C ON C.id=A.country
LEFT JOIN states AS S ON S.id=A.state
LEFT JOIN user_skills AS US ON U.user_id=US.user_id
LEFT JOIN user_interested_cities AS UC ON U.user_id=UC.user_id
WHERE D.designation LIKE '$designation' && (CJ.hiring_mode='2' || CJ.hiring_mode='$mode') && CJ
.notice_period<='$notice_period' && UC.city='$city' && US.skill IN(".implode(",", $skills).")
");
return $query;
}
How to implement this on codeigniter?
Thanks in advance
You need try to add ' around each argument. After it should looks like IN ('PHP','AngularJS'), because it is a string value and datatype is varchar as well.
$skills = "'";
foreach($skill as $item) {
$skills .= $item."',";
}
$skills = trim($skills,",")
Codeigniter comes with a built in Querybuilder - i strongly suggest to use it, because it makes your life much easier, and protects you against SQL injections - which is clearly a problem in your case.
Try the following
function fetch_candidate($data)
{
$this->db
->select('SELECT DISTINCT(U.user_id), U.firstname, U.lastname, U.username, U.usertype, U.email, U.phone, U.address, U.profile_image, C.name AS country,C.id AS countryid, S.name AS state,S.id AS stateid, A.housename, A.street, A.area, A.po, A.city, CJ.designation, CJ.resume, CJ.biography, CJ.hiring_mode, CJ.notice_period, CJ.current_CTC, CJ.expected_CTC, D.designation_id AS desig, D.designation AS desig_name')
->from('users U')
->join('address A', 'U.user_id=A.cand_id', 'left')
->join('cand_job_details CJ', 'CJ.cand_id=U.user_id', 'left')
->join('designations D', 'D.designation_id=CJ.designation', 'left')
->join('countries C', 'C.id=A.country', 'left')
->join('states S', 'S.id=A.state', 'left')
->join('user_skills US', 'U.user_id=US.user_id', 'left')
->join('user_interested_cities UC', 'U.user_id=UC.user_id', 'left');
if (isset($data['designation']) && !empty($data['designation']))
{
$this->db->like('D.designation', $data['designation']);
}
if (isset($data['mode']) && !empty($data['mode']))
{
$this->db
->group_start()
->where('CJ.hiring_mode', 2)
->or_where('CJ.hiring_mode', $data['mode'])
->group_end();
}
if (isset($data['notice_period']) && !empty($data['notice_period']))
{
$this->db->where('CJ.notice_period <=', $data['notice_period']);
}
if (isset($data['city']) && !empty($data['city']))
{
$this->db->where('UC.city', $data['city']);
}
if (isset($data['skills']) && is_array($data['skills']))
{
$this->db->where_in('US.skill', $data['skills']);
}
return $this->db->get();
}

prevent dql from entity joins

I want to write a DQL query that select post and join to another Entity's
here is my code
$dql = '
SELECT p , h ,t ,m
FROM App:Post p
LEFT JOIN p.mentions m
LEFT JOIN p.tags t
LEFT JOIN p.file h
WHERE p.user
IN (
SELECT f FROM App:User u
JOIN u.followers f
WHERE u.id = :uid
)
OR p.user = :uid ';
$query = $this->getEntityManager()
->createQuery($dql)
->setMaxResults(1)
->setParameters(['uid' => $user->getId()]);
$paginator = new Paginator($query, $fetchJoinCollection = true);
but the problem is the circular reference, for example, Post -> Tags -> Posts that is used in serialization and make project freeze and shows a blank page.
here is dump export
how can I handle that Except using loop look at PersistentCollection
UPDATE ::
here is my seriallizer code
$posts= [];
foreach ($paginator as $post) {
$posts[] = $post;
}
$serializer = SerializerBuilder::create()->build();
$gifts = $serializer->toArray($posts);
You can use serialization groups to avoid circular reference issues. Basically, this lets your define a group (or multiple ones) to each property, then you can ask only specific(s) group(s) to be serialized.
For symfony native serializer :
http://symfony.com/doc/current/serializer.html#using-serialization-groups-annotations
https://symfony.com/blog/new-in-symfony-2-7-serialization-groups
For JMS : https://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies

codeigniter Database class JOIN USING

how can i use
left JOIN Table2 using(table.id) ?
Example of my CODE
$this->db->select('visits.*,patients.name,workers.dr_name,time(visits.time)');
$this->db->from('visits');
//The next join = LEFT JOIN workers ON visits.worker_id=workers.worker_id
$this->db->join('workers','visits.worker_id=workers.worker_id','left');//WORKING
//The next join = JOIN `patients` ON patient_id --> i want it JOIN patients USING(patient_id)
$this->db->join('patients','patient_id','USING');//NOT WORKING
i searched every were, yet couldnt find a solution, and so i opened and tried to edit JOIN function in db_active_rec.php
/system/database/DB_active_rec.php
and found the join function
public function join($table, $cond, $type = '')
{
if ($type != '')
{
$type = strtoupper(trim($type));
if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
{
$type = '';
}
else
{
$type .= ' ';
}
}
// Extract any aliases that might exist. We use this information
// in the _protect_identifiers to know whether to add a table prefix
$this->_track_aliases($table);
// Strip apart the condition and protect the identifiers
if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
{
$match[1] = $this->_protect_identifiers($match[1]);
$match[3] = $this->_protect_identifiers($match[3]);
$cond = $match[1].$match[2].$match[3];
}
// Assemble the JOIN statement
$join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
$this->ar_join[] = $join;
if ($this->ar_caching === TRUE)
{
$this->ar_cache_join[] = $join;
$this->ar_cache_exists[] = 'join';
}
return $this;
}
tried to edit the part under "// Assemble the JOIN statement" and put ifcondition to detect USING and then adjust the query accordingly but failed.. epic fail
can any one help ? how can i edit this function so that it would use USING in Join query ?
From the manual:
$this->db->join();
Permits you to write the JOIN portion of your query:
$this->db->select('*');
$this->db->from('blogs');
$this->db->join('comments', 'comments.id = blogs.id');
$query = $this->db->get();
// Produces:
// SELECT * FROM blogs
// JOIN comments ON comments.id = blogs.id
Multiple function calls can be made if you need several joins in one query.
If you need a specific type of JOIN you can specify it via the third parameter of the function. Options are: left, right, outer, inner, left outer, and right outer.
$this->db->join('comments', 'comments.id = blogs.id', 'left');
// Produces: LEFT JOIN comments ON comments.id = blogs.id

Doctrine fetch join

First I will give an example with some pseudo code and then I will explain what is the problem. Let me say I have two entities User and Phonenumber. Their relation is one-to-many. In my UserRepository I can have something like that:
class UserRepository
{
public function getUser($id, $type)
{
$users = $this->createQuery("SELECT u, p FROM User u JOIN u.phonenumbers p
WHERE u.id = :id AND p.type = :type")
->setParameters(array(
'id' => $id,
'type' => $type,
))
->getResult();
return $users[0];
}
}
In my app if I have something like:
$user = $userRepo->getUser(1, 'home');
var_dump($user->getPhonenumbers()); // here phonenumbers collection is ok
$user = $userRepo->getUser(1, 'work');
var_dump($user->getPhonenumbers()); // Here phonenumbers collection is wrong.
// It's exactly the same as the previous one.
So my questions is: Is it possible to use fetch join (with different criteria) and to get the proper collection each time?
Fetch joining and filtering a collection are not things that work together quite well. Here's how you should do it:
SELECT
u, p
FROM
User u
JOIN
u.phonenumbers p
JOIN
u.phonenumbers p2
WHERE
u.id = :id
AND
p2.type = :type
This applies filtering on the second joined (and not hydrated) p2, which results in correct hydration and filtering.
Use querybuilder, it is much simpler.
public function getUser($id, $type)
{
return $this->createQueryBuilder("u")
->leftJoin("u.Phonenumbers", "p", "WITH", "p.type=:type")
->where("u.id=:id")
->setParameters(.....)
->getQuery()
->getOneOrNullResult() ;
}

CakePHP, special select

I will be blunt, I need the model list to be built from this special select:
SELECT * FROM posts p WHERE p.user_id IN
(SELECT u.id FROM users u, following f
WHERE u.id = f.followee_id AND f.follower_id = $id)
ORDERED BY p.created
LIMIT $limit;
Is it possible to put this as a function into the model? I am quite new to CakePHP, I must admit.
I can't use the find functions here because then the posts wouldn't be properly "mixed".
Yes, you can add your own method to the Model class that will execute the query you write.
But don't forget to sanitize your input (it is not done automatically when you write your own queries) and to add table prefixes.
App::import('Sanitize');
class YourModel extends AppModel {
public function specialSelect($id, $limit) {
$id = Sanitize::paranoid($id); // or use (int) to convert it to integer
$limit = Sanitize::paranoid($limit);
return $this->query(
'SELECT * FROM '.$this->tablePrefix.'posts p WHERE p.user_id IN '.
'(SELECT u.id FROM '.$this->tablePrefix.'.users u, '.$this->tablePrefix.'.following f '.
'WHERE u.id = f.followee_id AND f.follower_id = '.$id.') '.
'ORDER BY p.created LIMIT '.$limit
);
}
}

Categories