I am working on a Symfony 2.7 webapp that uses the FOSUserBundle. Everything works fine so far. Not I would like to add an Admin Backend, that allow to show details about different Users.
For example in a Phone Book App, on should be able to see how many contacts a selected user has created:
$contact_count = $this->contactsCountForUser(5);
...
public function contactsCountForUser($user_id) {
$repo = $this->em->getRepository('AppBundle:Contact');
$qb = $repo->createQueryBuilder('c');
$qb->select('COUNT(c)');
$qb->where('c.user = :userId');
$qb->setParameter('userId', $user_id);
$sql = $qb->getQuery()->getSql();
$count = $qb->getQuery()->getSingleScalarResult();
return $count;
}
This fails, since the following is created as SQL query:
SELECT COUNT(c0_.guid) AS sclr0 FROM contact c0_ WHERE (c0_.user_id = ?) AND (c0_.user_id = '1')
Problem 1:
Why is $qb->where('c.user = :userId') being translated to c0_.user_id = ?? Why isn't 5 beeing used as user_id?
Problem 2:
AND (c0_.user_id = '1') is automatically added to the query. I assume this is done by the FOSUserBundle which limits the query to the current user. Here ID 1 is the ID of the currently logged in user, which is the Admin... Obviously (c0_.user_id = ?) AND (c0_.user_id = '1') can never be true.
So: How do I convince Doctrine and/or the FOSUserBundle, that the admin should be able to execute queries on other users data?
Thanks to the comment of #LBA, I was able to find the source of the problem:
A piece of third-party code add an SQLFilter as UserAware annotation. This webpage describes in detail what is done and how it works.
Maybe this can help others to avoid this kind of "problem" and to figure out what is "wrong" :-)
About Problem 1: Even after solving Problem 2, Problem 1 is still the same. The userId is still translated to ? within the query. However this does not seem to influence the function of the code. As far as I can see everything is working as expected.
Related
I'm currently creating a basic private messaging system in Laravel. In my database I have a messages table. Two of the columns are "sender_id" and "recipient_id".
What I am trying to do is use eloquent to go through this table and list in the inbox all the times the current logged in user's id is listed in these columns. I will then use "distinct" to ignore duplicate entries so that the user is only listed once. Using this ID, I can display the username of the recipient so that when the user clicks on the username, it will take them to the message thread for that user.
For the sake of testing, I am only currently retrieving the column "recipient_id" and outputting it into the blade. Here is the line I believe should only output the recipient once despite being found many times in the table.
MessageController
$messages = Message::where('recipient_id', $user)->distinct('recipient_id')->get();
However in the blade, the same user is being output twice (as they have 2 messages found) when I would have expected the distinct function to remove the duplicate entry.
I have also tried
$messages = Message::where('recipient_id', $user)->distinct()->get();
But that also did not work.
If I have received 3 messages from 2 different users, it is outputting something like below:
Messages from:
Example User 1
Example User 1
Example User 2
What it should output
Example User
Example User 2
Thanks
Use Laravel Collection and changed code to:
$messages = collect(Message::where('recipient_id', $user)->get());
$messagesUnique = $messages->unique('recipient_id');
$messagesUnique->values()->all();
You can follow this
$payment = Payment::with('invoice','customer')->get();
$payment = $payment->unique('customer_id');
It will return all the unique customer payment data.
You should use something like this:
$data = Message::select([ DB::raw('DISTINCT(recipient_id)')'])
->where('recipient_id', $user)
->get();
instead of using a collection, as when you use collection you returned with all data you needed or not then you filter it. but when using distinct in the query you just take them in one process.
Or you can try one of these options: mentioned here
$diff = Crud::distinct()->pluck('name');
$diff = Crud::distinct()->get(['name']);
$diff = Crud::distinct()->select('name')->get();
I am trying to add a feature to a website built with Laravel.
There is a table containing vote numbers and user. I want to get the total points a user has in a certain category. I do not have any PHP or Laravel experience but said I would give this a shot.
$votes1 = UserVotes::select ('select vote from user_votes where feedback_id = ? and feedback_type = 1', Auth::user()->id);
This should return an object containing the vote amount. I want to interrogate the the object to check if the vote number is above a certain amount and then do something based on that being the case or not.
if vote > 50{
//do stuff
}
foreach ($votes1 as $vote1) {
echo $vote1->vote;
}
The query should return 1. I have verified this by querying the database, so the problem is with my understanding of Laravel or php. What I am doing wrong?
You don't need to construct your own SQL statement; Eloquent will do that for you.
If your models are set up in the default way, your query would look something like:
$votes = UserVotes::where('feedback_id', Auth::user()->id)
->where('feedback_type', 1)
->get();
You can then iterate over that as normal.
Additionally, if there is a relationship set up with the user model you could do something like
$votes = Auth::user()->votes()
->where('feedback_type', 1)
->get();
Check out the documentation here: http://laravel.com/docs/4.2/eloquent
assuming UsersVotes extends Model, here's how you should do it:
UsersVotes::select('vote')->where('feedback_type', 1)->where('feedback_id', Auth::user()->id)-get();
I made this SQL statement to use in a project i'm working on and i have used FluentPDO before but it has been a while and i have never used a subquery in it before, so was wondering if anyone out there knows a good way to do this, i know you can do a JOIN but i am not really familiar with that method and never seen it used before so i don't know enough to make it work, i'm trying to brush up on it so i can do this myself.
SELECT *
FROM users
WHERE username = 'admin'
AND password = 'testing'
AND company_id IN (SELECT company_id
FROM company
WHERE subdomain = 'testing');
$result = $db->from('users')
->innerJoin('company ON users.company_id = company.company_id')
->where('username', 'admin')
->where('password', 'testing')
->where('subdomain', 'localhost')
->fetch();
I figured out the answer, and wanted to post it for anyone that was wondering the same way i was.
I hope I described the subject properly. I'm creating a contact management application where each user will have his own contacts within the same contact table. Users must not be able to see each other's contacts.
I started by doing this but there must be a better way:
$contact = Contact::where('user_id', Auth::user()->id)->find($id);
The problem with the line above is that I would like to write it this way:
$contact = Contact::find($id)
Is there a way to have the where clause loaded somehow like filters maybe so that all searches have to match the Auth::user()->id?
As suggested, you can use a query scope. Add this in your Contact model:
public function scopeOfUser($query, $user_id)
{
return $query->where('user_id', '=', $user_id);
}
And then use it like this: $contacts = Contact::ofUser(Auth::user()->id)->get();.
I found the answer I was looking for on laracasts.com. (video: Repositories Simplified)
I solved the problem by creating repositories. For example in my ContactController:
$contact = Contact::where('user_id', Auth::user()->id)->find($id);
is now
$contact = $this->contact->getAll();
The DbRepository file has:
public function getAll() {
return $this->model->where('user_id', Auth::user()->id)->get();
}
There's a lot more to it and you'll need to view the video to set it up. It's a lot more work to set up but it's a lot cleaner and the DbRepository can be used by all my controllers since every table will have a user_id field.
I have this query which I want to run in my PHP application back end. Notionally, sheet is a DB that keeps track of all the sheets we have. Purchases is a DB that keeps track of which users have access to which sheet. The query I want to run is given a user's id, I can get all the sheets that they should have access to. In query form:
select distinct s.wsid, s.name from sheets s, purchases p where
s.wsid = p.wsid AND p.uid = *value*;
where value is something input by the application
The way I see it there are two ways to go about getting this to work in the back end.
Option 1)
public function getPurchasedSheets($uid){
if( is_numeric($uid) ){ //check against injections
$query = "select distinct s.wsid, s.name from sheets s, purchases p
where s.wsid = p.wsid AND p.uid = ".$uid.";" ;
return $this->db->query($query);
} else {
return NULL; //or false not quite sure how typing works in PHP
}
}
Option 2)
public function getPurchasedSheets($uid){
if( is_numeric($uid) ){
$this->db->select('wsid, name');
$this->db->distinct();
$this->db->from('purchases');
//not sure which order the join works in...
$this->db->join('sheets', 'sheets.wsid = purchases.wsid');
$this->db->where('uid ='.$uid);
return $this->db->get();
} else {
return NULL;
}
}
Source for all the CodeIgniter Active Record commands:
codeigniter.com/user_guide/database/active_record.html
Is there some sort of performance or security difference from doing thing one way or another? Doing it the second way seems so much more confusing to me... This is compounded a little bit because I am not sure how to do referential disambiguation in this style of coding because purchases and sheets both have a uid field but they mean different things (in addition to not being very familiar with the SQL join command in the first place.). Uid (user id) in purchases means that user has purchased that sheet, while Uid in sheets denotes which user owns that sheet.
TL,DR: Basically, I am asking is there a reason I should sink time into looking how to do things the option 2 way?
The main benefits are:
Abstraction from the database engine, where the library can take care
of database-specific SQL syntax differences for you. Relevant if you
ever have/want to change the database you're working with. In theory,
the second form should still just work.
The 'Active Record' syntax
automatically escapes parameters for you.
Readability, although
that's a matter of taste.
Incidentally, if you're in a PHP 5 environment, the library supports method chaining:
if( is_numeric($uid) ){
return $this->db->select('wsid, name')
->distinct()
->from('purchases')
->join('sheets', 'sheets.wsid = purchases.wsid')
->where('uid ='.$uid)
->get();
// nb. didn't check your join() syntax, either :)
}
Probably off-topic: CodeIgniter's Active Record is more of a query builder than an implementation of Active Record. In case you're wondering. When viewed as a query builder, it makes a bit more sense ;) FWIW, I do love CodeIgniter. I jest from affection.
Query binding is the easiest to implement and does the same thing query building does - and doesn't limit you as much as you will find building does.
$query = $this->db->query('SELECT something FROM table WHERE name1=? AND name2=?', array($name1, $name2);
$result = $query->result();
http://codeigniter.com/user_guide/database/queries.html