Creating a multidimensional array of data pulled from database - php

I am using codeIgniter. I need to create a multidimensional array of the data from the DB nammed college. The database has 3 columns: id, OfID and name. The OfID column contains the ID of the parent of that college. For colleges who don't have any parent have OfID as 0.
The array should contain the name, ID and OfID of colleges who have OfID=0 as the elements of first dimension. For colleges which have OfID!=0 should be put as 2nd (and so on) dimension array for the college whose ID they have as OfID.
I thought to do this recursively , but I am unable to finish this. I know there are a lot of mistakes in this please help.
The model class follows: (the controller calls meth() function)
class Model extends CI_Model
{
var $return_this=array();
function meth()
{
$loop_id=0;
getit($loop_id);
var_dump($return_this);
}
function getit($loop_id)
{
$index=0;
$query = $this->db->query("select * from college where OfID=$loop_id ORDER BY `OfID` ASC;");
if ($query->num_rows() > 0)
{
foreach ($query->result() as $row)
{
$pass=$row->id;
$temp=getit($pass);
if($temp==0)
$return_this[$loop_id]= $query->result();
}
}
else return 0;
}
}

Try something like this:
$rows = array();
foreach ($query->result() as $row)
{
$pass=$row->id;
$rows[] = getit($pass);
}
return $rows;
In any case, the best way I found myself to do recursion, is to take some recursive function that is really simple and you know every aspect about it, and to build it up step by step. By "step by step" I mean at first you don't pass all the values, but print them out, just to see what, where and how you get, then try to pass them. Recursive functions such as this one are brain damaging if you don't understand how it works.
The idea behind your one, is to get an array every time you stumble upon a college that has child colleges. I can see you get it right, just try to make this one as I told earlier - step by step and you will get a hang of it.

Related

Fetch data from many to many relationship with eloquent

I have 2 models, store and dvd with many to many relationship
dvd model:
public function stores() {
return $this->belongsToMany('App\store');
}
store model:
public function dvds ( ) {
return $this->belongsToMany('App\dvd');
}
Then, in controller, when I need fetch data from both models, I use code like this:
$res_store = store::orderBy("id","desc")->get();
foreach( $res_store as $row ) {
$dvds = $row->dvds()->get();
foreach ($dvds as $dvd) {
// echo columns here
}
}
This works, but my question is, I'm doing this in correct way? I'm asking because it seems 2 loops for this simple relation is somehow inefficient.
No, this is not the right way.
When looping over a $store, you can access the associated $dvd records via $store->dvds; there is no need to call $row->dvds()->get(), as that is executing a new query with the same result of $store->dvds. Full code should simply be:
$stores = Store::with("dvds")->orderBy("id", "DESC")->get();
foreach($stores AS $store){
foreach($store->dvds AS $dvd){
... // Do something with `$dvd`
}
}
The ::with("dvds") clause is known as "Eager loading", and prevents $store->dvds from needing execute another query behind the scenes.
Also, please name your models correctly. Classes in PHP are StudlyCase, so Store and DVD, not store and dvd.

How to match data from two different database tables and display it

I am looking for a solution which would withdraw essential data used to match other data from a different table. Then I would like to display this data inside a blade in a form of a table.
Inside the database, I have a "matching" entity which stores user's credentials which I would like to use for matching (for example desired price of the product). Entity contains "peopleID" as "matching" belongs to website users. When user is created, we assign matching options which are getting stored inside that "matching" entity. The number of rows inside Matching entity depends on the number of counties chosen during user creation stage.
I know that to withdraw matching data from the database I need to use a foreach loop.
The problem I have is when I output data inside the blade. For some reason it matches products only with the last item from an array. It should match prodtucts with all matching credentials.
Code:
$matchings = Match::where('PeopleID', '=', $id)->get();
$sales = DB::table('sales');
foreach ($matchings as $matching)
{
$county = $matching->county;
$sales->where('county', '=', $county);
}
$results = $sales->get();
So for one of the customers I have two matchings with different "counties". It only displays data for the last one added. How could I make it display data for other matching which contains a different county. I hope you know what I mean.
Thanks for any help.
Update - Major part of the code is done. Thank you for your help.
The second question is about adding the rest of matching options. As stated before the number of matches depends on the number of counties added. Each match has its own attributes. The idea is to show matched results for each county.
I know I will need some if statements to do this.
Here is an example which I would like to implement:
$maxprice = $match->maxprice;
$minprice = $match->minprice;
$brand_a = $match->brand_a;
$brand_b = $match->brand_b;
if($maxprice != '0')
{
$sales = DB::table('sales')->where('maxprice', '<=', $maxprice);
}
if($minprice != '0')
{
$sales = DB::table('sales')->where('minprice', '>=', $minprice);
}
if($brand_a == '1')
{
$sales = DB::table('sales')->where('brand_a', '1');
}
if($brand_b == '1')
{
$sales = DB::table('sales')->where('brand_b', '1');
}
To this code:
$user = User::find($id); // get our User with the Id (person id?)
$matches = $user->matches; // get all the matches
// or you could one line the above: $matches = User::find($id)->matches;
// get all the counties in the returned matches, could use pluck() method in higher version of laravel
$counties = [];
foreach($matches as $match) {
$counties[] = $match->county;
}
$results = DB::table('sales')->whereIn('county', $counties)->get();
Many Thanks for your help!
#update
Relationships:
Match:
public function people()
{
return $this->belongsTo('People', 'PeopleID', 'PeopleID');
}
People:
public function matches()
{
return $this->hasMany('Match', 'PeopleID', 'PeopleID');
}
I have a connection between those as Match holds people's "search" credentials. The first solution which you have provided works perfectly. Now, this solution filtered out sales by county which is a good move as now they need to be filtered by minimum and maximum price (minprice, maxprice) and other credentials such as brand_a and brand_b.
The idea of brand_a and brand_b:
Checkboxes are responsible for changing brand_a and brand_b value inside Matching. If these are checked the values inside Matching entity become '1'. If these are not checked they become '0' which means that sales don't have to be filtered out by those values.
Sales entity contains "Holdings" attribute. The value of "Holdings" can be brand_a or brand_b. Sales also contains "Price".
So, to make this clear:
Sale Entity contains: SaleID, Price, Holdings, County.
Holdings are values: brand_a or brand_b.
Price is just a number.
County is plain text.
Matching Entity contains: PeopleID, MinimumPrice, MaximumPrice, brand_a, brand_b, county.
PeopleID is a foreign key. We need to know which matching belongs to what user.
(there can be multiple matchings for one user depending on the number of counties chosen).
MinimumPrice and MaximumPrice are numbers.
brand_a and brand_b are the values (1 or 0) depending if the checkboxes were checked.
County is the name of a county.
Now, if person 1543 (peopleID = 1543) contains 3 matchings, each containing different search credentials.
1st:
PeopleID: 1543
MinimumPrice: 1000
MaximumPrice: 7000
brand_a: 0
brand_b: 1
county: county_a
2nd:
PeopleID: 1543
MinimumPrice: 2500
MaximumPrice: 10000
brand_a: 1
brand_b: 1
county: county_f
3rd:
PeopleID: 1543
MiniumPrice: 2000
MaximumPrice:9500
brand_a: 0
brand_b: 0
county: county_d
I need to match this data against the data that is inside the Sales. There can be over a 1,000 different sales with different prices etc. I just need to filter them and display Sales that are desired by the person based on person's matching.
I hope this better presents you the situation. Thanks.
In short, I belive you need to leverage Eloquent Relationships to easily retrieve the data you desire. Read up on relationships in the docs here: https://laravel.com/docs/4.2/eloquent#relationships.
I've made some assumptions so you may need to work the following into your actual setup. Also, I found it quite difficult to 100% understand your DB structure from your question, but from what I gather from your question your DB structure is like this:
User/Person *has many* Match
(Note: Name may be wrong, but you didn't mention what it's called in the question all I can see is the word "user" and "personId")
Match *belongs to* User/Person
Based on this I think you should set up your relationships like this:
User
class User extends Eloquent {
public function matches()
{
return $this->hasMany('Match');
}
//...
}
Match
class Match extends Eloquent {
public function user()
{
return $this->belongsTo('User');
}
//...
}
Then your code can look like this:
$user = User::find($id); // get our User with the Id (person id?)
$matches = $user->matches; // get all the matches
// or you could one line the above: $matches = User::find($id)->matches;
// get all the counties in the returned matches, could use pluck() method in higher version of laravel
$counties = [];
foreach($matches as $match) {
$counties[] = $match->county;
}
$results = DB::table('sales')->whereIn('county', $counties)->get();
A better approach to this issue (I think) would be to give County it's own entity then Match would have a county_id then you can use a has many through relationship if you can link up Match, County and Sales. You can read more about has many through in the docs here: https://laravel.com/docs/4.2/eloquent#has-many-through
Also, a side point... this part of your code:
$sales->where('county', '=', $county);
will just continuously add where statements to your query which I would imagine won't return anything if there's more than one.
Just to make this clearer, imagine you have 2 counties "county_1" and county "county_2", through your for loop your query would end up like this:
WHERE COUNTY = "county_1" // first loop
AND COUNTY = "county_2" // second loop
and as you can see a match cannot be two counties at one time! So you were probably looking for ->orWhere('county', 'county_value') after the first one was added, but a better approach is to use whereIn('county', $countiesArray) which you can pass an array you've built up, which is what I've done above.
Hope this helps! Let me know if it wasn't clear.
Edit
The best approach would be to establish relationships between the Sale and Match entities. As I still don't fully understand your database schema I can't advise so well on how you would approach that. If you gave some more details it may be possible.
Alternatively, you could approach the code by building up an array which you will use for applying conditions to your query. Consider your updated question with the four if statements, anytime you're repeating yourself like that, more often that not it can be simplified.
$filters = [
'maxprice' => $match->maxprice,
'minprice' => $match->minprice,
'brand_a' => $match->brand_a,
'brand_b' => $match->brand_b,
];
$salesQuery = DB::table('sales');
foreach($filters as $key => $value) {
if($value) {
$salesQuery->where($key, $value);
}
}
$results = $salesQuery->get();
As your conditionals are a bit stricter in your code from your question, you do to it like this instead:
foreach($filters as $key => $value) {
if ($value) {
if (in_array(['brand_a', 'brand_b'], $key)) {
$salesQuery->where($key, $value);
} else if($key === 'minprice') {
$salesQuery->where($key, '>=' $value);
} else if($key === 'maxprice') {
$salesQuery->where($key, '<=' $value);
}
}
}
the good thing about this approach is that you can easily add new conditionals via the filters array without having to write a new if statement and query/where code each time.
I'll stress this probably isn't the best approach, ideally you'd leverage Eloquent Relationships, but it may be a starting point if you can't figure that out right away.

Codeigniter - Use the id from a query result in a model to query in a different function in the same model

I'm using codeigniter to code my site and I'm running into a roadblock. I know how to do this in regular, non "MVC", not OOP PHP, but am struggling on it in Codeigniter.
I have blog_model.php, which has a function to retrieve the datetime from my database, explode it into an array so that I can work with it outside the model and feed it into CSS where I have individual calendar icons for it. Each calendar icon is loaded by the month number in the view (<div class='calendar-icon-$stats['date']). This function also pulls the amount of comments from that individual post and outputs it into an array so that I can show it in the view.
public function get_stats($id) {
$this->db->select('id,datetime')->from('blog_posts')->where('id',$id);
$dquery = $this->db->get();
$dquery = $dquery->row_array();
$date = date('Y-m-d', strtotime($dquery['datetime']));
$stats = explode("-", $date); // This makes $stats[0] the year, $stats[1] the month and $stats[2] the day.
$stats['time'] = date('H:i', strtotime($dquery['datetime']));
$stats['comcount'] = $this->db->get_where('blog_comments', array('blogid' => $id));
$stats['comcount'] = $stats['comcount']->num_rows();
return $stats;
}
There is also a function to retrieve the three most recent entries:
public function get_blog_last() {
$query = $this->db->order_by('id desc')->get('blog_posts',3);
return $query->result_array();
}
This code is then loaded into my controller and sent to the view to be displayed:
$data['blog'] = $this->blog_model->get_blog_last();
$data['stats'] = $this->blog_model->get_stats($data['blog']);
$this->load->view('index',$data);
The problem I face is how to get the get_stats() function to run for every entry I have on the index page, where the last three entries are displayed. So far I can only get it to run for one of them, therefore all three of the entries on my front page have the same date, the same time and the same amount of comments. I figured putting the code in a model would save myself from repeating myself when I had to load it for the archives page (where I display all the posts from the month) and the main entry page where I just display that entry and its comments.
So, the ultimate question here is:
How do I run get_stats for every entry I have on a given page?
I'm also having a bit of issue figuring out the correct value to pass to my get_stats() function.
Any guidance would be appreciated. Thank you in advance.
If I'm understanding correctly, you need to call get_stats for each of the three entries that you receive in get_blog_last. If that is the case, just change get_blog_last to this:
public function get_blog_last() {
$query = $this->db->order_by('id desc')->get('blog_posts',3);
$entries = $query->result_array(); // get the latest entries array
foreach ($entries as $index => $entry) { // loop through those entries
$stats = $this->get_stats($entry['id']); // call this model's `get_stats` method
$entries[$index]['stats'] = $stats; // add a `stats` key to the entry array
}
return $entries;
}
Why don't you put
$this->blog_model->get_stats($data['blog']);
inside loop ? ( i'd rather use normal loop )
example :
$stat_list = array();
for($i=0;$i<count($data['blog']);$i++){
$stat_list[] = $this->blog_model->get_stats($data['blog'][$i]);
}
$data['stats'] = $stat_list;
and in your view, you should try the same to print out each $stat_list

PHP MVC loop in the view

I consider myself as a php beginner, so it may be possible that this question is too easy for someone, but I got really confused on how to solve it. I am trying to loop something from the database in my views. So, in a quick way I solved it like this:
I've created a function in my model that does the loop and in the same time is creating the html and saves it in a variable. Then, I get that variable from my controller and I pass it in my view. But, it seems that this is not a good way to solve it, since if I want to change my html I need to enter my model function instead some of the view files.
Then, I've created another function in my model that looks like this:
function displayUsers() {
$sql = $this->pdo->prepare('select * from user');
$sql->execute();
while($row = $sql->fetch())
$results[] = $row;
return $results;
}
Now... I take the result in my controller, and send it in the view, but then... I don't know how to extract the results from my variable. I have done something like this:
while($output) {
foreach($output[$i] as $key => $value)
$data[$key] = $value;
echo $data['email'];
$i++;
}
But then, in the end it says to me undefined offset, which means I am referring to an array key that doesn't exist. Can anyone help me on how to solve this issue?
Proper MVC shouldn't have any output in the model or the controller.
Ideally you would have a model that just gets the raw data and returns it in the controller. The controller can then build up an array of values that we'll call data. For example:
Controller
$data['users'] = $this->MyModel->getusers(); // Getting the users from your model
$data['posts'] = $this->MyModel->getposts(); // Getting the posts from your model
$this->getTemplate('userdisplay', $data); // Get the template userdisplay and pass data
This gets the data from the model, and then assigns it to a key within the "data" variable. You can then pass the data variable into the template. You'll then have two variables to work with in the template, $users and $posts.
You'll need a "getTemplate" function that properly maps the data array to individual variables for use in the template, but all of the display should be located in the template.
To answer your specific question at the end, something like this should work in the template:
if (count($users) > 0) {
foreach ($users as $person) {
echo $person['email'];
}
}
You should be able to do this:
foreach($output as $row) {
echo $row['email'];
}

Cakephp 1.3 HABTM issue! :D

Hey, im having this issue with cakephp, bascially i have a Has And Belongs To Many (HABTM) model relationship.
My models are Categroy and Project
bring all project data is fine, it comes out as [0]['Project'], [1]['Project'] ...etc
but when i use the relationship and pull out projects with certain categories in the categories controller i get these tpye of results [0] (all project data in [0] instead of [0]['Project']), [1] (project data and related model info) this is really messing my code up as i use one element view file to render my projects is there any way to return [0]['Project'] for both project controller and categories controller? thanks Chris
Hi sorry if my example isnt clear
i have projects and categories
when i pull a list of projects from the projects controller from my project model the results i get are in this format
[0]['Project'] = array(data...);
[1]['Project'] = array(data...);
[2]['Project'] = array(data...);
this is how the data is pulled and thats fine for me but when i pull projects per cetegory page using the HABTM relationship in the categories controller from the category model this is how my data is returned
['Project'][0] = array(data...);
['Project'][1] = array(data...);
['Project'][2] = array(data...);
which as you can see is a bit of a strain as i want to keep 1 element view file to display my projects, so far my view file prints data like so
<?php print $project['Project']['title']; ?> //data is returned [x]['Project']
<?php print $project['Feature']['title']; ?>
with the way the HABTM relationship is returning data i would need to do this
<?php print $project['title']; ?> //because data is returned ['Project'][x]
<?php print $project['Feature']['title']; ?>
can anyone help with this? thanks
This has frustrated me too. I like to have one set of elements that can be used for rendering both "primary" find results as well as related find results.
This is the way I currently deal with the differences in formats of results.
When calling find on, say, a "Project" model and wanting to render the related "Task" list, I run the "Task" key of the results through a function on its way into the element like so:
echo $this->element('tasks/index',array(
'data'=>make_primary('Task',$data['Task'])
));
My 'make_primary' function is like so:
function make_primary($alias,$data) {
$d = array();
foreach($data as $item) {
$related = array();
foreach($item as $key => $val) {
if(!is_numeric($key) && is_array($val)) {
$related[$key] = $val;
unset($item[$key]);
}
}
$d[] = array_merge(array($alias=>$item), $related);
}
return $d;
}
This returns a new array as though it was the result of a "primary" find query.

Categories