I have 3 mySQL tables: user, section and user_section (a joining table).
The SQL below:
SELECT id, description,
NOT ISNULL(
(SELECT user_id
FROM user_section
WHERE user_section.section_id = section.id
AND user_id=5)) AS user_in_section
FROM section
WHERE site_id = 3
nicely produces the following results:
id description user_in_section
3 section1 1
8 section2 0
9 section3 1
I have a form in my view to edit users and the sections they belong to. I'm writing the checkboxes out like so ($user_sections contains the above data):
<div class="checkboxes">
<?php foreach ($users_sections as $row) { ?>
<label class="checkbox"><input <?= ($row->checked>0?'checked':'') ?> type="checkbox" name="section[]" value="<?= $row->id ?>" /> <?= $row->description ?></label></br>
<?php } ?>
</div>
My questions are:
Is there a better way to write the sql query? Or is what I have good / the only way to get the data I want?
I want to use Datamapper ORM to write the query. I have this so far...
$section
->select('sections.id, description')
->select_func('NOT ISNULL', array('(SELECT id FROM sections_site_users where sections_site_users.site_section_id=sections.id and sections_site_users.site_user_id='.$user_id.')'), 'checked')
->where('site_id', $site_id)
->get();
The NOT before the ISNULL is being escaped with single quotes preventing the query from being correct sql. How can I write this properly in Datamapper?
Any suggestions for improvement greatly appreciated. Thanks in advance.
EDIT:
I have found a solution that works - here is my Datamapper code:
$sections = new Section();
$sections
->where('site_id', $site_id)
->get();
foreach ($sections as $s)
{
$s2 = new Section();
$s2
->where('id', $s->id)
->where_related('user', 'id', $user_id)
->get();
$s->checked = ($s2->exists() ? 1 : 0);
}
which produces the same data as the sql at the top of my answer. It does however use more database queries (I was hoping to do it in one database query).
Can anyone confirm for me that I've done the best thing here?
Thanks!
Yes! Simply:
$user = new User();
$sections = $user->section->where('id', $site_id)->get_iterated();
foreach($sections as $section)
{
// $section->id
// $section->description
}
But you have to set your relation properly!
ie:
Class user:
public $has_many = array('section);
Class section:
public $has_many = array('user');
Join table should be : users_sections
User table : users
section table : sections
Edit:
You want the section that have a specific user for a given site. You have a n relationship between sites and users. So you'll end loading the User first, then get his section:
$user = new User($user_id);
if ($user->result_count())
{
$sections = $user->section->where_related_site('id', $site_id)->get_iterated();
}
This should be fine. Sorry I didn't understand all at first.
A short description of your model would have help :)
Related
In Laravel 9 I am trying to add the result of a subquery to a query(for lack of better wording) and I am stuck. More concretely, I am trying to load all products and at the same time add information about whether the current user has bought that product.
Why do I want to do this?
I am currently loading all products, then loading all bought products, then comparing the 2 to determine if the user has bought a product, but that means extra queries which I would like to avoid. Pretend for the sake of this question that pagination doesn't exist(because when paginating the impact of those multiple queries is far diminished).
There is a many to many relationship between the 2 tables users and products, so these relationships are defined on the models:
public function products()
{
return $this->belongsToMany(Product::class);
}
and
public function users()
{
return $this->belongsToMany(User::class);
}
What I have tried so far:
I created a model for the join table and tried to use selectRaw to add the extra 'column' I want. This throws a SQL syntax error and I couldn't fix it.
$products = Product::query()
->select('id', 'name')
->selectRaw("ProductUser::where('user_id',$user->id)->where('product_id','products.id')->exists() as is_bought_by_auth_user")
->get();
I tried to use addSelect but that also didn't work.
$products = Product::query()
->select('id', 'name')
->addSelect(['is_bought_by_auth_user' => ProductUser::select('product_id')->where('user_id',$user?->id)->where('product_id','product.id')->first()])
->get();
I don't even need a select, I actually just need ProductUser::where('user_id',$user?->id)->where('product_id','product.id')->exists() but I don't know a method like addSelect for that.
The ProductUser table is defined fine btw, tried ProductUser::where('user_id',$user?->id)->where('product_id','product.id')->exists() with hardcoded product id and that worked as expected.
I tried to create a method on the product model hasBeenBoughtByAuthUser in which I wanted to check if Auth::user() bought the product but Auth wasn't recognized for some reason(and I thought it's not really nice to use Auth in the model anyway so didn't dig super deep with this approach).
$products = Product::query()
->select('id', 'name')
->addSelect(\DB::raw("(EXISTS (SELECT * FROM product_user WHERE product_users.product_id = product.id AND product_users.user_id = " . $user->id . ")) as is_bought_by_auth_user"))
->simplePaginate(40);
For all attempts $user=$request->user().
I don't know if I am missing something easy here but any hints in the right direction would be appreciated(would prefer not to use https://laravel.com/docs/9.x/eloquent-resources but if there is no other option I will try that as well).
Thanks for reading!
This should do,
$id = auth()->user()->id;
$products = Product::select(
'id',
'name',
DB::raw(
'(CASE WHEN EXISTS (
SELECT 1
FROM product_users
WHERE product_users.product_id = products.id
AND product_users.user_id = '.$id.'
) THEN "yes" ELSE "no" END) AS purchased'
)
);
return $products->paginate(10);
the collection will have purchased data which either have yes or no value
EDIT
If you want eloquent way you can try using withExists or withCount
i.e.
withExists the purchased field will have boolean value
$products = Product::select('id', 'name')->withExists(['users as purchased' => function($query) {
$query->where('user_id', auth()->user()->id);
}]);
withCount the purchased field will have count of found relationship rows
$products = Product::select('id', 'name')->withCount(['users as purchased' => function($query) {
$query->where('user_id', auth()->user()->id);
}]);
I'm trying to build a SQL query using doctrine. Here's my code snippet:
/**
* #Route("/db", name="user_skill_testing")
*/
public function dbTest()
{
//all skills for user
$userName = "Jelle";
$user = $this->getDoctrine()
->getRepository('AppBundle:User')
->findOneByFirstname($userName);
echo "userId: ".$user->getId()."<br />";
$userSkills = $this->getDoctrine()
->getRepository('AppBundle:Userskill')->findById($user->getId());
$proficiencies = array();
foreach ($userSkills as $userSkill) {
array_push($proficiencies, $userSkill);
echo $userSkill->getId();
echo "-";
echo $userSkill->getProficiency()->getId();
echo "<br />";
}
var_dump($userSkills);
$html = "<html><body>".$user->getFirstname()."<br /><br />"."</body></html>";
return new Response($html);
}
It returns the following webpage(screenshot):
When I look at the queries it ran...:
...and rerun them...:
...I get a very different result. :(
I have no idea why, can anyone help me out?
thank you!
Edit: using this code to build the query reproduces the same result.
The problem lies with your PK on UserSkill. When doctrine Hydrates, it will assume entities with the same primary key, are the same entity, ignoring rows with the same PK if one has already been hydrated.
Since your Userskill::$id is not unique, only the first one will be hydrated, subsequent rows with the same id, will get a reference to the same entity.
To solve this, you need to create a compound key, consisting of the id and the proficiencyId.
In you use-case though, this will make things unpractical. So I would just replace your manual id on Userskill with an actual one-to-many relation from Userto Userskill...
Having MySql generate the many-to-many relationship helped doctrine generate the correct entities.
I am looking for a way to retrieve all models in a database. Then loop through all of the models and read out the values for name, firstname and phonenumber.
So far I've gotten this and failed to go past it:
$searchModel = new EmployeeSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
I am then looking to implement those three values in a simple HTML table:
<tr><td>$firstname</td><td>$name</td><td>$phone</td></tr>
The table should be part of a PDF output, so ideally I would save it to a variable:
$html_table = '<tr><td>$firstname</td><td>$name</td><td>$phone</td></tr>';
I would need to get this for every model that fulfills the criteria of status = 'active' in the database.
So far I've only been able to get tables via gridView and not in a HTML template either.
You don't really need a data provider to achieve this, you could simply try :
$models = Employee::find()->where(['status'=>'active'])->orderBy('name ASC')->all();
foreach ($models as $model) {
echo "<tr><td>{$model->firstname}</td><td>{$model->name}</td><td>{$model->phone}</td></tr>";
}
Read more : http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#querying-data
You can get all models like this:
$employees = Employee::find()
->select('firstname, name, phone')
->asArray()
->where(['status'=>'active'])
->all();
This way you will get an array of arrays containing the 3 selected fields, so now you only need to use a foreach to loop through them and create the table:
$html = '<table>';
foreach($employees as $employee) {
$html .= '<tr><td>'.$employee['firstname'].'</td><td>'.$employee['name'].'</td><td>'.$employee['phone'].'</td></tr>';
}
$html .= '</table>'
Greetings,
Facts:
Database named -> acastro
Table called -> contacto
Fields in table are -> id, nome, email
I making an Yii2 application, and need to connect a highcharts chart to a table field in my database.
How can i inside an action called actionAdmin connect to my database and then count the number of id's in my Contacto table stored inside acastro database.
In the old Yii1.xx i used to establish connection this way:
public function actionAdmin() {
$sql = Yii::app()->db->createCommand('
SELECT count(*) as total
FROM contacto
')->queryAll();
$total = array();
for ($i = 0; $i < sizeof($sql); $i++){
$total[] = (int) $sql[$i]["total"];
}
$this->render('admin', array('total' => $total));
}
}
The problem is that this syntax no longer works in Yii2, and i've tried the sintaxe explained in Yii2 api guide but it always give's me error of undefined variable. Here is the code that i'm using to connect acording to Yii2 api guide:
use yii\db\Command;
$total = $connection->createCommand('SELECT count (*) FROM contacto')->queryAll();
What am i doing wrong ? Any solutions ?
Many thanks in advance.
I am not very sure that it will solve ur problem.
But in yii2 this the syntax
use app\models\Contacto; //look your Contacto Model namespace
$query = (new Query())->from('contacto');
$count = $query->count('column_name');
I hope this will help
The easiest syntax in Yii2 is:
$count=(new \yii\db\Query)->from('TBL_NAME')->count('*');
It just returns the count. For example: 500
I'm coming from codeigniter background. Unlike codeigniter helper directory, i just created helper directory within app directory of Laravel. Just want to know how to execute query within this common function. Here is my codeigniter function.
function show_menu($primary_key_col, $parent_id, $sort_order)
{
$output = "";
$ci =& get_instance();
$ci->db->select("*");
$ci->db->where('is_active', "Y");
$ci->db->where('is_delete', "N");
$ci->db->where('parent_id', $parent_id);
($sort_order!="")?$ci->db->order_by($sort_order, "ASC"):"";
$query = $ci->db->get('tbl_cms_menus');
foreach ($query->result() as $row){
$output .= '<option value="'.$row->$primary_key_col.'">'.$indent.$row->menu_name.'</option>';
}
return $output;
}
I tried something like this in laravel file. but this code did't give me any result. Please tell me where i'm doing wrong in this code. thanks
function databaseTable()
{
$table = DB::table('tbl_cms_menus');
$get_rows = $table->get();
$count_rows = $table->count();
if($count_rows > 0){
foreach ($get_rows as $tbl)
{
echo $tbl->menu_name;
}
}
}
This code will rot so hard that it shipped pre-rotten.
But, if you want to just.. ram it into the app all dry like that.. then add something like this to your base controller class...
$whatever = crazyChainingStuff;
foreach ($whatever ...) { $topMenu .= ... }
View::share('topMenu', $topMenu);
If you want to learn how to write code that will do less damage to your company and your clients then I recommend starting by watching Uncle Bob's "Fundamentals" videos. At least the first 5-6. http://cleancoders.com
It looks like you are trying to generate a drop-down/select with some data from your database, in this case, you should pass the data required for the drop-down/select from your controller to the view where you have written your HTML, for example, in your view, you may have a select like this:
echo Form::select('cms_menu', $cms_menu, Input::old('cms_menu'));
Or this (If you are using Blade):
{{ Form::select('cms_menu', $cms_menu, Input::old('cms_menu')) }}
From your controller you should pass the $cms_menu which should contain the menu-items as an arrtay and to populate that array you may try something like this:
$menuItems = DB::table('tbl_cms_menus')->lists('menu_name','id');
return View::make('your_view_name', array('cms_menu' => $menuItems));
Also, you may use something like this:
// Assumed you have a Page model
$menuItems = Page::lists('menu_name', 'id');
return View::make('your_view_name', array('cms_menu' => $menuItems));
You may also read this article which is about building a menu from database using view composer (More Laravelish way). Read more about Form::select on documentation.
It was too late to give an answer. I was also from CodeIgniter background and when I learnt Laravel then first I try to find how can I write a query in Helper. My Team leader helped me.
I have converted your code in a helper function.
function show_menu($primary_key_col, $parent_id, $sort_order)
{
$query = DB::table('tbl_cms_menus')
->select('*')
->where('is_active', '=', 'Y')
->where('is_delete', '=', 'N')
->where('parent_id', '=', $parent_id);
($sort_order != "")? $query->orderBy($sort_order, "ASC") : "";
$resultData = $query->get()->toArray();
}
Here $resultData will be array format. Now, you can create a foreach loop according to your requirement.