array_unshift - how to put array the top with key name - arrays

I have array element stored in $sal to put at the start of an array $fields['billing']. i am using array_unshift for this purpose.
$sal = array(
'label' => __('Tratamiento', 'woocommerce'),
'placeholder' => _x('', 'placeholder', ''),
'required' => 0,
'clear' => true,
'class' => array('form-row form-row-wide'),
'type' => 'select',
'options' => array(
'Señor' => __('Señor', 'woocommerce' ),
'Señora' => __('Señora', 'woocommerce' ),
'Señorita'=> __('Señorita', 'woocommerce')
)
);
array_unshift($fields['billing'] , $sal);
array_unshift adding element at the start of array at 0 key index. after print_r i see:
[0] => Array
(
[Label] => Treatment
[Placeholder] =>
[Required] => 0
[Clear] => 1
[Class] => Array
(
[0] => form-row-row-wide form
)
[Type] => select
[Options] => Array
(
[Lord] => Lord
[Lady] => Lady
[Ms.] => Miss
)
)
My problem is only that i just want to change the key value from [0] to ['saluation'], i can simply do that with:
$fields['billing']['saluation'] = $fields['billing'][0];
unset($fields['billing'][0]);
but i also want it at the start of array. i tried many techniques but still unable to figure this out.
this is actully woocommerce fields arrays which i am dealing with.

I just solved it by array_merge() function.
$fields['billing']= array_merge(array('saluation' => $sal), $fields['billing']);

Related

Nested Result while using CakePhp Containable

I am not sure about the question title but tried to explain more below. Thanks in advance for all who helps me.
I sampled the tables to simplify my questions.
DB Tables
News: news_id, title
Comments: comment_id, news_id, content, created (timestamp)
Users are posting comments to the news. In a search with the input of "date interval 01.10.2015 - 05.11.2015", the result should include: the news which has been commented between this interval. And comment_count should be shown next to the title on the screen. This comment_count is not whole comment_count, only the count between this dates.
To do that, I ran the query first in comments. Then count comments. Then group by news_id.
$Data = $this->Comment->find('all', array(
'fields' => array(
'News.news_id','News.title'
),
'conditions' => array(
"Comment.created >=" => date('Y-m-d', strtotime("-1 days")) //yesterday's commented news
),
'contain' => array(
'News' => array(
'Comment => array(
'fields' => array('COUNT(Comment.id) as comment_count'),
)
)
),
'group' => array('News.title')
));
The result is below with too much nesting:
Array
(
[0] => Array
(
[News] => Array
(
[id] => 27
[title] => sample news title
[News] => Array
(
[id] => 27
[title] => sample news title
[Comment] => Array
(
[0] => Array
(
[News_id] => 27
[Comment] => Array
(
[0] => Array
(
[Comment_count] => 1
)
)
)
)
)
)
)
)
In conclusion, to reach comment_count, I have to write the nestings manually. However I would like to reach it in the same level with first [title] node.
$JsonData [] = array(
"id" => $Item["News"]["id"],
"title" => $Item["News"]["title"],
"comment_count" => $Item["News"]["News"]["Comment"][0]["Comment"][0]["comment_count"]
);
How can I reduce the life-long nesting?
Thanks in advance.
First of all, you should name your table id like id not news_id. For your question, I'm not sure from what controller you are displaying news, IMO this should be done in NewsController. Here is how you can retrieve your news with comments count from previous day:
$Data = $this->News->find('all', array(
'fields' => array(
'News.id',
'News.title',
'COUNT(Comment.id) as comment_count'
),
'group' => array('News.id'),
'joins' => array(
array(
'table' => 'comments',
'alias' => 'Comment',
'conditions' => array(
'News.id = Comment.news_id',
'Comment.created >=' => date('Y-m-d', strtotime("-1 days"))
)
)
)
));
This should give you resulting array like this:
array(
(int) 0 => array(
'News' => array(
'id' => '1',
'title' => 'New news'
),
(int) 0 => array(
'comment_count' => '2'
)
),
(int) 1 => array(
'News' => array(
'id' => '2',
'title' => 'Seconds news'
),
(int) 0 => array(
'comment_count' => '1'
)
),
)
Then you can get your comment count(assuming through foreach loop):
... "comment_count" => $Data[0]['comment_count'] ...
You should look counterCache it might be useful to you.

CakePHP: HABTM relationship returns join table as an object - how do I get rid of it?

I have a 2 CakePHP models, Articles and Categories, attached using a hasAndBelongsToMany relationship, like so:
$category = new Category();
$category->bindModel(array('hasAndBelongsToMany' => array(
'Article' => array(
'className' => 'Article',
'joinTable' => 'articles_categories',
'foreignKey' => 'category_id',
'associationForeignKey' => 'article_id',
'fields' => 'id,name'
))));
$this->set('categories', $category->find('all',
array(
'fields' => 'id,name'
)));
...but then, when I print out $categories, I get the following:
Array
(
[0] => Array
(
[Category] => Array
(
[id] => 31
[name] => category name
[article_count] => 1
)
[Article] => Array
(
[0] => Array
(
[id] => 1445
[name] => article name
[teaser] =>
[author_id] => 3
[ArticlesCategory] => Array
(
[id] => 6634
[article_id] => 1445
[category_id] => 31
[author_id] => 3
[created] => 2014-03-10 12:27:26
[modified] => 2014-03-10 12:27:26
)
)
)
)
I really don't need the [ArticlesCategory] member of [Article]. This just leads me back to information I already have. I tried limiting recursion but that didn't help.
How would I get rid of this?
You have two options:
[1] Reduce recursive value to 0 (CakePHP default: 1)
$category->recursive = 0;
$category->find('all',
array(
'fields' => 'id,name'
))
[2] Start using ContainableBehaviour (my own preference), which gives you more control over model data retrieved
Add following to AppModel for App-wide coverage:
public $actsAs = array('Containable');
The find method becomes:
$category->find('all',
array(
'fields' => 'id, name',
'contain' => 'Article'
))
That should do it!

CakePHP 2.4.2: Contain Not Working as Expected

I have a model, Comment, that belongsto Module, Photo, Review, Article, and User. In turn, each of those models havemany Comment.
User belongsto Avatar and Avatar hasmany User
In the code below I successfully retrieve the latest 5 comments regardless of what model they come from (Photo, Article, Review) and I display some information about the User (username, online status).
$recentComments = $this->find('all',
array(
'limit' => '5',
'order' => array('Comment.id' => 'desc'),
'conditions' => array(
'Comment.page_id' => $page_id
),
'contain' => array(
'Photo' => array(
'fields' => array('Photo.id'),
'conditions' => array(
'Comment.module_id' => 8
),
),
'Review' => array(
'fields' => array('Review.title', 'Review.id'),
'conditions' => array(
'Comment.module_id' => 2
),
),
'Article' => array(
'fields' => array('Article.title', 'Article.id'),
'conditions' => array(
'Comment.module_id' => 3
),
),
'Module' => array(
'fields' => array('Module.model', 'Module.post_title'),
),
'User' => array(
'fields' => array('User.username', 'User.online'),
),
)
));
Unfortunately there are some issues with this. As you can see above I don't contain User->Avatar and all expected data is retrieved successfully.
$recentComments = Array
(
[0] => Array
(
[Comment] => Array
(
[id] => 179
[page_id] => 2
[module_id] => 3
[page] =>
[user_id] => 29
[post_id] => 9
[title] => test comment for article 9
[content] => here is the content for the comment
[created] => 2013-04-24 00:00:00
[redeemed] => 0
[status] => 0
)
[User] => Array
(
[username] => bowlerae
[online] => 0
)
[Module] => Array
(
[model] => Article
[post_title] => title
)
[Article] => Array
(
[title] => Test title for article 9
[id] => 9
[likes] => 0
[dislikes] => 0
[comments] => 2
)
[Photo] => Array
(
[id] =>
)
[Review] => Array
(
[title] =>
[id] =>
)
)
However, if I DO contain User->Avatar like this...
'User' => array(
'fields' => array('User.username', 'User.online'),
'Avatar' => array(
'fields' => array('Avatar.file')
)
),
Then the recursion basically becomes unlimited, ALL models related to Comment, User, Module, Article, Photo and Review are also retrieved which is A LOT.
Can anyone explain why this is happening? I will be happy to submit more code from some of the models if needed but I don't see any issues there.
Take a look at another example that works successfully...Below I am retrieving the 5 most recent articles. All information including the user Avatar is successfully retreived.
$this->set('articles_sidebar', ClassRegistry::init('Article')->find('all',
array(
'limit' => '5',
'order' => array('Article.id' => 'desc'),
'conditions' => array('
Article.page_id' => $page_id
),
'contain' => array(
'User' => array(
'fields' => array('User.username', 'User.online'),
'Avatar' => array(
'fields' => array('Avatar.file')
)
),
)
)));
Please note these two finds are performed in the AppController in the beforeRender given that $page_id > 0. $page_id is set in whatever the current controller is. I know people would probably ask about it but that's not what the issue is as I mentioned that example 2 retrieving the recent articles currently works.
EDIT: I discovered that it has something to do with my afterfind callback in the Article model. Is there a way I can tweak the queries in the afterfind and/or the $recentComments query so that they still work without breaking my contain? I don't need the likes, dislikes or comments virtual fields in my $recentComments query which is why they are not listed as one of the contained fields.
function afterFind($results, $primary = false) {
parent::afterFind($results, $primary);
foreach($results as $key => $val){
if (isset($val['Article']['id'])){
$results[$key]['Article']['likes'] = $this->Like->find('count', array('conditions' => array('Like.post_id' => $results[$key]['Article']['id'], 'Like.module_id' => 3, 'Like.status' => 0)));
$results[$key]['Article']['dislikes'] = $this->Like->find('count', array('conditions' => array('Like.post_id' => $results[$key]['Article']['id'], 'Like.module_id' => 3, 'Like.status' => 1)));
$results[$key]['Article']['comments'] = $this->Comment->find('count', array('conditions' => array('Comment.post_id' => $results[$key]['Article']['id'], 'Comment.module_id' => 3, 'Comment.status < 2')));
}
} // end for each
return $results;
} // end afterfind
My guess is your problem is this:
When using ‘fields’ and ‘contain’ options - be careful to include all
foreign keys that your query directly or indirectly requires.
Make sure you're including whatever field(s) are used to join User and Avatar models.
(read here)
For now I changed (in the Article model afterFind)
if (isset($val['Article']['id']))
to
if (isset($val['Article']['id']) && $val == "article")
Seems to be working in current controller but need further testing. Is there a better solution?

set() data is not being passed to view

view/plans/index.ctp
<?php debug($plans); ?>
controllers/plans_controller.php (index function)
function index() {
$plansC = $this->Plan->find('all',
array('contain' => array('PlanDetail' => array('fields' => array('id',
'effective_date',
'expiration_date',
'active',
'name',
'plan_type_id',
'max_benefit',
'deductible',
'preventive',
'basic',
'major',
'ortho',
'company_id',
'plan_type_id',
'plan_detail_note_id'),
'Company' => array('fields' => array(
'id',
'company_logo_url'
)),
'PlanType' => array('fields' => array(
'id',
'name'
))
))));
debug($plansC);
$this->set('plans',$this->paginate($planC));
Here is a sample index() debug record from the plans_controller.php (as you can see all data is being contained properly using containable):
[0] => Array
(
[Plan] => Array
(
[id] => 7
[created] => 2011-01-10 14:11:40
[modified] => 2011-02-03 18:35:29
[plan_detail_id] => 32
[monthly_cost] => 25.49
[dental_cost] => 0.00
[age_id] => 2
[applicant_id] => 1
[state_id] => 1
)
[PlanDetail] => Array
(
[id] => 32
[effective_date] => 2011-01-10 14:07:00
[expiration_date] => 2011-01-10 14:07:00
[active] => 1
[name] => Classic 1500
[plan_type_id] => 2
[max_benefit] => 0.00
[deductible] => $75/year
[preventive] => 90%
[basic] => 75%
[major] => 50%
[ortho] =>
N/A
[company_id] => 4
[plan_detail_note_id] => 9
[Company] => Array
(
[id] => 4
[company_logo_url] => nationwide_logo.png
)
[PlanType] => Array
(
[id] => 2
[name] => Indemnity
)
)
)
The containable data is not being passed. Only data associated with Plan and PlanDetail (no deeper relations than PlanDetail such as Company or Plan type), but the debug in the index controller shows all data being passed! But none of this data is making it into the view debug???
Does anyone know if this is a bug with containable?
You must either paginate or find, you can't paginate the found data array. Pagination is retrieving data from the database. Replace your find call with a paginate call. Save the result of the paginate call in a variable and debug it, your problem is there, not in the set call.
After 8 hours pain, I solved it : ) and I added pagination to boot. I ended up using compact() in place of the baked set().
function index() {
//$this->Plan->find('all'); not needed
$this->paginate['Plan'] = array('contain' => array('PlanDetail' => array('fields' => array('id',
'effective_date',
'expiration_date',
'active',
'name',
'plan_type_id',
'max_benefit',
'deductible',
'preventive',
'basic',
'major',
'ortho',
'application_url',
'company_id',
'plan_type_id',
'plan_detail_note_id'),
'Company' => array('fields' => array(
'id',
'company_logo_url'
)),
'PlanType' => array('fields' => array(
'id',
'name'
))
)));
$plans = $this->paginate('Plan');
$this->set(compact('plans'));
}

Pagination + Routes problem in CakePHP 1.3.6

I can't paginate my results if I access them from a Routed url. These are the routes that I'm using:
// NEWS
Router::connect('/news.rss', array('controller' => 'posts', 'action' => 'index', 'ext' => 'rss'));
Router::connect('/news/*', array('controller' => 'posts', 'action' => 'index'));
Router::connect('/:lang/posts/*', array('controller' => 'posts', 'action' => 'index'));
I know that in the last route I'm not passing the :lang parameter, but if I pass it:
Router::connect('/:lang/news/*', array('controller' => 'posts', 'action' => 'index'), array('lang' => $regex['lang'], 'pass' => array('lang')));
It does not work either.
If I try to access the url /news/page:2 it will show me the results from the first page. I printed out $this->params to see if it takes the page number correctly, and, in first instance, it does:
Array
(
[lang] => ca
[named] => Array
(
[page] => 2
)
[pass] => Array
(
)
[controller] => posts
[action] => index
[plugin] =>
[url] => Array
(
[ext] => html
[url] => ca/posts/page:2
)
[form] => Array
(
)
[...]
)
This part of the array (I've ommited some parts that I'll show you later) is the same if I access /news/page:2 and /posts/index/page:2, but if you take a look to this part:
Array
(
[...]
[paging] => Array
(
[Post] => Array
(
[page] => 1
[current] => 3
[count] => 3
[prevPage] =>
[nextPage] =>
[pageCount] => 1
[defaults] => Array
(
[limit] => 3
[step] => 1
[order] => Post.created DESC
[conditions] => Array
(
[Post.active] => 1
[Post.page] =>
[0] => Post.public_date <= NOW()
)
)
[options] => Array
(
[page] => 1
[limit] => 3
[order] => Post.created DESC
[conditions] => Array
(
[Post.active] => 1
[Post.page] =>
[0] => Post.public_date <= NOW()
)
)
)
)
You can see that it doesn't take the page number correctly. But if I access from /posts/index/page:2 it takes the number well and pagination works.
If only it were pretty URLs do not bother me, but considering that the site is multilingual, I need at least that works if I access /en/posts/index/page:2 (or /en/news/page:2)...
Here is my full routes.php file:
http://pastebin.com/th4hLZNz
Anybody has an idea of what is occurring?
Thanks in advance
Finally I've found the solution. Actually it was easy and the biggest problem was that I did not focus it properly. I focused on the routes thinking I did something wrong, but the problem was the controller.
Here was the problem:
$this->paginate['conditions'] = array(
'Post.active' => true,
'Post.page' => $page,
'Post.public_date <= NOW()');
$this->paginate['group'] = 'Post.id';
The group (in convination with the conditions) doesn't allow the paginateCount function to count the results well. So I've created my own paginateCount function on Post's Model missing the group condition:
/**
* This method fixes the count query
* when there's a GROUP BY on it
*
* #return integer
*/
public function paginateCount($conditions = null, $recursive = 0, $extra = array())
{
$parameters = compact('conditions', 'recursive');
$params = array();
if (isset($extra['group']))
{
$params = array_merge(array(
'fields' => array(
'COUNT(DISTINCT(' . $this->alias . '.' . $this->primaryKey . ')) AS `count`'
)
), $parameters);
}
else
{
$params = array_merge($parameters, $extra);
}
return $this->find('count', $params);
}
And now it seems to work well

Resources