cakePHP: how to get iterator - cakephp

Im using something similar to this code:
<?php foreach ($items as $item): ?>
<div><?php echo $item['Item']['content']; ?></div>
<?php endforeach; ?>
And i'd like to know which element is every item, because i want to add class "last-in-row" for every fourth item in row. How to make something like this code?
<?php for ($i=1; $i <= $items.count; $i++) {
echo "<div ";
if ($i % 4 == 0) {
echo " class=\"last-in-row\""; }
echo ">$items[$i]</div>";
}; ?>

I haven't tested it but the following should work.
<?php
$i = 1;
foreach ($items as $item) {
$class = ($i % 4 == 0) ? '' : 'class="last-in-row"';
echo "<div $class>{$item['Item']['content']}</div>";
$i++;
}
?>
p.s. I hope you are sanitizing $item['Item']['content'].

What you are trying to do could be done with css3. This will mean you do not need to add a class which is fat better as later on you might want 3 or 5 in a row.
div:nth-child(4n+4) {
....
clear: both;
....
}
The CakePHP option without css3
foreach ($items as $i => $item) {
echo $this->Html->tag('div', $item['Item']['content'], array(
'class' => ($i + 1) % 4 === 0 ? 'last' : null
));
}

You nearly had it in your second example, just change $items.count to the value of count($items)
$itemsCount = count($items);
for ($i=1; $i <= $itemsCount ; $i++) {
echo "<div ";
if ($i % 4 == 0) {
echo " class=\"last-in-row\""; }
echo ">{$items[$i]}</div>";
}

Related

Need help in printing records from database

I want to print records from db like this.
http://www.imagesup.net/dm-613781138202.png
I have tried for loop and foreach both.
The sample code is:
<?php
$str = '1,2,3,4,5,6,7,8,9,10,11,12,13,14';
$str2 = (explode(",",$str));
echo '<table border="1">';
foreach ($str2 as $str3)
{
echo '<tr>';
for($i=0;$i<5;$i++)
{
echo '
<td>'.$str3.'</td>
';
}
echo '</tr>';
}
echo '</table>';
?>
I have tried many others but not getting required result.
#kami you should replace + with . like this.
<?php
$str = '1,2,3,4,5,6,7,8,9,10,11,12,13,14';
echo '<table>';
$list = explode(",", $str);
$itemsPerRow = 7;
for ($i = 0; $i < sizeof($list); $i+=$itemsPerRow)
{
echo '<tr>';
for($j = 0; $j < $itemsPerRow; $j++)
{
$val = isset($list[$i + $j]) ? $list[$i + $j] : '';
echo '<td>' .$val. '</td>';
}
echo '</tr>';
}
echo '</table>';
?>
Try something like this
<?php
$str = '1,2,3,4,5,6,7,8,9,10,11,12,13,14';
echo '<table>';
$list = explode(",", $str);
$itemsPerRow = 7;
for ($i = 0; $i < sizeof($list); $i+=$itemsPerRow)
{
echo '<tr>';
for($j = 0; $j < $itemsPerRow; $j++)
{
$val = isset($list[$i + $j]) ? $list[$i + $j] : '';
echo '<td>' . $val . '</td>';
}
echo '</tr>'
}
echo '</table>'
?>
The above uses two for loops to iterate over the data. The outer loop controls the row, and the inner loop controls the content.

Create a custom loop with post IDs taken from Magic Fields 2 duplicate text fields

I'm trying to create a custom loop with content related to specific post IDs whose numbers I'm getting from a Magic Fields duplicate text field called "reference_posts".
When I echo $testvalue; it outputs the correct listing of posts "20432,43242,34253," but when I try to output it inside the array I only get the first value repeated over and over "20432,20432,20432,".
I'm guessing the problem is that I have to envelope the second foreach within the first but I'm not managing to do that.
Can anyone help me out?
<?php
$value = get_field ('reference_posts') ;
foreach ( $value as $my_val ) {
$testvalue = $my_val . ",";
echo $testvalue;
$post_idarray = array( 'post__in' => array( $testvalue ) );
$postspecial = get_posts($post_idarray);
}
foreach( $postspecial as $post ) :
setup_postdata($post);
?>
<div>my content</div>
<?php endforeach; ?>
Thanks in advance!
Got it with:
<?php
$value = get_field ('reference_posts') ;
foreach ( $value as $my_val );
$args = array( 'include' => $value );
$myposts = get_posts( $args );
foreach( $myposts as $post ) : setup_postdata($post); ?>
<div>my content</div>
<?php endforeach; ?>

wordpress super loop style posts in rows N times

I am trying to adapt the Wordpress loop to style posts differently in rows that get
infinitely smaller until all posts are displayed
The concept here is to display posts in rows
first row 1 post
second row 2 posts
third row 3 posts
fourth row 4 posts
fifth row 5 posts
sixth row 6 posts
seventh row 7 posts
and onward until all posts have been retrieved
the below code is limited and does not do the above how would you adapt to make the below do the above?
the below code is functional and can be seen here: http://ccs.btcny.net/redhook/
<?php if (have_posts()) : ?>
<?php $count = 0; ?>
<?php while (have_posts()) : the_post(); ?>
<?php $count++; ?>
<?php if ($count == 1) : ?>
<div class="style-1"><?php the_content(); ?></div>
<?php elseif ($count == 2 || $count == 3) : ?>
<div class="style-2"><?php the_content(); ?></div>
<?php elseif ($count == 4 || $count == 5 || $count == 6) : ?>
<div class="style-3"><?php the_content(); ?></div>
<?php elseif ($count == 7 || $count == 8 || $count == 9 || $count == 10) : ?>
<div class="style-4"><?php the_content(); ?></div>
<?php elseif ($count == 11 || $count == 12 || $count == 13 || $count == 14 || $count == 15 ) : ?>
<div class="style-5"><?php the_content(); ?></div>
<?php elseif ($count >= 16 ) : ?>
<div class="style-6"><?php the_content(); ?></div>
<?php endif; ?>
<?php endwhile; ?>
Here is my solution. Basically I am setting the row number by checking if the next element is inside the current row. To do that I need to see if next index is equal to the first index of the next row.
The tricky part is to find the index of the first item in the row. As this is not linear but geometrical order the items number in each row will be increasing. To calculate the first item of the next row I need to add the number of elements in the current row (in this case simply the current row) to the first index of the current row. When I get the first index of the next row and when the next item will be equal to that number I need to go to the next row and set the first index for the current row for that calculated index.
<?php //The first index of the first row is 1?>
<?php $row = 1;?>
<?php $curFirstIndex = 1;?>
<?php //start counting items ?>
<?php $count = 0;?>
<?php while (have_posts()) : the_post();?>
<?php //create actual html code ?>
<div class="style-<?php echo $row;?>"><?php the_content(); ?></div>
<?php //check if the next item is equal to the first index of the next row ?>
<?php if ($count+1 >= ($row + $curFirstIndex)) :
<?php
//the next item will be in the new row
//in $curFirstIndex store the first number of the current row
$curFirstIndex = $row + $curFirstIndex;
//go to the next row
$row++;
?>
<?php endif; ?>
<?php $count++;?>
<?php endwhile;?>
[EDIT]
The above solution works but it has one little flaw, namely it incorporates the logic into the template. Wordpress does not follow some strict layer separation but in my opinion it is always good to try to do that if it is possible. So I come up with two ways that can reduce the logic of this in the template file and move the logic outside. Since wordpress has functions.php in its theme we can use this file to create a function which will handle that logic. Here is the code
Template view file:
<?php //Initial values?>
<?php $row = 1;?>
<?php $count = 1;?>
<?php while (have_posts()) : the_post();?>
<?php //create actual html code ?>
<div class="style-<?php echo $row;?>"><?php the_content(); ?></div>
<?php //check if the current item is the last in the row ?>
<?php if ($count == getRowLastItemIndex($row)) {$row++;} ?>
<?php $count++;?>
<?php endwhile;?>
in functions.php:
function getRowLastItemIndex($row) {
$index = 0;
for($i = 1; $i <= $row; $i++) {
$index += $i;
}
return $index;
}
Or make it even more separate in the following way
The template file
<?php //Initial values?>
<?php $row = 1;?>
<?php $count = 1;?>
<?php while (have_posts()) : the_post();?>
<?php //create actual html code ?>
<div class="style-<?php echo $row;?>"><?php the_content(); ?></div>
<?php $row = getRowNumber($row,$count);?>
<?php $count++;?>
<?php endwhile;?>
And add another function to the functions.php
function getRowNumber($row,$count) {
if ($count == getRowLastItemIndex($row))
$row++;
}
return $row;
}
What an elegant idea! Try something like this:
<?php
if (have_posts()):
$count = 0;
while (have_posts()):
$count++;
?>
<div class="style-<?php echo $count; ?>">
<?php
for( $i = 1; $i <= $count; $i++ ):
if (have_posts()):
the_post();
the_content();
endif;
endfor;
?>
</div>
<?php
endwhile;
?>
A while loop count posts and output <div>'s. Inside div executes for body as many times, as current $count value have. So for $count = 1 loop executes 1 time, then for $count = 2 loop executes 2 times and so on. Inside loop wp function the_post() iterate post index and the_content() output current post.

Updating specified rows in CakePHP using array of ID's?

This code is only updating one row (the one that matches the first in the array):
Edit: showing more code!
Here's my view. It's grabbing db entries based on an association (there's one model "clients" that has a one-to-many relationship with two other models, Programs and Users).
<div class="view">
<h2><?php echo h($program['Program']['title'])?></h1>
<?php echo $this->Form->create('User', array('action' => 'pushing')); ?>
<table id="pushTable">
<tr><th colspan="5">Select the athletes you would like to push this program to:</th></tr>
<tr>
<?php $i=0; ?>
<?php foreach ($clients['Players'] as $player) {?>
<?php if ($i == 0) {?><tr><?php } ?>
<td><?php echo $this->Form->checkbox($player['id']) . ' ' . $player['username'];?></td>
<?php if ($i == 4) {?></tr><?php $i = 0; } else { $i++; } ?>
<?php } ?>
</tr>
</table>
<?php echo $this->Form->end(__('Push')); ?>
</div>
In my Users controller:
public function pushing() {
if ($this->request->is('post') || $this->request->is('put')) {
$athletes = $this->request->data['User'];
foreach ( $athletes as $player => $flag){
if ($flag == 0){
unset($athletes[$player]);
}
}
$this->User->updateAll(
array('User.data' => "'foo'"),
array('User.id' => $athletes)
);
$this->Session->setFlash(__('Programs were pushed!'));
}
}
}
$athletes is the array is collected from checked boxes, and there seem to me no problems with that... so I'm not sure why the updateAll isn't iterating over each ID in the array...
Maybe it's not working for a db related reason? I'm developing on MAMP... maybe the db isn't set up for "atomic" stuff (only heard about that here today!).
I had previously tried using a foreach to loop over the id's, then in the foreach just did this (edit: more code!)
public function pushing() {
if ($this->request->is('post') || $this->request->is('put')) {
foreach ($this->request->data['User'] as $player => $flag) {
if ($flag) {
$this->User->id = $player; // set ID to player we want to save ($player is id that was suplpied in view to checkbox
$this->User->saveField('data', 'foo'); // then, push the data!
}
}
$this->Session->setFlash(__('Programs were pushed!'));
}
$this->autoRender = false;
$this->redirect(array('action' => 'index'));
}
But that caused weird results with redirection. No matter where I put redirection in that action, the save just wanted to do its own thing. That $this->autoRender did nothing. The controller still tried to resolve to the /pushing/ route
Give this a shot :)
In your view:
<div class="view">
<h2><?php echo h($program['Program']['title'])?></h1>
<?php echo $this->Form->create('User', array('action' => 'pushing')); ?>
<table id="pushTable">
<tr><th colspan="5">Select the athletes you would like to push this program to:</th></tr>
<tr>
<?php $i=0; ?>
<?php foreach ($clients['Players'] as $player) {?>
<?php if ($i == 0) {?><tr><?php } ?>
<td><?php echo $this->Form->input('Player.' . $player['id']. '.id', array('type' => 'checkbox', 'value' => $player['id'])) . ' ' . $player['username'];?></td>
<?php if ($i == 4) {?></tr><?php $i = 0; } else { $i++; } ?>
<?php } ?>
</tr>
</table>
<?php echo $this->Form->end(__('Push')); ?>
</div>
In your controller:
public function pushing() {
if ($this->request->is('post') || $this->request->is('put')) {
$athletes = $this->request->data['Player'];
$athlete_ids = array();
foreach($athletes as $a){
$athlete_ids[$a['id']] = $a['id'];
}
$this->User->updateAll(
array('User.data' => "'foo'"),
array('User.id' => $athlete_ids)
);
$this->Session->setFlash(__('Programs were pushed!'));
}
}
}
Hi had to change the code a bit to make it for work me..
$contactsids = array();
foreach($selected as $key => $val){
if(($val <> '') && ($val <> 0) ) {
$contactsids[$val] = $val;
}
}
$this->Contact->updateAll(
array('Contact.contact_category_id' => $category_id),
array('Contact.id' => $contactsids)
);

Count associated records with tree model (full depth)

We have two models. Ebooks HABTM Tags, where tags follows the tree behavior.
For each tag we need two numbers. First, the number of ebooks associated to the tag, and secondly the number of ebooks associated to the tag + the number of associated ebooks for each descendant.
How can we get the tags with these numbers in an array in tree format?
Thank you very much for any help.
Update: There is a datetime parameter Ebook.published which defines when the book is to be counted or not. All the ebooks that have codeEbook.published < NOW() should be counted.
Cake has no basic support for this. You will need to do the calculations on the fly or create your own counter cache with custom code to update. This is messy.
I'd suggest overriding the beforeSave() and afterSave() function in your Ebooks controller. If updating, grab the current existing set of tags associated with the Ebook in your beforeSave(). In the afterSave() grab the new set of tags and merge it with the previous set. If there are any changes, iterate through all the tags and call $this->Tag->getPath($id) to get a list of all the ancestors. You'll now have all the tags that were affected by the save. You can now iterate through them and update the counts.
Actually, I found a simpler solution since I already have build the function that returns the tags tree. I used a query for each tag to get the actual count of that moment. Here is what I 've build. Feel free to use it according your needs.
In Tag model
// Returns the number of published ebooks of selected tag
function count_direct_published($tag_id = 0){
$temp = $this->query('SELECT count(*) as count FROM ebooks_tags LEFT JOIN ebooks ON ebooks_tags.ebook_id = ebooks.id WHERE ebooks.published < NOW() AND ebooks_tags.tag_id = '.$tag_id);
return $temp[0][0]['count'];
}
// Returns an array in tree format with $id tag and all his children
// $id = 0 start from the top (parent_id = null), or, from $id = the top's tag id
// $limit = boolean (default false)
// $level = Is the limit of depth applied only if $limit = true
// $ext = true Means this is the first time the function is called
// You can run tree_builder(), returns all the tree,
function tree_builder($id = 0, $limit = false, $level = 1, $ext = 1){
if($ext == 1){
$ext = 0;
$undo = true;
}else{
$undo = false;
}
$this->recursive=-1;
$this->contain('EbooksTag');
$var = array();
$count_all = 0;
// If limit = too big , exit
if($limit !== false && $level > $limit){
return '';
}
// Or else,
// If $id=0, find all the children
if($id == 0){
$tags = $this->find('all',array('conditions'=>array( 'Tag.parent_id IS NULL'), 'order'=>array('Tag.gre')));
// If $id!=0 && runs internally
}elseif($id != 0 && !$undo ){
$tags = $this->find('all',array('conditions'=>array( 'Tag.parent_id'=>$id ), 'order'=>array('Tag.gre')));
}
// If $id!=0 && is called from outside
elseif($id != 0 && $undo){
$tags = $this->find('all',array('conditions'=>array( 'Tag.id'=>$id )));
}
foreach($tags as $key => $tag){
$var[] = $tag;
$next = $this->tree_builder($tag['Tag']['id'], $limit, $level+1, $ext);
end($var); // move the internal pointer to the end of the array
$last_key = key($var); // fetches the key of the element pointed to by the internal pointer
$var[$last_key]['children'] = $next['var'];
$counter_direct = $this->count_direct_published($id);
$var[$last_key]['Tag']['count_all'] = $next['count_all']+$counter_direct;
$count_all += $var[$last_key]['Tag']['count_all'];
}
if( $undo )
{
return $var;
}else{
return array('count_all'=> $count_all, 'var' => $var);
}
}
In tags_controller.php
$this->set('tags', $this->Tag->tree_builder());
In the view
<?php foreach($tags as $tag){?>
<?php // Ο Γονέας σε dropdown box ?>
<div class="main-categ">
<?php echo $tag['Tag']['gre']; ?>
<?php echo $html->image('layout/arrows.png', array('alt'=> "Expand")); ?>
</div>
<div class="collapse">
<?php // Τα στοιχεία του γονέα ?>
<div class="tag-1">
<span class="tag-1">
<?php // Αν ?>
<?php if($tag['Tag']['count_direct']>0){
// Display link
echo $html->link($tag['Tag']['gre'],array('action'=>'view',$tag['Tag']['id']));
echo ' ('.$tag['Tag']['count_direct'].')';
}else{
// Display text
echo $tag['Tag']['gre'];
} ?>
</span>
<?php echo $html->link( 'view all' ,array('action'=>'view_all',$tag['Tag']['id'])); ?>
(<?php echo $tag['Tag']['count_all']; ?>)
</div>
<?php // Για κάθε πρώτο παιδί ?>
<?php foreach($tag['children'] as $tag_1){ ?>
<div>
<span class="tag-2">
<?php if($tag_1['Tag']['count_direct']>0){
// Display link
echo $html->link($tag_1['Tag']['gre'],array('action'=>'view',$tag_1['Tag']['id']));
echo ' ('.$tag_1['Tag']['count_direct'].')';
}else{
// Display text
echo $tag_1['Tag']['gre'];
} ?>
</span>
<?php echo $html->link( 'view all' ,array('action'=>'view_all',$tag_1['Tag']['id'])); ?>
(<?php echo $tag_1['Tag']['count_all']; ?>)
<?php // Τα δεύτερα παιδιά ?>
<?php $i=0; ?>
<?php foreach($tag_1['children'] as $tag_2){ ?>
<?php if($i==0){ echo '<ul class="split">'; $i++; } ?>
<li>
<?php if($tag_2['Tag']['count_direct']>0){
// Display link
echo $html->link($tag_2['Tag']['gre'],array('action'=>'view',$tag_2['Tag']['id']));
echo ' ('.$tag_2['Tag']['count_direct'].')';
}else{
// Display text
echo $tag_2['Tag']['gre'];
} ?>
</li>
<?php } ?>
<?php if($i==1) echo '</ul>'; ?>
<div class="clear"></div>
</div>
<?php } ?>
</div>
Perhaps its not the best solution but it works. Hope that helps

Resources