To implement this feature I had created a a column replyTo which relates to the comment_id in the same table. The original comments have this as 0. The problem I face is what could be the best way to show them.
In my model, I have created a function nested_comments() to get them and in my view I was doing like, this.
<? foreach( $comments as $comment ): ?>
....
<? foreach( $comment->nested_comments() as $comm): ?>
But that is only fine if I have one level of nested comments. Actually, I wish if there was a way to do this in the view. I don't wish to create another view file and controller for this purpose alone.
You can use function, Like below:
function getComments($comments){
if(!is_array($comments)){
return;
}
foreach($comments as $key => $value){
// do what you want with comments
getComments($nestedComments);
}
}
it's not ready to use function, but you can work in the same way.
You can achieve it with mptt modules, there are a few around:
https://github.com/spadefoot/kohana-orm-leap
https://github.com/rafi/orm-mptt
https://github.com/evopix/orm-mptt
I've been using third one but now its old and I suggest you to take a look at leap, it looks very promising.
And also take a look at http://kohana-modules.com/search?query=mptt
Related
I trying to get deep into WordPress development, I was wondering when we do var_dump($post->post_id), it gives a list of objects that, that function has. The reason I said objects, is I don't know what they are. While it gives you a comprehensive list of properties that you can access as the WordPress codex page state. My question is how can I access other function and its properties like:
`get_the_category();`, I might be naive to get a list of properties like
$category = get_the_category();
foreach ($category as $cat) {
echo $cat;
}
How can I access properties of a WordPress function, a example would be something like $category->ID() or other properties, other example might include
<?php
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
?>
<?php
$test = get_cat_ID($post->ID);
var_dump($test)
?>
<?php }
}
?>
But in that example, I get a int(0), so how can I get different properties on a post, like its category, slug, taxonomies etc.
I think what you're trying to do is to get information about the API programmatically. The problem is that PHP is not well suited to do something like that, because there are not static types. In any case, Wordpress makes use of on-the-fly generated objects and associative arrays. If the template function would actually return objects of a certain type, you could definitely look up the properties of this type and have your answer.
However, as this is not the case, all you really can do is to call the function in question once and then take a look at the result. In your case for example:
$category = get_the_category();
var_dump($category);
Of course, you could also take a look at the code to figure out how the result value will look like. This is quite cumbersome though, because there are usually a myriad of other functions being called to assemble the result.
Note: This will not work with all functions. There are some that actually output the result rather than returning it. You don't really need to investigate these, however, because their result is only a single string. (You can recognize these functions usually by their prefix the_, but not get_the_ as in your example.)
If I totally missed your point, let me know and I'll try again. ;-)
I am trying to get all stores on a Magento shop. By all stores, I mean all stores from all websites. I wrote this code and it works, but I'm a little concerned about the complexity of the nested foreach loop. Please take a look at it and advise me if you think I can do something different.
public function getAllStoresCustom(){
$all_stores = array();
foreach (Mage::app()->getWebsites() as $website) {
foreach ($website->getGroups() as $group) {
$all_stores [] = $group->getStores();
}
}
return $all_stores;
}
I've only found these functions in Magento, so I think I had to use those and this seemed the only combination that worked.
Thanks a lot
Try this:
$allStores = Mage::getModel('core/store')->getCollection();
Then loop through $allStores when needed
foreach ($allStores as $store) {
//do something with $store
}
Notice: You will get a store with id 0. That is the admin store view. If you want all stores without the admin store view use this:
$allStores = Mage::getModel('core/store')->getCollection()->setWithoutDefaultFilter()
foreach() is an incredibly efficient PHP function so you can bet that it is not going to be your slowdown. If you are looking to optimize something then look into the code for the getStores() and getGroups() functions because those are being called within the iterations whereas getWebsites() gets called only once.
If you want more guidance then please feel free to update your question with the contents of those functions.
You may also want to try https://codereview.stackexchange.com/ for more experienced opinions especially since you don't have any specific programming issue/error =)
I'm new to OOP and MVC and currently building a website using CodeIgniter.
There seems to be a lot of contrasting information about whether loops should be in the view or the model.
On the one hand I'm trying to keep all my html markup inside the views, but on the other hand I want to keep my messy PHP logic outside of the view. Plus I also need to format the data inside my loops using functions located in my model.
What's the best way to go about organising this?
Here is a simplified version of my current implementation:
View
<section>
<ul>
<?php echo $albumTracklistHtml ?>
</ul>
</section>
Controller
$data = [
'$albumTracklistHtml' => $this->MyModel->getAlbumTracklistHtml()
];
$this->load->view('myPage', $data);
Model
public function getAlbumTracklistHtml()
{
//$this->tracklisting returned from db call in other function
foreach($this->tracklisting as $song) {
$mp3 = $this->convertToAmazonUrl($song['mp3']);
$art = $this->formatArtUrl($song['art']);
$name = $this->formatTrackName($song['name']);
$class = 'mp3';
$btn ='';
if(substr($name, 0, 1) == '*') {
$class = 'load mp3';
$btn = '<span class="playBtn"></span>';
}
<li class="'.$class.'" '.$mp3.'>'.$btn.$name.'</li>';
}
}
Very generally speaking, and keep in mind that this isn't a hard and fast rule and if you ask ten different people you'll get ten slightly different answers, but the job of the model view and controller are essentially:
The model provides a way for the controller & view to access data from another source (a database, for instance). It's basically an abstraction on whatever your data is stored in.
The views simply display data they are given.
Controllers connect the model's data with the view, so it can display the data.
I would argue that the example code you've posted is just fine, and fits these definitions. Your model retrieves the data (or processes it), the controller hands the resulting data to the view, and the view simply displays it.
However, I also think it's fine (and generally I prefer this) for the model to simply return a list of items, and then for the view to loop through them and display each one. Of course, the view "shouldn't" be doing a lot of processing, but outputting HTML for each item seems like exactly what it should be doing. The reason I prefer this is purely for separating concerns - your models should be fairly HTML-agnostic. As in, if you ever wrote a non-web-based application to interact with the same data, it could use the same models. Because of this, I would put any HTML-rendering code in my views. Even though it requires some looping logic.
At the end of the day, though, I don't think it matters that much in your case. If you strongly prefer putting the loop in the model, go with that. The most important thing is just to develop your own conventions, and then stick to them.
Here's how I would do the view:
<section>
<ul>
<?php foreach($album->getTracks() as $track): ?>
<li
class="<?php echo $track->isPlayable() ? 'load mp3' : '' ?>"
>
<span class="playBtn">
<?php echo $track->getName() ?>
</span>
</li>
<?php endforeach ?>
</ul>
</section>
This assumes that you've passed a variable called $album, and that a method offered therein returns an array of type Track.
You can return arrays if you like as well, however I prefer objects as you can convert complex conditions to simple, meaningful names. Thus, rather than your '*' test, the programmer calls $track->isPlayable(), which makes much more sense, and doesn't need commenting in the template.
In my experience it depends on what the loop is doing. One can have view specific loops. You can loop through html tags that display elements dynamically and that should go in the view.
for($controller_sent_array as $element)
{
echo "<h4>$element</h4>";
}
However things like looping through file input should go in the controller/model side. I make a point of being vague here because the choice of what should be in models verses controllers depends on framework optimizations. However what is important is that the model and controller are not sending html to be rendered. Rather, they should process data either from a database or user input or network connection, and package that data for the view to figure out. To this end you also need loops.
// This is not a safe way to do this in real life...
for($_POST as $post_input)
{
$this->your_database_library->save_input($post_input);
}
Consider your framework selection with respect to what loops are processing what where, but loops should be used when needed in the model, view, or controller.
I just realized that i may not be following best practices in regards to the MVC pattern.
My issue is that my views "know" information about my database
Here's my situation in psuedo code...
My controller invokes a method from my model and passes it directly to the view
view.records = tableGateway.getRecords() // gets array of records
view.display()
in my view
each records as record
print record.name
print record.address
...
In my view i have record.name and record.address, info that's hard-coded to my database. Is this bad?
What other ways around it are there other than iterating over everything in the controller and basically rewriting the records collection. And that just seems silly.
Thanks
EDIT
Heres an actual view
<?php foreach( $categories as $category ): ?>
<tr>
<td><?php echo $category['name'] ?> </td>
<td><?php echo $category['fields'] ?> </td>
<td><?php echo $category['records'] ?></td>
<td>View</td>
</tr>
<?php endforeach; ?>
So a simple loop through the data won't work, i need to capture certain fields of the sql result in my view.
Is there a way around this? It makes me feel dirty.
I'd say it's not bad to have such info hardcoded if you need to have it quick and dirty.
But consider having generic class for views with method that takes your data from db and some array describing which columns to use. Then in the children classes (UserView, PostView, WhateverTableNameView) you could call this base method with array containing "Name", "Address" etc.
Pardon me if I am talking Python gibberish, I came to this question from PHP tag ;) More or less like this
class BaseView {
public function display(& $data, array $columnNames) {
foreach($data as $row) {
foreach($columnNames as $c) {
echo $row->$c; // or $row[$c] or whatever your data is, I'm assuming objects
}
echo "\n";
}
}
class UserView extends BaseView{
public function display(& $data) {
parent::display($data, array('Name', 'Address');
}
}
The nice things here:
Need one more column? Make sure you query for it, then modify 1 line in UserView.
Need to have text for HTML column labels (<th> stuff) - it's already here.
$data could be resource descriptor (think while($rs.nextRow())) and not neccessarily full array that might occupy a lot of memory and take time to pass around from one function to another.
if you go for nice looking HTML tables around these records, you have unified look & feel across application as there's only one place where you define them.
If for some reason this doesn't appeal to you, the truly generic solution is to have indexes instead of column names. $data[$i][0], $data[$i][1] and so on... Most database APIs offer possibility to query for columns as names, as numbers or both. For PHP + MySQL see examples on http://www.php.net/manual/en/function.mysql-fetch-array.php
But this will bite you in the a$$ sooner or later because you lose metadata info. Let's say you want later to wrap your "names" into links:
echo '',$record['name'],'';
Good luck doing this in reusable way without column names...
With getters/setters and a piece of code to map the record fields to them you can remove this, but you'll add some complexity.
The real question is: Do i need to rename field names at all?
With some planning/thinking/feedback it shouldn't be hard to find appropriate names for your fields that survive the applications lifetime. However, if the semantics of the field change you should add a new field. This has also the advantage that you can clearly document the deprecation of it and lead the programmer to the new one.
I have a CakePHP application that in some moment will show a view with product media (pictures or videos) I want to know if, there is someway to include another view that threats the video or threats the pictures, depending on a flag. I want to use those "small views" to several other purposes, so It should be "like" a cake component, for reutilization.
What you guys suggest to use to be in Cake conventions (and not using a raw include('') command)
In the interest of having the information here in case someone stumbles upon this, it is important to note that the solution varies depending on the CakePHP version.
For CakePHP 1.1
$this->renderElement('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.thtml, where $flag will have the value of whatever you pass to it.
For CakePHP 1.2
$this->element('display', array('flag' => 'value'));
in your view, and then in /app/views/elements/ you can make a file called display.ctp, where $flag will have the value of whatever you pass to it.
In both versions the element will have access to all the data the view has access to + any values you pass to it. Furthermore, as someone pointed out, requestAction() is also an option, but it can take a heavy toll in performance if done without using cache, since it has to go through all the steps a normal action would.
In your controller (in this example the posts controller).
function something() {
return $this->Post->find('all');
}
In your elements directory (app/views/element) create a file called posts.ctp.
In posts.ctp:
$posts = $this->requestAction('posts/something');
foreach($posts as $post):
echo $post['Post']['title'];
endforeach;
Then in your view:
<?php echo $this->element('posts'); ?>
This is mostly taken from the CakePHP book here:
Creating Reusable Elements with requestAction
I do believe that using requestAction is quite expensive, so you will want to look into caching.
Simply use:
<?php include('/<other_view>.ctp'); ?>
in the .ctp your action ends up in.
For example, build an archived function
function archived() {
// do some stuff
// you can even hook the index() function
$myscope = array("archived = 1");
$this->index($myscope);
// coming back, so the archived view will be launched
$this->set("is_archived", true); // e.g. use this in your index.ctp for customization
}
Possibly adjust your index action:
function index($scope = array()) {
// ...
$this->set(items, $this->paginate($scope));
}
Your archive.ctp will be:
<?php include('/index.ctp'); ?>
Ideal reuse of code of controller actions and views.
For CakePHP 2.x
New for Cake 2.x is the abilty to extend a given view. So while elements are great for having little bits of reusable code, extending a view allows you to reuse whole views.
See the manual for more/better information
http://book.cakephp.org/2.0/en/views.html#extending-views
Elements work if you want them to have access to the same data that the calling view has access to.
If you want your embedded view to have access to its own set of data, you might want to use something like requestAction(). This allows you to embed a full-fledged view that would otherwise be stand-alone.
I want to use those "small views" to
several other purposes, so It should
be "like" a cake component, for
reutilization.
This is done with "Helpers", as described here. But I'm not sure that's really what you want. The "Elements" suggestion seems correct too. It heavily depends of what you're trying to accomplish. My two cents...
In CakePHP 3.x you can simple use:
$this->render('view')
This will render the view from the same directory as parent view.