I'm writing an invoicing application in CodeIgniter/DataMapper.
Each customer has many invoices.
In the view, I want to be able to display customer data and then a table of the invoices for that customer.
At the moment, I load the customer and their related invoices in the controller and send them to the view.
public function view($id) {
$c = new Customer($id);
$c->invoice->get_iterated();
$data['customer'] = $c;
}
But when I iterate over the invoices to display them in the view, I really want them to be in descending order by date, but of course they're not.
Is there any way to specify the order of related items or to sort them before displaying them, or do I need to load the invoices separately, something like in the following the controller?
public function view($id) {
$c = new Customer($id);
$i = new Invoice();
$i->order_by('invoice_date', 'desc');
$i->get_where(array('customer_id' => $id));
$data['customer'] = $c;
$data['invoices'] = $i;
}
You can simply add an ->order_by() call before issuing the get_iterated(). So in your examples it would look something like:
$c->invoice->order_by('invoice_date', 'desc')->get_iterated();
Related
I want to loop over a collection of items and attach a relationship based on if a particular condition is satisfied. Here is my code
public function bulkAssign()
{
$trainers = MasterTrainer::all();
for ($i=0; $i < count($trainers); $i++) {
$this->assignToManager($trainers[$i]);
}
// return redirect()->back()->with('success', 'Project Managers Assigned Successfully');
}
private function assignToManager($trainer)
{
$manager = ProjectManager::where('state', $trainer->state)->first();
return $trainer->update([
'project_manager_id' => $manager->id
]);
}
What I get is it attaches only the first manager to all the elements in the collection. What am i doing wrong?
can you inline the func for now? do some sort of echo/debugging?
but also I see several issues:
yes do use foreach because that is a bit better and you avoid having to use $i (making code a little more easy to read)
you are not attaching a relationship, you are setting a project_manager_id (i say this because initially i automatically thought you were going to dynamically add a relationship to model)
without knowing your db schema.. could you not do some sort of trick to avoid having to do this nth times?
$manager = ProjectManager::where('state', $trainer->state)->first();
you could either do:
$states = $trainers->pluck('states');
$managers = // do a query to get one trainer per state using group by
foreach ($trainers... ) {
$manager = $managers->where('state', $trainers->state)->first() // this is collection not eloquent
$trainer->update([
'project_manager_id' => $manager->id
]);
other would be to create a scope where you do a sub query to get manager id when u query for trainers
I want to add Order search functionality in customer account My Orders section. As if customer have many orders so they dont need to navigate instead of they can search by orders like this -
http://demo.dckap.com/m2/sales/order/history/
I tried to get customer session in Magento_Sales/templates/order/history.phtml page but its not working.
Is there any way we can pass input search box value to order object ?
Or Load customer orders collection ?
you need to override few files. you can try with below code, it should work.
for view access, override canView() function defined in Magento\Sales\Controller\AbstractController\OrderViewAuthorization.php
//overide getOrders() method in history.php block file as below
// to get customer id from customer session
if (!($customerId = $this->_customerSession->getCustomerId())) {
return false;
}
// to load orders for customer
$this->orders = $this->_orderCollectionFactory->create()->addFieldToFilter('customer_id', array('eq' => $customerId));
//to add filter for search
if (!empty(<yoursearchterm>)) {
$this->orders->addFieldToFilter(
'entity_id', ['like' => '%' . <yoursearchterm> . '%']
);
}
and finally add below line
return $this->orders;
Next you will need to override history.phtml and add your search boxes inside form. you can set action like below
action="<?php echo $block->getUrl('sales/order/history'); ?>"
Hope this helps!!
This is my solution to load logged In customer orders collection -
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$resource = $objectManager->get('Magento\Framework\App\ResourceConnection');
$connection = $resource->getConnection();
$customerSession = $objectManager->create('Magento\Customer\Model\Session');
if ($customerSession->isLoggedIn()) {
$customer_id = $customerSession->getCustomer()->getId();
$order_collection = $objectManager->create('Magento\Sales\Model\Order')->getCollection()->addAttributeToFilter('customer_id', $customer_id)->addAttributeToFilter('increment_id', array('eq' => $orderId));
}
Then after that I have replace order collection with my order collection $order_collection to get desired search order value from text box.
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'm trying to make categorized gallery for my blog. So far I've created datebase with tables: photos (photos_id, photos_gal_id, photos_link), galeries (galeries_id, galeries_title, galeries_description), and there are other tables, but not related to this problem (such as users, posts etc).
I've established connection with db through init file:
<?php
class init {
protected $db, $result;
private $rows;
public function __construct(){
$this->db = new mysqli('localhost','root','hhpass','europa');
}
public function query ($sql){
$this->result = $this->db->query($sql);
}
public function rows(){
for($x =1; $x<= $this->db->affected_rows; $x++){
$this->rows[] = $this->result->fetch_assoc();
}
return $this->rows;
}
}?>
Then I get the data from DB through:
class Galeries extends Init {
public function fetchGaleries(){
//query db
$this->query("SELECT photos_id,
photos.photos_gal_id as 'group',
GROUP_CONCAT(photos_link) as link, galeries.galeries_title, galeries.galeries_description, galeries.galeries_id
FROM photos
INNER JOIN galeries
ON galeries.galeries_id=photos.photos_gal_id
GROUP BY photos.photos_gal_id
ORDER BY galeries.galeries_id ASC");
//return
return $this->rows();
}
}
So far it works fine.. when I call this function in seperate file with:
$galeries_a = new Galeries();
$gals_x = $galeries_a->fetchGaleries();
and if I use the
foreach($gals_x as $gals_y){
echo $gals_y['group'];
}
it does fine and lists galeries(categories): 1,2,3,4. Which are the DB-s groups, as defined by query.
NOW, the problem is, how to make the links show up inside these groups (only links that belong to that group).
I know I have to make UL/LI listings in HTML, and that is not the problem, that part works, the problem is the PHP part :)
To sum, it should look like this.
1 First Gallery
Link One
Link Two etc
2 Second Gallery
Link One
Link Two etc
3 Third Gallery
Link One
Link Two etc
4 Fourth Gallery
Link One
Link Two etc
I've tried everything: while, foreach, everything, cannot get it to work properly.
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