I'm having trouble getting the results of a has_many query using php idiorm/paris. Following the example from the paris site the has_many result for posts returns as an object.
That's great, and I can run through the object and access individual methods, but what I want to be able to do is pass the result set as an associative array off to my template engine for display.
Example:
class Post extends Model {
}
class User extends Model {
public function posts() {
return $this->has_many('Post'); // Note we use the model name literally - not a pluralised version
}
}
The api works this way:
// Select a particular user from the database
$user = Model::factory('User')->find_one($user_id);
// Find the posts associated with the user
$posts = $user->posts()->find_many();
I am able to access the posts object and print the result set like this:
// echo each post id
foreach ($posts as $post) {
echo $post->id;
}
What I'd really like to be to do though, is use as_array() to get the entire resultset as an associative array, limited by certain fields in the way as_array works for an individual row, e.g.
$post_list = $posts()->as_array(id,title,post,date);
This, or a call on something like $user->posts()->find_many()->as_array() don't work.
What is the correct way to access this type of result set using paris?
Adding this method to idiorm.php gives me the desired functionality.
public function find_array() {
if (func_num_args() === 0) {
return $this->_run();
}
$args = func_get_args();
$array = array();
foreach ($this->_run() as $r) {
$array[] = array_intersect_key($r, array_flip($args));
}
return $array;
}
Now I can call $post_list = $posts()->find_array(); or $posts()->find_array('id','title'); etc.
find_one returns a Model object, find_many returns an array of Models.
If you want to get the entire result set as an array of associative array, one solution should be to use array_map
function model_as_array($model) {
return $model->as_array();
}
$posts = $user->posts()->find_many();
$my_view->posts = array_map(model_as_array, $posts);
var_dump($my_view->posts);
or in php 5.3+ (not tested)
$aa_posts = array_map(function($model) {return $model->as_array();} , $posts);
Related
In my Symfony project I am returning all objects with Doctrine query builder defined with Paginator.
When dumping $posts['data'], response is on the image: IMAGE
When entering the loop and dumping first result, this is what I get: IMAGE
I want on each array object to assign new key-value pair. Every array object has destinationId (you can see on the image), and I have a method that searches for the name by that param.
I want to assign that new value to every object in foreach.
Code:
$posts = $this->entityManager->getRepository(Post::class)->getPage();
foreach ($posts['data'] as $postsData) {
foreach ($postsData as $post) {
$destinationName = $this->destinationService->getDestinationNameById(
$post->getDestinationId()
);
$postsData['destinationName'] = $destinationName;
}
}
Error is:
Call to a member function getDestinationId() on string
This is very odd as this field has entity type defined as string and also when dumping
dump($post->getDestinationId());
I get: "107869901061558" which is string.
It's because you override you $postsData variable.
You need to use a different variable to store your $destinationName like this :
$posts = $this->entityManager->getRepository(Post::class)->getPage();
$destinationNames = [];
foreach ($posts['data'] as $postsData) {
foreach ($postsData as $post) {
$destinationName = $this->destinationService->getDestinationNameById(
$post->getDestinationId()
);
$destinationNames[$post->getId()] = $destinationName;
}
}
Like this, you could send $destinationNames to your template and find the right $destinationName thanks to the index.
I have 2 tables, one is magazine and the other is issues. I have set up their relationship like this:
Magazine model:
public function issues()
{
return $this->hasMany('App\Issue')->orderBy('date', 'desc');
}
Issue model:
public function magazine()
{
return $this->belongsTo('App\Magazine');
}
I have a query where I get magazines ordered by a column and then in foreach loop I am getting the first issue of each magazine and storing it in array:
$magazines = Magazine::with('issues')->orderBy('order')->get();
foreach ($magazines as $magazine)
{
$issues[] = $magazine->issues()->first();
$images[] = $magazine->issues()->first()->image;
}
But, I would like to make a collection instead of an array. I am not sure how can I do that kind of query or is there a way to somehow store values to a collection in a foreach loop?
There are several ways of doing this.
You can turn an array into a collection by doing the following.
$issuesCollection = collect($issues);
$imagesCollection = collect($images);
You could also initialize an empty collection and then use the push() method to append items to it. Check the documentation
Just use the map function:
$magazines = Magazine::with('issues')->orderBy('order')->get();
$firstIssues = $magazines->map(function($magazine) {
return $magazine->issues->first();
});
$images = $firstIssues->map(function($issue) {
return $issue->image;
});
The map method iterates through the collection and passes each value
to the given callback. The callback is free to modify the item and
return it, thus forming a new collection of modified items
In my controller, I can get the organization name but when I pass it to the view
there's an error. It said invalid argument supplied for foreach( ):
.
This is my codes.
Controller
public function index()
{
$user_id = $this->session->userdata('user_id');
$data['title'] = "User";
$getID['orgID'] = $this->userModel->getOrganizationID($user_id); // used my session user_id to
foreach ($getID['orgID'] as $orgID)
{
$org_id = $orgID->org_id;
$getName['myOrganization'] = $this->userModel->myOrganization($org_id);
foreach($getName['myOrganization'] as $orgName)
{
$name = $orgName->org_name;
$data['name'] = $name;
}
}
$this->load->view('xxxx/xxxx/xxxx',$data);
Model
public function getOrganizationID($user_id)
{
$this->db->select('org_id');
$this->db->from('organization_members');
$this->db->where('user_id', $user_id);
$query = $this->db->get();
return $query->result();
}
public function myOrganization($org_id)
{
$this->db->select('org_name');
$this->db->from('tblorganization');
$this->db->where('org_id', $org_id);
$query = $this->db->get();
return $query->result();
}
My output
First array is my result of $getID['orgID'] = $this->userModel->getOrganizationID($user_id); which I used my user_id session to get all the org_id of the user then
Second array is my result of $getName['myOrganization'] = $this->userModel->myOrganization($org_id); which I used my org_id(from my previous method) to get all the org_name of the user.
Is there going to be more then one result? Because if its only one result then you can use $query->row(); and eliminate the foreach completely.
Always check to make sure your database method worked AND that you actually got a returned value whenever you are making any database call. So i'll let you add the if condition in the database method but in short it should return FALSE if nothing came back. So thats the database method heres one way of doing it in your controller. Note this: $getID['orgID'] is very awkward. You are getting results back from the members table so call it members.
// check for the negative first - if no members came back
if( ! $members = $this->userModel->getOrganizationID($user_id) )
{
// if no results back leave this method
// pass the user id so you can echo it out in the error page
$this->showNoResultsFor($user_id) ;
}
else{
foreach ($members as $member)
{
$org_id = $member->org_id;
// etc etc etc
I'm not a codeigniter expert but looking at your code, I am wondering why you are setting:
$getID['orgID'] = $this->userModel->getOrganizationID($user_id);
First, you are setting an array $getID['orgID'] rather than just using something like $memberships = ...; I'm not sure why you are casting an array.
Secondly, you seem to be referencing a model class without instantiating it:
$this->userModel->getOrganizationID($user_id);
Perhaps codeigniter does some magic? $this refers to this instance and from the code you show, your model is likely in a separate class/file so I am unclear how $this->userModel is referenced in your method, unless you are instantiating it in your Controller's constructor?
From what I see it looks like you are getting the error because you are not supplying a valid object/array to your foreach. Perhaps start by testing you are actually getting a valid return from $this->userModel->getOrganizationID($user_id).
I am new to MVC, I am porting a project written in non-MVC style to MVC, but I am stuck on a problem where it is necessary to call Model function in View.
Scenario:
Table1 - Products:
contains product_id, product_name etc. and for each product there can be multiple versions.
Table2 - Versions:
contains version_id, version_name, ... , product_id etc.
Now in the View I am displaying products and under each product heading I have to display version list of that product, in non-MVC style it was pretty simple, I can use the following code snippet in View:
foreach ($product as $row)
{
echo $row['product_name'];
if ($main->getVersionList($vresult,$row["product_id"]))
{
foreach ($vresult as $vrow)
{
echo $vrow['version_name'];
}
}
}
Now, I can pass Product array from controller to view but what about each Version array which needs to be generated corresponding to each product?
Update:
This is my final working solution (used a map), in controller:
$this->load->model ( 'product_mod' );
$data ['products'] = $this->product_mod->getProductList ();
$data ['versions'] = array ();
foreach ( $data ['products'] as $product )
{
$data ['versions'] [$product['product_id']] = $this->product_mod->getVersionList ( $product['product_id'] );
}
MVC or not to MVC
The first thing I should note is that It is impossible to write classical MVC in PHP. In fact the MVC-like PHP frameworks such as CodeIgniter or Yii implements sort of MVP in which:
view is passive and unaware of model
presenter (controller) changes state of model, reads information and passes it to view
Credits to tereško
CodeIgniter Approach
However, particularly in CodeIgniter, you have 3 steps:
Create a Model to query through the database and return the data (as an array or object)
Create a Controller to load and fetch the result from the Model (a method of the Model), and pass the returned data to the view
Create a View and use PHP loops to echo the result out, build the HTML.
Getting all together
Considering the above approach, you need to fetch the result from the database in your Model:
application/models/product.php
class Product extends CI_Model
{
public function get_product($product_id)
{
$this->db->select('*')->from('products');
$this->db->where('product_id', $product_id);
$this->db->join('versions', 'versions.product_id = products.product_id');
$query=$this->db->get();
return $query->first_row('array');
}
}
Then fetch and pass the result within the Controller:
application/controllers/products.php
class Products extends CI_Controller
{
public function view($product_id)
{
$this->load->model('product');
// Fetch the result from the database
$data['product'] = $this->product->get_product($product_id);
// Pass the result to the view
$this->load->view('product_view', $data);
}
}
Finally, use the returned data in the view, to generate the list:
application/views/product_view.php
// Use $product to display the product.
print_r($product);
You should do mysql query in your model, for example products_model (don't forget to load it)
Example Query : This is just select * from products
public function All_Products()
{
$this->db->select('');
$result = $this->db->get('products')->result_array();
return $result;
}
So as I see , you are foreach guy like me, rather than using mass queries.
In your controller you could load $products my your model.
$products = $this->products_model->All_Products();
My solution is creating a new array then putting new values in it.Also you need to getVersionList function in your model.
$newArray = array ();
foreach ( $products as $values ) {
$version = $this->products_model->getVersionList($values['product_id']);
$tmp = array (
'product_id' => $values ['product_id'],
'product_name' => $values ['product_name'],
'version' => $version
);
array_push ( $newArray, $tmp );
}
So add your new array to $data you could have them in your view file.
$data ['products'] = $newArray;
Sorry I didnt figure out all your queries but I think its better to teach how to catch fish than giving a fish.
Using the below code you can call the model's method in the view file. It's worked for me and is so simple also.
$CI =& get_instance();
$CI->model_name->method_name();
I can't figure this out. I've create a simple class that returns an array of arrays. Here is the class contructor...
class BlogComments {
public $commentArray=array();
public $blogId;
function __construct($inId) {
if(!empty($inId)) {
$this->blogId=$inId;
$sql="select id,name,url,comment,email from blog_comment where blog_id=$inId";
$link2=GetConnection();
$query=mysql_query($sql,$link2) or die("Invalid blog id:".mysql_error());
while($row=mysql_fetch_array($query)) {
$this->commentArray=array(
"id"=>$row['id'],
"name"=>$row['name'],
"url"=>$row['url'],
"email"=>$row['email'],
"comment"=>$row['comment']
);
}
mysql_close($link2);
}
}
}
I'm trying to access each member of the array via a loop. It's entering the loop but the values returned are empty. I've verified that data is being written into the array. Here's my code...
include "include/commentclass.php";
$comments = new BlogComments($post->id);
foreach($comments as $comment) {
echo "<h4>".$comment->commentArray['name']."</h4>
".$comment->commentArray['url']."
<p>".$comment->commentArray['comment']."</p>";
}
Basically it returns empty tags. I've also verified that $post->id holds a valid value. Any ideas what I'm doing wrong?
Thanks for the help,
B
You are doing some mistakes, the first is the one netcoder pointed out: you are using the object as an array without implementing an Iterator interface. The second is that you are assigning directly the result array to $this->commentArray. You should append the result to the array this way: $this->commentArray[] = array(
Try this:
$comments = new BlogComments($post->id);
foreach ($comments->commentArray as $comment) {
echo "<h4>".$comment['name']."</h4>
".$comment['url']."
<p>".$comment['comment']."</p>";
}
The new keyword returns a single object. Unless your object (BlogComments) implements Traversable, foreach will act on the public properties commentArray and blogId, and not on the commentArray contents.
You could also have your class implement an Iterator interface.