I am working on a custom joomla component and have a single view setup. I am trying to figure out how to pull a list of k2 items into the view based on a few custom filters...
In weird english it would something like this:
Get all k2 items that_match_some_requirements into my custom components view where user_id = this user
It would be nice to be able to reference the item data normally like so:
$this->item->info
I am really just trying to understand / figure out the best way to import k2 item's and their object into my components view. If that makes sense?
Maybe something with this? Although I feel the name indicates otherwise :-/
JModelLegacy::addIncludePath(JPATH_SITE . '/components/com_component/models');
$whateverModel = JModelLegacy::getInstance('something', 'something'); //? not sure
or maybe from this module code?
require_once (JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'helpers'.DS.'route.php');
require_once (JPATH_SITE.DS.'components'.DS.'com_k2'.DS.'helpers'.DS.'utilities.php');
class modK2ContentHelper
{
public static function getItems(&$params, $format = 'html')
{
jimport('joomla.filesystem.file');
$mainframe = JFactory::getApplication();
$limit = $params->get('itemCount', 5);
$cid = $params->get('category_id', NULL);
$ordering = $params->get('itemsOrdering', '');
$componentParams = JComponentHelper::getParams('com_k2');
$limitstart = JRequest::getInt('limitstart');
Thank you!
I think it's easier your second option. Actually the whole process of getting K2 items with specific conditions is specified in the helper.php file.
In line 261:
$items = $db->loadObjectList();
The objects are loaded after the query has been created (the code is too long to be pasted here).
In the next lines you can see how a lot of item properties are created, modified or generated (300 lines of code).
At the end you get an array of items (php objects):
...
$rows[] = $item;
}
return $rows;
...
You could just take this file and reuse the code, or even call it from your component assuming always that the module is installed.
Related
I'm writing an Omeka Plugin and wants to get the list of all public Items with their all elements, in a controller under my plugin.
I've tried get_items() but the function doesn't exists, it looks like the function is only available for the views - not sure how.
another try was to manually fetch the records from database, but that's not a standard way.
So, the question is, is there a predefined function/class or way to get all the items in a controller?
I'm not sure if there is a function that will get you the items along with all of their element texts, but if you want a list of items, inside the controller you should be able to make a call like:
$items = $this->_helper->db->getTable('Item')->findAll();
The Omeka docs warn against getting all the items at once because it could be memory intensive. So, alternatively, you can loop through items.
$items = $this->_helper->db->getTable('Item');
$item = $items->findFirst();
while($item != NULL){
// Do something
$item = $items->findNext($item);
}
There is a "public" property on an item that tells you if it's public. In order to get the element texts for an item, I think you'd have to make a query on the ElementText table.
For more information, see the Omeka read the docs page for Table_Item, Omeka_Db_Table and Item:
http://omeka.readthedocs.io/en/latest/Reference/libraries/Omeka/Db/Table.html
http://omeka.readthedocs.io/en/latest/Reference/models/Table/Item.html
http://omeka.readthedocs.io/en/latest/Reference/models/Item.html
I have a CJ affiliate module that its already working perfectly fine:
Please see structure here:
http://screencast.com/t/21tsCh9loPSc
The module has an admin section where some settings are filled in:
cookie lifetime, affiliate id, etc.
Then I have to generate a JSON object on the HTML tag only on the success page.
This file is called udo.phtml, but its outside the module structure.
Is there anyway I can integrate that into the module itself?
http://screencast.com/t/jkJhKbHvk2
udo.phtml file code
<?php
class xxx_Commissionjunction_Helper_Data extends Mage_Core_Helper_Abstract
{
/**
* Get SKU, quantity, price and discount amount for each product in a given order
* #param object $order
* #return array
*/
private function _getOrderProductsList($order)
{
$orderItems = $order->getAllItems();
$purchasedSkus = array();
$count_orderItems = count($orderItems);
for($i = 0; $i < $count_orderItems; $i++) {
$purchasedSkus[$i] = array(
'ITEM' => $orderItems[$i]['sku'],
'QTY' => number_format($orderItems[$i]['qty_ordered'],0), // no decimals
'AMT' => number_format($orderItems[$i]['price'],2), // 2 decimal places
'DCNT' => number_format(abs($orderItems[$i]['discount_amount']),2)
);
}
return $purchasedSkus;
}
/**
* Get the Universal Data (JSON) Object for Commission Junction.
* This object contains the order details passed on to Commission Junction for reporting purposes
* on the Checkout Success / Order Confirmation page.
* Notes:
* - CID, TYPE AND CURRENCY are hard coded
* #param string $orderId
* #return JSON object Universal Data Object for Commission Junction $json_masterTmsUdp
*/
public function getCommissionJunctionUdo()
{
$lastOrderId = Mage::getSingleton('checkout/session')
->getLastRealOrderId();
$orderId = Mage::getModel('sales/order')
->loadByIncrementId($lastOrderId)
->getEntityId();
$order = Mage::getModel('sales/order')->load($orderId);
$udo = array();
//$udo['CID'] = '1531288';
$udo['CID'] = Mage::getStoreConfig('luisvalenciasection/luisvalenciagroup/cid');
$LastOrdertime= $order->getCreatedAt();
$OrderCollection=Mage::getModel('sales/order')->getCollection()->addFieldToFilter('customer_email',$order->getData('customer_email'))
->setOrder('created_at','asc');
$fstoredetime= $OrderCollection->getFirstItem()->getCreatedAt();
if($fstoredetime==$LastOrdertime)
{
// new customer
//$udo['TYPE'] = '373626';
$udo['TYPE'] = Mage::getStoreConfig('luisvalenciasection/luisvalenciagroup/type_new_customer');
}
else
{
//old customer
//$udo['TYPE'] = '373627';
$udo['TYPE'] = Mage::getStoreConfig('luisvalenciasection/luisvalenciagroup/type_old_customer');
}
$udo['CURRENCY'] = 'USD';
$udo['OID'] = $order->getIncrementId();
$udo['DISCOUNT'] = number_format(abs($order->discount_amount),2);
$order_coupon_code = $order->coupon_code;
if(!is_null($order_coupon_code) && !empty($order_coupon_code))
{
$udo['COUPON'] = $order_coupon_code;
}
$udo['PRODUCTLIST'] = self::_getOrderProductsList($order);
if(Mage::getModel('core/cookie')->get('ref') == 'cj') {
$udo['FIRECJ'] = "TRUE";
}
else {
$udo['FIRECJ'] = "FALSE";
}
$masterTmsUdo['CJ'] = $udo;
$json_masterTmsUdo = json_encode($masterTmsUdo);
Mage::log('Udo: '.$json_masterTmsUdo, null, 'cj.log');
return $json_masterTmsUdo;
}
}
?>
<script>var MasterTmsUdo = <?php $myObject = new xxx_Commissionjunction_Helper_Data(); echo $myObject->getCommissionJunctionUdo(); ?></script>
<script>/*DO NOT ALTER *** The Printer Depo*/(function(e){var t="1340",n=document,r,i,s={http:"http://cdn.mplxtms.com/s/MasterTMS.min.js",https:"https://secure-cdn.mplxtms.com/s/MasterTMS.min.js"},o=s[/\w+/.exec(window.location.protocol)[0]];i=n.createElement("script"),i.type="text/javascript",i.async=!0,i.src=o+"#"+t,r=n.getElementsByTagName("script")[0],r.parentNode.insertBefore(i,r),i.readyState?i.onreadystatechange=function(){if(i.readyState==="loaded"||i.readyState==="complete")i.onreadystatechange=null}:i.onload=function(){try{e()}catch(t){}}})(function(){});</script>
I dont know what you are intending to tell us by specifying, you need to integrate a p)html file with your custom module, by showing your file structure. Yes of course, that template file is outside your module structure. But you cannot attach that template file to your module (structure wise). This is simple and logical once you think about it. Just think, how Magento integrate template files with to its core modules, even though templates(phtml files), js and css files reside outside of its module scope(structure wise).
So we have a backend logic and view logic seperated in two section in magento. Magento now uses a layer called layout XML, which is used to connect these two sections.
Magento Modules <-------> Layout <-----------> view files
(lives in app/code) (app/design/.../layout) (templates :- app/design/.../templates
css,js,images :- skin)
So layouts stands in between modules and view and connect them. The advantage for this approach is two
This makes Magento highly extendable
This makes different logics seperated in structure wise. The importance is, we can now know where is a view logic resides, where controllers resides, where model resides. This logics seperated and most importantly indeperndent to each other.
Here is an another approach. Magento use module approach in it. Mean each module do different purposes and are independent each other. That means, if we made any changes in one module, it would not alter any logics of any other module. Each module has its own Model and its own controllers. That means Modules can individually talk to database and can connect its own module to View. Since Each modules create their own world in this way, modules are purely independent each other.
Now in order to communicate with view section, Magento uses layout layer. This is where everything get connecteD. Layouts used to set templates, js and css to each module in Magento. Thus they can access properties of that module in it and do Magics !!!. Layout is the place where each individual module get in touch. Hence it is very very important to study layout layer that using by Magento.
overview
Module1 TEMPLATES(hold design)
|
------ controllers(private)
| JS
------ Models(private) LAYOUTS Css
(Here every logics unites) Images
Module2
Module3
so on
(resides app/code) (resides app/design../layout) (reside app/design/..template and in skin)
so on
Once you mastered it, Magento will starts to obey you... Otherwise she will show hesitation. She is such a noty girl. Thats why I love her :)
I'm trying to get a template to work with a sorting menu in Joomla 3.
I'm using the category layout and a infinity load script which is working fine.
After that I made a new menu out of the categorie_list module which adds parameters like this (?category=your_category) to the a tag.
Now in order to get this system to work, I need to change the category where the blog view gets its articles from.
I already found the position at
components/com_content/models/category.php
at line 222
function getItems()
{
$limit = $this->getState('list.limit');
if ($this->_articles === null && $category = $this->getCategory())
{
$model = JModelLegacy::getInstance('Articles', 'ContentModel', array('ignore_request' => true));
$model->setState('params', JFactory::getApplication()->getParams());
$model->setState('filter.category_id', '$category->id'); // <- here!!!
$model->setState('filter.published', $this->getState('filter.published'));
$model->setState('filter.access', $this->getState('filter.access'));
$model->setState('filter.language', $this->getState('filter.language'));
$model->setState('list.ordering', $this->_buildContentOrderBy());
$model->setState('list.start', $this->getState('list.start'));
$model->setState('list.limit', $limit);
$model->setState('list.direction', $this->getState('list.direction'));
$model->setState('list.filter', $this->getState('list.filter'));
// filter.subcategories indicates whether to include articles from subcategories in the list or blog
$model->setState('filter.subcategories', $this->getState('filter.subcategories'));
$model->setState('filter.max_category_levels', $this->setState('filter.max_category_levels'));
$model->setState('list.links', $this->getState('list.links'));
if ($limit >= 0)
{
$this->_articles = $model->getItems();
if ($this->_articles === false)
{
$this->setError($model->getError());
}
}
else
{
$this->_articles = array();
}
$this->_pagination = $model->getPagination();
}
return $this->_articles;
}
Since I don't know, how to override a model within a template even having Googled it, I found nothing more than import it via a plugin.
And that is not what I need and want at all.
Maybe you guys have a handy trick for me.
1st suggestion
How to override the component mvc from the Joomla! core
http://docs.joomla.org/How_to_override_the_component_mvc_from_the_Joomla!_core
NOTICE: This method only works if you install and enable the 3rd party MVC plugin - or provide your own equivalent plugin. It is fine for advanced developers - just be aware that this is not part of Joomla! Core code.
2nd suggestion
Copy the entire core component, hack the copy and package the copy as a new component under a new name (e.g com_mycustomcontent). By doing this you will not have problems with upgrades unless there is a security issue with the original component. That means that you will be stuck if you don't know how to apply the updates of the original component to your component.
If anyone has an idea, I couldn't think of a better way to phase the question.
I'll try to not make this to complicated an explination.
I'm writing a "quotes" class that is the main class. This class has "overall" functions that preform calculations based on "items" stored in its array. Suffice it to say, the end-developer will call it as $q = new apiQuote/quote().
Then, before it's of any use, the first item must be added and it's properties set so it can do it's "own" calculations. Something like $q->createItem(). Once the item is created with this call, an "item" of the class "item" is added to an array in "quotes" named "items".
The currently editable item, $q->item is always the last one added to the array via the createItem method. Which looks like:
public function createNewItem() {
$this->items[] = new item();
$this->item = $this->items[count($this->items)-1];
}
I added setItem method, whereby the parameter would be an integer representing item index in the array and would set $q->item to the item index chosen. This works, but still seems "not as productive" as I'd like".
What I'm curious about, is if anyone has any suggestions on a better way to go about this. I tried looking for a "cards/deck" php example, but all I could find was array shuffles, which is kinda useless here. I know how to do such associations in .NET and thought this would be just as easy, but I don't have the same property abilities in PHP that I have in a .NET language, thus negating what I'm used to in created this kind of "class/subclass[items]" type structure.
Really I would just like to know if anyone has done anything similar and if I'm doing things to the "best of ability" or if there might be a better way, via PHP, to allow an "end-developer" to call on one main class and create a list "items" based on a subclass that can later be used for methods of the main class?
I really hope this sums it all up well and I havn't gone outside the guidelines of "question asking" here, but I can't think of a better place, other than maybe Code Review to pose such a question and get great developer feed back. If y'all feel I need move it to Code Review, let me know. My main reason for choosing this over CR is this site tends to get faster responses.
Perhaps a view of what I have and what I "might" like to see:
Way it works now
$q = new apiQuote\quote(TRUE);
$q->createNewItem();
$q->item->totalHeight = 100;
$q->item->totalWidth = 250;
...
$q->createNewItem();
$q->item->totalHeight = 300;
$q->item->set_coverage('25%');
...
$q->setItem(1);
$q->item->totalHeight = 250;
...
$q->getTotalsCurv(); // an array to create a graph curve of totals from each item
What I "think" I might like:
$q = new apiQuote\quote(TRUE);
$q->items[] = new apiQuote\item();
$q->items[0]->totalHeight = 100;
$q->items[0]->totalWidth = 250;
...
$q->items[] = new apiQuote\item();
$q->items[1]->totalHeight = 300;
$q->items[1]->set_coverage('25%');
...
$q->items[0]->totalHeight = 250;
...
$q->getTotalsCurv();
However, something like the second idea mean leaving the "items" array public, which could lead to a vast amount of "other" problems as I'm trying to set this whole thing up to be "near dummy proof". Thus the usage of protected variables with specific get/set methods as if they where C# properties.
I think your problem is how to identify an "item" outside of the quote instance. And by using its array index you feel you are going to run into the problems. And you will, when you will try to delete an item. It would successfully invalidate any index already known/stored outside. The simplest patch to it is to give every item a unique ID and store them in the map instead of storing it as a vector.
Also, in your solution item by itself cannot provide you with any helpful information how to access this item in your collection of items (a quote).
public function createNewItem() {
static $counter;
$id = $counter++;
return $this->item = $this->items[$id] = new item($id);
}
public function editItem($id) {
return $this->item = $this->items[$id];
}
public function removeItem($id) {
$this->item = null;
unset($this->item[$id]);
}
Alternatively I recommend you not to reinvent the wheel and take a look here:
http://php.net/manual/en/spl.datastructures.php
and here in specific
http://www.php.net/manual/en/class.splobjectstorage.php
Anything that implements Iterator interface can be iterated with foreach
http://www.php.net/manual/en/class.iterator.php
Ah well you could return the new item from the createItem function.
An equivalent of your .NET example would be to simply return the new item
public function createNewItem() {
$this->items[] = new item();
$this->item = $this->items[count($this->items)-1];
return $this->items[count($this->items)-1];
}
then you could do
$item = $q->createNewItem();
$item->totalHeight = 100;
...
And as you are already adding the new item to the array from within createNewItem so no need for something like $q->add($item);
And to get at any other item you could do a
function getItem($index){
return $this->items[count($this->items)-1];
}
$otheritem = $q->getItem(3);
$otheritem->totalHeight = 100;
I'm trying to create my own xml sitemap. Everything is done except for the part that I thought was going to be the easiest. How do you get a list of all the pages on the site? I have a bunch of views in a /site folder and a few others. Is there a way to explicitly request their URLs or perhaps via the controllers?
I do not want to make use of an extension
You can use reflection to iterate through all methods of all your controllers:
Yii::import('application.controllers.*');
$urls = array();
$directory = Yii::getPathOfAlias('application.controllers');
$iterator = new DirectoryIterator($directory);
foreach ($iterator as $fileinfo)
{
if ($fileinfo->isFile() and $fileinfo->getExtension() == 'php')
{
$className = substr($fileinfo->getFilename(), 0, -4); //strip extension
$class = new ReflectionClass($className);
foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method)
{
$methodName = $method->getName();
//only take methods that begin with 'action', but skip actions() method
if (strpos($methodName, 'action') === 0 and $methodName != 'actions')
{
$controller = lcfirst(substr($className, 0, strrpos($className, 'Controller')));
$action = lcfirst(substr($methodName, 6));
$urls[] = Yii::app()->createAbsoluteUrl("$controller/$action");
}
}
}
}
You need to know what content you want to include in your sitemap.xml, I don't really think you want to include ALL pages in your sitemap.xml, or do you really want to include something like site.com/article/edit/1 ?
That said, you may only want the result from the view action in your controllers. truth is, you need to know what you want to indexed.
Do not think in terms of controllers/actions/views, but rather think of the resources in your system that you want indexed, be them articles, or pages, they are all in your database or stored somehow, so you can list them, and they have a URI that identifies them, getting the URI is a matter of invoking a couple functions.
There are two possiblities -
Case 1:
You are running a static website then you can find all your HTML inside 1 folder - protected/views/site/pages
http://www.yiiframework.com/wiki/22/how-to-display-static-pages-in-yii/
Case 2:
Website is dynamic. Tasks such as generating and regenerating Sitemaps can be classified into background tasks.
Running background taks can be achieved by emulating the browser which is possible in linux using - WGET, GET or lynx commands
Or, You can create a CronController as a CConsoleCommand. How to use Commands in YII is shown in link below -
http://tariffstreet.com/yii/2012/04/implementing-cron-jobs-with-yii-and-cconsolecommand/
Sitemap is an XML which lists your site's URL. But it does more than that.
It helps you visualize the structure of a website , you may have
category
subcategories.
While making a useful extension, above points can be kept into consideration before design.
Frameworks like Wordpress provide way to generate categorical sitemap.
So the metadata for each page is stored from before and using that metadata it discovers and group pages.
Solution by Reflection suggested by #Pavle is good and should be the way to go.
Consider there may be partial views and you may or may not want to list them as separate links.
So how much effort you want to put into creating the extension is subject to some of these as well.
You may either ask user to list down all variables in config fie and go from there which is not bad or you have to group pages and list using some techniques like reflection and parsing pages and looking for regex.
For ex - Based on module names you can group them first and controllers inside a module can form sub-group.
One first approach could be to iterate over the view files, but then you have to take into account that in some cases, views are not page destinations, but page sections included in another pages by using CController::renderPartial() method. By exploring CController's Class Reference I came upon the CController::actions() method.
So, I have not found any Yii way to iterate over all the actions of a CController, but I used php to iterate over all the methods of a SiteController in one of my projects and filter them to these with the prefix 'action', which is my action prefix, here's the sample
class SiteController extends Controller{
public function actionTest(){
echo '<h1>Test Page!</h1></p>';
$methods = get_class_methods(get_class($this));
// The action prefix is strlen('action') = 6
$actionPrefix = 'action';
$reversedActionPrefix = strrev($actionPrefix);
$actionPrefixLength = strlen($actionPrefix);
foreach ($methods as $index=>$methodName){
//Always unset actions(), since it is not a controller action itself and it has the prefix 'action'
if ($methodName==='actions') {
unset($methods[$index]);
continue;
}
$reversedMethod = strrev($methodName);
/* if the last 6 characters of the reversed substring === 'noitca',
* it means that $method Name corresponds to a Controller Action,
* otherwise it is an inherited method and must be unset.
*/
if (substr($reversedMethod, -$actionPrefixLength)!==$reversedActionPrefix){
unset($methods[$index]);
} else $methods[$index] = strrev(str_replace($reversedActionPrefix, '', $reversedMethod,$replace=1));
}
echo 'Actions '.CHtml::listBox('methods', NULL, $methods);
}
...
}
And the output I got was..
I'm sure it can be furtherly refined, but this method should work for any of the controllers you have...
So what you have to do is:
For each Controller: Filter out all the not-action methods of the class, using the above method. You can build an associative array like
array(
'controllerName1'=>array(
'action1_1',
'action1_2'),
'controllerName2'=>array(
'action2_1',
'action2_2'),
);
I would add a static method getAllActions() in my SiteController for this.
get_class_methods, get_class, strrev and strlen are all PHP functions.
Based on your question:
1. How do you get a list of all the pages on the site?
Based on Yii's way of module/controller/action/action_params and your need to construct a sitemap for SEO.
It will be difficult to parse automatically to get all the urls as your action params varies indefinitely. Though you could simply get controller/action easily as constructed by
Pavle Predic. The complexity comes along when you have customized (SERF) URL rules meant for SEO.
The next best solution is to have a database of contents and you know how to get each content via url rules, then a cron console job to create all the urls to be saved as sitemap.xml.
Hope this helps!