CakePHP 3 create dynamic Menu - php

I am trying to create a short submenu for CakePHP with a Database Table.
First I tried this solution how to create dynamic navigation menu cakephp which seemed outdated (because its two years old) and since I donĀ“d need to add menus over the add function, its to big anyways.
So can I solve this with just the table in my DB, the model in Cake and an element?
Thats what I got so far:
src/template/element/main.ctp
<ul class="header main-menu">
foreach($something as $something ) :
?>
<li>
somethine
</li>
<? endforeach; ?>
</ul>
my view
<?= $this->element('main'); ?>
My Model
class Menu extends Entity
{
var $name = 'Menu';
}
Is this the way to go?

your question is a little generic, but here's something you want to consider:Html helper class
and in particular Html helper lists. That way you can do in your main.ctp:
$list = [];
foreach ($menu as $menuItem) {
$list[] = $menuItem;
}
echo $this->Html->nestedList($list);

Related

Joomla custom fields inside template

I would like to customize my template for Joomla 3.7 so that I can use the new feature of Joomla 3.7, Custom fields (com_fields), and display and format them via CSS in my template where I need to display them.
Can someone suggest me the PHP code I should use in the template to display field(s), some example please.
Thanks in advance.
For everyone getting late to the party. In case you want to use your custom form fields in a Module-Override (which really are the only way to modify j!-templates, so google 'joomla template override') you can use this handy snippet:
<?php
JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');
$jcFields = FieldsHelper::getFields('com_content.article', $item, true);
$itemCustomFields = array();
foreach($jcFields as $field) {
$itemCustomFields[$field->name] = $field->rawvalue;
}
?>
Now you cna use your customfields like so: itemCustomFields['customFieldName1']
Haven't tested in article overrides. May soon, if so, this will get updated.
certainly not the right way to do it but I had the same need and I found a work around based on https://www.giudansky.com/news/12-coding/146-joomla-custom-fields
Copie default.php from /components/com_content/views/article/tmpl/default.php to
templates/YOUR_THEME/html/com_content/article/default.php
Add following code line 25 :
$myCustomFields = array();
foreach($this->item->jcfields as $field) {
$myCustomFields[$field->name] = $field->value;
}
$GLOBALS['myCustomFields'] = $myCustomFields;
Typically you put on a global var the content of fields attached to your article.
On your template page you can know retrieved value of your field.
just print_r($GLOBALS['myCustomFields']); to view the content of your array.
That will do the trick waiting for a better answer..
This is absolutely the wrong way to do this I think but I was tearing my hair out so i came up with this quick db query to return custom field values in the template. surely this violates some kind of joomla protocol?
obviously this assumes you can get $articleid into your template already which is the Current ID of your article.
I too am waiting on a better solution but hope this helps
$db =& JFactory::getDBO();
$sql = "select * from #__fields_values where `item_id` = $articleid";
$db->setQuery($sql);
$fieldslist = $db->loadObjectList();
echo $fieldslist[0]->value;
echo $fieldslist[1]->value;
echo $fieldslist[your field ID here]->value;
I found it was easiest to follow how com_fields does it in its rendering code. In Joomla!3.7+, you'll find it in [joomla_root]/components/com_fields/layouts/fields/render.php .
Here are the main parts you need to reproduce the formatting that Joomla has:
JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');
<dl class="fields-container">
<?php foreach ($this->item->jcfields as $field) : ?>
<?php // If the value is empty do nothing ?>
<?php if (!isset($field->value) || $field->value == '') : ?>
<?php continue; ?>
<?php endif; ?>
<?php $class = $field->params->get('render_class'); ?>
<dd class="field-entry <?php echo $class; ?>">
<?php echo FieldsHelper::render($context, 'field.render', array('field' => $field)); ?>
</dd>
<?php endforeach; ?>
</dl>
This loops through all available tags for the component or article. The nice thing about this method is it still applies the render classes you include with the fields.
Make sure to set Automatic Display to Do not automatically display on your fields; otherwise you will see them twice on your page view.
If you want to just target specific fields to show, you can use the name of the field to target it. (The label and value pair is underneath.) See the field Joomla docs for more info.
I implemented this small function to get specific custom field values:
function getCustomFieldValue($field_name, $article_id, $default_value = '') {
// Load custom field list
$fields = FieldsHelper::getFields('com_content.article', $article_id, true);
$field_ids = array_column($fields, 'id', 'name');
$model = JModelLegacy::getInstance('Field', 'FieldsModel', array('ignore_request' => true));
// Return the value if the field exists, otherwise the default
return array_key_exists($field_name, $field_ids)
? $model->getFieldValue($field_ids[$field_name] , $article_id)
: $default_value;
}
Usage:
$some_field_value = getCustomFieldValue('some-field-name', $some_article_id);
Optimization: I placed the function into a helper class, implemented the variables $fields, $field_ids and $model static and checked if they are already loaded to prevent redundant loading of the same data.

Concrete 5 Pagination (Page List Blogs)

Is it possible to have some sort of pagination within the URL in Concrete 5. I see many CMS's such as Wordpress and Drupal etc that have such a feature.
At the moment my blogs are the following:
/blog?ccm_paging_p_b348=2
and the way I want it to be is:
/blog/page/1 ... /blog/page/2 etc (or something similar)
Any tips or advice would be appreciated
Your only choice is to create a custom page type for your blog page and then a custom controller for that which handles the pagination.
Please see this page:
http://www.concrete5.org/documentation/developers/pages/mvc-approach
And particularly the "Page Types" section under "Controllers". It explains how to create your page type controllers. For them, you can create similar functions that you would for normal single pages, so you can paginate the results there according to the parameters you get from the URL.
This example is for 5.6 and earlier:
<?php
class BlogPageTypeController extends Controller {
public function view($page=1) {
$pageIndex = intval($page)-1;
if ($pageIndex < 0) {
$pageIndex = 0;
}
$pageList = new PageList();
$pageList->setItemsPerPage(25);
$this->set('pages', $pageList->getPage($pageIndex));
}
}
And then you would use the $pages variable in your view to go through the pages:
<?php foreach($pages as $page) : ?>
<h2><?php echo $page->getCollectionName()</h2>
<?php endforeach; ?>

How to add functions to a MVC Joomla component to access data from a different table?

I have a custom joomla MVC component created by http://component-creator.com with 4 tables:
#__mycomponent_items 27 Fields
#__mycomponent_bids 12 Fields
#__mycomponent_journeys 9 Fields
#__mycomponent_users 8 Fields
I am trying to set the relationships between these tables, but in the absence of documentation and experience I am struggling.
The basic relationships between the tables need to allow USERS to make BIDS to deliver ITEMS.
So I have created fields for items like this:
#__mycomponent_items
id
created
updated
ordering
state
checked_out
checked_out_time
created_by
deliverydestination
itemtitle
status
requiredby
listprice
deliveredprice
commission
points_reward
accepted_bid
accepted_bidder
accepted_journey
And for bid like this:
#__mycomponent_bids
id
state
created_by
item_id
buyer
bid
created
updated
bid_status
bid_expires
journey
arrival_date
I am working in templates/mytemplate/html/com_mycomponent/item/default.php and trying to add to that view a list of the current bids on that item. To do that I assume I need to add a custom function to /components/com_mycomponent/models/item.php and the function I have created is follows:
function itemBids() {
// Get a db connection.
$db = JFactory::getDbo();
// Create a new query object.
$query = $db->getQuery(true);
// Select item record matching the $orderID
$query
//->select('*')
->select($db->quoteName(array('id', 'created_by', 'created', 'bid', 'bid_status', 'arrival_date')))
->from($db->quoteName('#__mycomponent_bids'))
->where('item_id = item.id');
// Reset the query using our newly populated query object.
// Load the results as a list of stdClass objects (see later for more options on retrieving data).
$db->setQuery($query);
$itemBids = $db->loadObjectList();
//print_r($itemBids);
}
How do I then access the data in the view /mytemplate/html/com_mycomponent/item/default.php?
I have tried this and it returns nothing:
<ul>
<?php foreach ($itemBids as $itemBid) :?>
<?php $arrivalDate = $itemBid->arrival_date; ?>
<li><strong><?php echo $itemBid->created_by; ?></strong> <small>can deliver for</small> $<?php echo $itemBid->bid;?> <small>
<?php /*?><abbr class="timeago" title="<?php echo $itemBid->created; ?>"></abbr><?php */?>
in <strong><abbr class="timeago" title="<?php echo $arrivalDate; ?>"></abbr></strong></small><div class="uk-badge uk-float-right"><?php echo $itemBid->bid_status; ?></div></li>
<?php endforeach; ?>
</ul>
You wouldn't be putting it in your template like that. the template just holds the layouts that generate the html. Also you need to have a default layout in your views/myview/tmpl folder.
You don't seem to be returning anything from your itemBids() function. You would want to add return $itemBids; or possibly return $this->itemBids; depending on what you are doing elsewhere.
YOu want to get $this->itemBids in your view.html.php class so that it is then available to your layout. THen instead of referring to $itemBids you can refer to $this->itemBids in your loop in the layout.
Have you been through the Creating an MVC Cmponent tutorial? It would probably help you get a sense of how MVC works in Joomla.
OK , as far as I understand you have a method in yourmodel.php and you are trying to access it from the view I did notice that you are not returning any values in your method
return $db->loadObjectList();
let me just make it simple by the below code
//com_component/models/yourmodel.php
class componentModelYourmodel extends JModelLegacy
{
function yourMethod()
{
//code
return $value;
}
}
And then in view file
//com_component/views/yourview/tmpl/default.php
//get the model first
$model=$this->getModel();
//call the method
$items=$model->yourMethod();
//print
print_r($items);

How can I add a derived column to my Yii model?

In Yii, I need to add a "derived" column to any resultset from my model. The column doesn't actually exist in the database table.
For example, say I have an Activity model. There are only two types of Activities: (1) Income, or (2) Expense.
If I want to add a column called income_total or expense_total (depending on what type of activity is being accessed), how would I do that?
Here's a working example of an Activity model in Ruby on Rails (I'm basically wondering how to do the same thing, but in Yii):
class Activity < ActiveRecord::Base
attr_accessible :name, :effective_at, :amount, :category
scope :incomes, :conditions => { :category => 'Income' }
scope :expenses, :conditions => { :category => 'Expense' }
def self.incomes_total
incomes.sum :amount
end
def self.expenses_total
expenses.sum :amount
end
end
Update 2012-07-01:
The answer provided by Leonardo points to the use of Virtual Attributes, this adds an attribute to each "row" of the resultset that I'm retrieving from the database.
If the Activity model has a BELONGS_TO relationship with Parent, a Parent View may look like the following:
<h2><?php echo $parent->name; ?></h2>
<ul>
<?php foreach($portfolio->activities as $activity): ?>
<li>
<?php echo CHtml::link($activity->name, array('activity/view', 'id' => $activity->id)); ?>
<?php echo $activity->amount; ?>
<?php echo $activity->incomes_total; ?>
</li>
<?php endforeach; ?>
</ul>
However, it doesn't make sense for this Virtual Attribute to be accessed within the foreach() loop.
These Virtual Attributes that I want provide one "aggregated" value for the whole resultset, so I want to be able access it using $parent->activities->incomes_total, like so:
<h2><?php echo $parent->name; ?></h2>
<?php echo $parent->activities->incomes_total; ?>
<ul>
<?php foreach($portfolio->activities as $activity): ?>
<li>
<?php echo CHtml::link($activity->name, array('activity/view', 'id' => $activity->id)); ?>
<?php echo $activity->amount; ?>
</li>
<?php endforeach; ?>
</ul>
What do I need to do within the Activity model code to achieve this, or should I be thinking about this a different way?
I believe it is pretty similar to Ruby. PHP has magic methods, which in Yii is implemented by CComponent (base class of many including CActiveRecord).
In short you can do this within your model
class Activity extends CActiveRecord {
public function getIncome_Total() {
// ...
}
}
And, to access it from controller
$activity = Activity::model->findByPk(1);
$income_total = $activity->income_total;
As I posted in the other answer You can simply use a stat relation. Specify a STAT relation in Parent model as
'incomes_total'=>array(self::STAT, 'Activity', 'parent_id','select'=>'SUM(amount)','condition'=>"incomes_total.category='Income'")
Similiarly
'expense_total'=>array(self::STAT, 'Activity', 'parent_id','select'=>'SUM(amount)','condition'=>"incomes_total.category='Expense'")
NOTE: Change the attribute names parent_id and amount as in your model
I don't know how this can be done within the model.
Although it is more processing, an option or workaround is to add another foreach() loop to the View like so:
$incomes_total = 0;
foreach($parent->activities as $activity)
$incomes_total += $activity->amount;
echo $incomes_total;

Rendering Active Branch of Zend Navigation Without Top Level

I am rendering the top-level elements of a Zend Navigation object in one place like this:
echo $this->navigation()->menu()->setMaxDepth(0);
How do I render the navigation tree from the second level on down for the active branch? I've tried creating a partial that loops the $this->container object, but I don't know how to determine if my current item is the active branch. Once I've determined that it's the active branch how do I render the menu? Am I doing this the hard way and missing something obvious?
Thanks!
UPDATE:
I accepted a solution because that's what I used, but I also would like to provide the answer to my actual question, for reference sake. ($this is the view object)
// Find the active branch, at a depth of one
$branch = $this->navigation()->findActive($this->nav, 1, 1);
if (0 == count($branch)) {
// no active branch, find the default branch
$pages = $this->nav->findById('default-branch')->getPages();
} else {
$pages = $branch['page']->getPages();
}
$this->subNav = new Zend_Navigation($pages);
$this->subNav can then be used to render the sub-menu.
If I got your question right, this is how I do it:
print $this->navigation()->menu()->renderMenu(null, array(
'minDepth' => 1,
'maxDepth' => 1,
'onlyActiveBranch' => true,
'renderParents' => false));
Renders only the submenu of currently active menu.
I do something similar. My main navigation is handled with something like this...
$this->navigation()->menu()->setPartial('tabs.phtml');
echo $this->navigation()->menu()->render();
Then in my tabs.phtml I iterate over the container like so...
if (count($this->container)) {
foreach($this->container as $page) {
if ($page->isVisible()) {
if ($page->isActive(true)) {
$subcontainer = $page->getPages();
foreach($subcontainer as $subpage) {
// echo my link
}
}
}
}
}
I hope that helps a bit.
I do it this way:
<?php
// Render top-level elements
echo $this->navigation()->menu()->setMaxDepth(0);
// Render 2nd level elements for active element
echo $this->navigation()->menu()
->setOnlyActiveBranch(true)
->setRenderParents(false)
->setMinDepth(1);
?>
but this is not a good solution. Better one for each level as a separate menu:
<!-- level 1 -->
<?php echo $this->navigation()->menu()->setMaxDepth(0); ?>
<!-- level 2 -->
<?php echo $this->navigation()->menu()->setOnlyActiveBranch(true)->setRenderParents(true)->setMinDepth(1)->setMaxDepth(1); ?>
<!-- level 3 -->
<?php echo $this->navigation()->menu()->setOnlyActiveBranch(true)->setRenderParents(false)->setMinDepth(2)->setMaxDepth(2); ?>

Categories