I wanted separate my HTML from PHP so after searching I found a great little php class that just do the trick. Only issue that I try merging 2 templates together but it doesn’t work.
Here is the original class that i found from below website
http://www.broculos.net/2008/03/how-to-make-simple-html-template-engine.html#.WCsa8CTy2ng
class Template {
/**
* The filename of the template to load.
*
* #access protected
* #var string
*/
protected $file;
/**
* An array of values for replacing each tag on the template (the key for each value is its corresponding tag).
*
* #access protected
* #var array
*/
protected $values = array();
/**
* Creates a new Template object and sets its associated file.
*
* #param string $file the filename of the template to load
*/
public function __construct($file) {
$this->file = $file;
}
/**
* Sets a value for replacing a specific tag.
*
* #param string $key the name of the tag to replace
* #param string $value the value to replace
*/
public function set($key, $value) {
$this->values[$key] = $value;
}
/**
* Outputs the content of the template, replacing the keys for its respective values.
*
* #return string
*/
public function output() {
/**
* Tries to verify if the file exists.
* If it doesn't return with an error message.
* Anything else loads the file contents and loops through the array replacing every key for its value.
*/
if (!file_exists($this->file)) {
return "Error loading template file ($this->file).<br />";
}
$output = file_get_contents($this->file);
foreach ($this->values as $key => $value) {
$tagToReplace = "[#$key]";
$output = str_replace($tagToReplace, $value, $output);
}
return $output;
}
/**
* Merges the content from an array of templates and separates it with $separator.
*
* #param array $templates an array of Template objects to merge
* #param string $separator the string that is used between each Template object
* #return string
*/
static public function merge($templates, $separator = "\n") {
/**
* Loops through the array concatenating the outputs from each template, separating with $separator.
* If a type different from Template is found we provide an error message.
*/
$output = "";
foreach ($templates as $template) {
$content = (get_class($template) !== "Template")
? "Error, incorrect type - expected Template."
: $template->output();
$output .= $content . $separator;
}
return $output;
}
}
Code that work
$post = new Template("post.tpl");
$post->set("post_title", $post_title);
$post->set("post_description", $post_description);
$post->set("content", $post->output());
echo $post->output();
Even when I want to loop if I add the code it works fine. But then I try to merge two template files together
all_posts.tpl
<div class=”posts”>
<h1>[#page_title]</</h1>
[#display_posts]
</div>
display_posts.tpl
<div class=”post”>
<h2>[#display_title]</h2>
<p>[#display_description]</p>
</div>
So what I want to do now is to push display_posts.tpl to all_posts.tpl and replace the tag [#display_posts]
So in my php I did below
$post = new Template("all_posts.tpl ");
$post->set("page_title", "All Posts");
echo $post->output();
//created a array from a mysqli loop
$post_set = array();
while ($post_row = mysqli_fetch_array($posts)){
$post_title = $post_row['title'];
$post_description = $post_row['description'];
$post_set[] = array(
"display_title" => $post_title,
"display_description" => $post_description
);
}
foreach ($post_set as $posts) {
$row = new Template("list_users_row.tpl");
foreach ($posts as $key => $value) {
$row->set($key, $value);
}
$postsTemplates[] = $posts;
}
// here i try to merge template
$postsContents = Template::merge($postsTemplates);
$layout->set("content", $postsContents->output());
echo $layout->output();
But this is throwing off a error set() is not an function. Could someone help me out to figure out this? I’m still in the process of learning php classes.
The reason why $layout->set() does not work is because $layout is not a Template Object. In your code you use $post = new Template("all_posts.tpl ");. This makes $post a Template object that can use the set() function in your Template class.
So you should do: $layout = new Template(....) and than you can call $layout->set().
In the tutorial they do the same:
include("template.class.php");
$profile = new Template("user_profile.tpl");
$profile->set("username", "monk3y");
$profile->set("photoURL", "photo.jpg");
$profile->set("name", "Monkey man");
$profile->set("age", "23");
$profile->set("location", "Portugal");
$layout = new Template("layout.tpl");
$layout->set("title", "User profile");
$layout->set("content", $profile->output());
echo $layout->output();
Hope this helps.
Related
I'm building the admin for a Magento2 store (currently on 2.1.7, they want to use the newest version until we go live and then want to stabilize a particular version). The module in question is supposed to display all existing orders, with an actionsColumn that contains links to cancel, edit, and open a detailed overview of the purchased items associated with that order. The order detail page contains a grid view that should display all order items associated with an order number passed in the URL.
In order to filter out Order Items that don't relate to the specific Order Number, I've extended the \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult class. This works except for one weird caveat. If, in the addFieldToFilter call, I replace $ordNum with, say, '10000', it grabs the correct data. When using $ordNum to call this dynamically, however, it returns no rows at all. This despite trying all sorts of casting and === checks to ensure that there's no difference between the hardcoded and dynamic values. Is this a Magento bug? I can't at all figure out why this would be the case.
<?php
class OrderItems extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult
{
protected function _initSelect()
{
$this->filterByOrderNum();
parent::_initSelect();
return $this;
}
private function filterByOrderNum()
{
$request = \Magento\Framework\App\ObjectManager::getInstance()
->get('Magento\Framework\App\Request\Http');
$ordNum = $request->getParam('order_num');
$this->addFieldToFilter('order_num', ['eq' => $ordNum]); //if I switch this to hardcoded 10000, this works. With the variable, no dice.
return $this;
}
}
I just fixed it by using mentioned below steps
Store param value in session in controller
public function execute() {
$this->_catalogSession->setTokenId($this->request->getParam('entity_id'));
$this->_view->loadLayout();
$this->_view->loadLayoutUpdates();
$this->_view->getPage()->getConfig()->getTitle()->set(__('Redeem Token History'));
$this->_view->renderLayout();
}
Use session value in dataprovider
$tokensCollection->addFieldToFilter('token_id', ['eq' => $this->_catalogSession->getTokenId()]);
Enjoy :)
Try this in place of the getParam statement:
$url = parse_url($request);
$path = explode('/',$url['path']);
$ordNum = $path[3];
Just to make sure we are on the same page, this is the full code:
<?php
class OrderItems extends \Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult
{
protected function _initSelect()
{
$this->filterByOrderNum();
parent::_initSelect();
return $this;
}
private function filterByOrderNum()
{
$request = \Magento\Framework\App\ObjectManager::getInstance()
->get('Magento\Framework\App\Request\Http');
$url = parse_url($request);
$path = explode('/',$url['path']);
$ordNum = $path[3];
$this->addFieldToFilter('order_num', $ordNum); //if I switch this to hardcoded 10000, this works. With the variable, no dice.
return $this;
}
}
We have solved this issue by doing the following :
/**
* CcCustompriceProductListingDataProvider constructor.
* #param string $name
* #param string $primaryFieldName
* #param string $requestFieldName
* #param \Magento\Framework\Api\Search\ReportingInterface $reporting
* #param \Magento\Framework\Api\Search\SearchCriteriaBuilder $searchCriteriaBuilder
* #param \Magento\Framework\App\RequestInterface $request
* #param \Magento\Framework\Api\FilterBuilder $filterBuilder
* #param array $meta
* #param array $data
* #throws \Exception
*/
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
ReportingInterface $reporting,
SearchCriteriaBuilder $searchCriteriaBuilder,
RequestInterface $request,
FilterBuilder $filterBuilder,
array $meta = [],
array $data = []
) {
$data['config']['filter_url_params']['product_id'] = $request->getParam('cppc_product_id', 0);
parent::__construct($name, $primaryFieldName, $requestFieldName, $reporting, $searchCriteriaBuilder, $request, $filterBuilder, $meta, $data);
}
You do not need to use any other function. The reason why this is is because it is also updated with an update URL and that does not have that parameter. By using adding that to the data it also parses that into the update url.
You can see that here (Parent function)
/**
* #return void
*/
protected function prepareUpdateUrl()
{
if (!isset($this->data['config']['filter_url_params'])) {
return;
}
foreach ($this->data['config']['filter_url_params'] as $paramName => $paramValue) {
if ('*' == $paramValue) {
$paramValue = $this->request->getParam($paramName);
}
if ($paramValue) {
$this->data['config']['update_url'] = sprintf(
'%s%s/%s/',
$this->data['config']['update_url'],
$paramName,
$paramValue
);
$this->addFilter(
$this->filterBuilder->setField($paramName)->setValue($paramValue)->setConditionType('eq')->create()
);
}
}
}
Is it possible to freeze 1st row (freeze pane) of the spreadsheet using box/spout?
With PHPexcel I do like that:
$objPHPExcel=new PHPExcel();
$ActiveSheet=$objPHPExcel->getActiveSheet();
$ActiveSheet->freezePane('A2');
Cannot use PHPexcel, as I am working with big files.
Found a hack to add this feature.
Inside of Spout\Writer\XLSX\Manager\WorksheetManager.php : function startSheet
After this line
fwrite($sheetFilePointer, self::SHEET_XML_FILE_HEADER);
Add this line
fwrite($sheetFilePointer, '<sheetViews><sheetView showRowColHeaders="1" showGridLines="true" workbookViewId="0" tabSelected="1">'
.'<pane state="frozen" activePane="bottomLeft" topLeftCell="A2" ySplit="1"/>'
.'<selection sqref="A1" activeCell="A1" pane="bottomLeft"/></sheetView></sheetViews>');
<?php
/**
*
* Inspired by: https://github.com/box/spout/issues/368
*
* Simple helper class for Spout - to return rows indexed by the header in the sheet
*
* Author: Jaspal Singh - https://github.com/jaspal747
* Feel free to make any edits as needed. Cheers!
*
*/
class SpoutHelper {
private $rawHeadersArray = []; //Local array to hold the Raw Headers for performance
private $formattedHeadersArray = []; //Local array to hold the Formatted Headers for performance
private $headerRowNumber; //Row number where the header col is located in the file
/**
* Initialize on a per sheet basis
* Allow users to mention which row number contains the headers
*/
public function __construct($sheet, $headerRowNumber = 1) {
$this->flushHeaders();
$this->headerRowNumber = $headerRowNumber;
$this->getFormattedHeaders($sheet);//Since this also calls the getRawHeaders, we will have both the arrays set at once
}
/**
*
* Set the rawHeadersArray by getting the raw headers from the headerRowNumber or the 1st row
* Once done, set them to a local variable for being reused later
*
*/
public function getRawHeaders($sheet) {
if (empty($this->rawHeadersArray)) {
/**
* first get column headers
*/
foreach ($sheet->getRowIterator() as $key => $row) {
if ($key == $this->headerRowNumber) {
/**
* iterate once to get the column headers
*/
$this->rawHeadersArray = $row->toArray();
break;
}
}
} else {
/**
* From local cache
*/
}
return $this->rawHeadersArray;
}
/**
*
* Set the formattedHeadersArray by getting the raw headers and the parsing them
* Once done, set them to a local variable for being reused later
*
*/
public function getFormattedHeaders($sheet) {
if (empty($this->formattedHeadersArray)) {
$this->formattedHeadersArray = $this->getRawHeaders($sheet);
/**
* Now format them
*/
foreach ($this->formattedHeadersArray as $key => $value) {
if (is_a($value, 'DateTime')) { //Somehow instanceOf does not work well with DateTime, hence using is_a -- ?
$this->formattedHeadersArray[$key] = $value->format('Y-m-d');//Since the dates in headers are avilable as DateTime Objects
} else {
$this->formattedHeadersArray[$key] = strtolower(str_replace(' ' , '_', trim($value)));
}
/**
* Add more rules here as needed
*/
}
} else {
/**
* Return from local cache
*/
}
return $this->formattedHeadersArray;
}
/**
* Return row with Raw Headers
*/
public function rowWithRawHeaders($rowArray) {
return $this->returnRowWithHeaderAsKeys($this->rawHeadersArray, $rowArray);
}
/**
* Return row with Formatted Headers
*/
public function rowWithFormattedHeaders($rowArray) {
return $this->returnRowWithHeaderAsKeys($this->formattedHeadersArray, $rowArray);
}
/**
* Set the headers to keys and row as values
*/
private function returnRowWithHeaderAsKeys($headers, $rowArray) {
$headerColCount = count($headers);
$rowColCount = count($rowArray);
$colCountDiff = $headerColCount - $rowColCount;
if ($colCountDiff > 0) {
//Pad the rowArray with empty values
$rowArray = array_pad($rowArray, $headerColCount, '');
}
return array_combine($headers, $rowArray);
}
/**
* Flush local caches before each sheet
*/
public function flushHeaders() {
$this->formattedHeadersArray = [];
$this->rawHeadersArray = [];
}
}
And then in your main file you can do:
$reader = ReaderEntityFactory::createReaderFromFile($filePath);
$reader->open($filePath);
/**
* Now get the data
*/
foreach ($reader->getSheetIterator() as $sheet) {
$spoutHelper = new SpoutHelper($sheet, 1); //Initialize SpoutHelper with the current Sheet and the row number which contains the header
foreach ($sheet->getRowIterator() as $key => $row) {
if ($key == 1) {
//echo "Skipping Headers row";
continue;
}
//Get the indexed array with col name as key and col val as value`
$rowWithHeaderKeys = $spoutHelper->rowWithFormattedHeaders($row->toArray());
}
}
Source: https://gist.github.com/jaspal747/2bd515f9e318b0331f3ca3d2297742c5
It's not possible to freeze panes with Spout yet. But you can always fork the repo and implement this feature :)
I've been trying to create a form in the article component backend, so that I can add few things attributes per article. I got this sample code from the joomla website documentation. http://docs.joomla.org/Adding_custom_fields_to_the_article_component
I understand the method onContentPrepareForm is an important function which adds this form in the joomla article backend. However, it doesn't appear for me. I somehow checked global other options and I got to see that the form comes up in the global article options as a seperate tab. However I'd like to add this form for each article.
The version of joomla I am using is 3.2 ...
Btw I have enabled the plugin in the backend ...
<?php
/**
* #package Joomla.Site
* #subpackage plg_content_rating
* #copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
* #license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('JPATH_BASE') or die;
jimport('joomla.utilities.date');
/**
* An example custom profile plugin.
*
* #package Joomla.Plugin
* #subpackage User.profile
* #version 1.6
*/
class plgContentRating extends JPlugin
{
/**
* Constructor
*
* #access protected
* #param object $subject The object to observe
* #param array $config An array that holds the plugin configuration
* #since 2.5
*/
public function __construct(& $subject, $config)
{
parent::__construct($subject, $config);
$this->loadLanguage();
}
/**
* #param string $context The context for the data
* #param int $data The user id
* #param object
*
* #return boolean
* #since 2.5
*/
function onContentPrepareData($context, $data)
{
if (is_object($data))
{
$articleId = isset($data->id) ? $data->id : 0;
if (!isset($data->rating) and $articleId > 0)
{
// Load the profile data from the database.
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('profile_key, profile_value');
$query->from('#__user_profiles');
$query->where('user_id = ' . $db->Quote($articleId));
$query->where('profile_key LIKE ' . $db->Quote('rating.%'));
$query->order('ordering');
$db->setQuery($query);
$results = $db->loadRowList();
// Check for a database error.
if ($db->getErrorNum())
{
$this->_subject->setError($db->getErrorMsg());
return false;
}
// Merge the profile data.
$data->rating = array();
foreach ($results as $v)
{
$k = str_replace('rating.', '', $v[0]);
$data->rating[$k] = json_decode($v[1], true);
if ($data->rating[$k] === null)
{
$data->rating[$k] = $v[1];
}
}
}
}
return true;
}
/**
* #param JForm $form The form to be altered.
* #param array $data The associated data for the form.
*
* #return boolean
* #since 2.5
*/
function onContentPrepareForm($form, $data)
{
if (!($form instanceof JForm))
{
$this->_subject->setError('JERROR_NOT_A_FORM');
return false;
}
/* if (!in_array($form->getName(), array('com_content.article'))) {
return true;
}*/
// Add the extra fields to the form.
// need a seperate directory for the installer not to consider the XML a package when "discovering"
JForm::addFormPath(dirname(__FILE__) . '/rating');
$form->loadFile('rating',false);
return true;
}
/**
* Example after save content method
* Article is passed by reference, but after the save, so no changes will be saved.
* Method is called right after the content is saved
*
* #param string The context of the content passed to the plugin (added in 1.6)
* #param object A JTableContent object
* #param bool If the content is just about to be created
* #since 2.5
*/
public function onContentAfterSave($context, &$article, $isNew)
{
$articleId = $article->id;
if ($articleId && isset($article->rating) && (count($article->rating)))
{
try
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->delete('#__user_profiles');
$query->where('user_id = ' . $db->Quote($articleId));
$query->where('profile_key LIKE ' . $db->Quote('rating.%'));
$db->setQuery($query);
if (!$db->query()) {
throw new Exception($db->getErrorMsg());
}
$query->clear();
$query->insert('#__user_profiles');
$order = 1;
foreach ($article->rating as $k => $v)
{
$query->values($articleId.', '.$db->quote('rating.'.$k).', '.$db->quote(json_encode($v)).', '.$order++);
}
$db->setQuery($query);
if (!$db->query()) {
throw new Exception($db->getErrorMsg());
}
}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}
return true;
}
/**
* Finder after delete content method
* Article is passed by reference, but after the save, so no changes will be saved.
* Method is called right after the content is saved
*
* #param string The context of the content passed to the plugin (added in 1.6)
* #param object A JTableContent object
* #since 2.5
*/
public function onContentAfterDelete($context, $article)
{
$articleId = $article->id;
if ($articleId)
{
try
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->delete();
$query->from('#__user_profiles');
$query->where('user_id = ' . $db->Quote($articleId));
$query->where('profile_key LIKE ' . $db->Quote('rating.%'));
$db->setQuery($query);
if (!$db->query())
{
throw new Exception($db->getErrorMsg());
}
}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}
return true;
}
public function onContentPrepare($context, &$article, &$params, $page = 0)
{
if (!isset($article->rating) || !count($article->rating))
return;
// add extra css for table
$doc = JFactory::getDocument();
$doc->addStyleSheet(JURI::base(true).'/plugins/content/rating/rating/rating.css');
// construct a result table on the fly
jimport('joomla.html.grid');
$table = new JGrid();
// Create columns
$table->addColumn('attr')
->addColumn('value');
// populate
$rownr = 0;
foreach ($article->rating as $attr => $value) {
$table->addRow(array('class' => 'row'.($rownr % 2)));
$table->setRowCell('attr', $attr);
$table->setRowCell('value', $value);
$rownr++;
}
// wrap table in a classed <div>
$suffix = $this->params->get('ratingclass_sfx', 'rating');
$html = '<div class="'.$suffix.'">'.(string)$table.'</div>';
$article->text = $html.$article->text;
}
}
EDIT POST:
I added this code to /administrator/components/com_content/views/article/tmpl/edit.php
<?php
$i = 0;
$fieldSets = $this->form->getFieldsets();
foreach ($fieldSets as $name => $fieldSet) :
if($i <= 3){
$i++;
continue;
}
echo JHtml::_('bootstrap.addTab', 'myTab', $fieldSet->name, JText::_($fieldSet->label, true));
?>
<div class="tab-pane" id="<?php echo $name;?>">
<?php
if (isset($fieldSet->description) && !empty($fieldSet->description)) :
echo '<p class="tab-description">'.JText::_($fieldSet->description).'</p>';
endif;
foreach ($this->form->getFieldset($name) as $field):
?>
<div class="control-group">
<?php if (!$field->hidden && $name != "permissions") : ?>
<div class="control-label">
<?php echo $field->label; ?>
</div>
<?php endif; ?>
<div class="<?php if ($name != "permissions") : ?>controls<?php endif; ?>">
<?php echo $field->input; ?>
</div>
</div>
<?php
endforeach;
?>
</div>
<?php echo JHtml::_('bootstrap.endTab'); ?>
<?php endforeach; ?>
As you've mentioned the core tmpl file won't support your changes.
Hacking the core files (as you've done) is a very bad idea for several reason, including that they could be overwritten when the next 3.2.x security patch is released (like the upcoming 3.2.1) and most certainly will be when 3.5 is released. Given the rapidity Joomla releases security patches and their regular 1-click Major and Minor update cycle the last thing you want to be worrying about is your changes being blown away.
Luckily Joomla lets you create template overrides, the process for admin is pretty much the same as overrides for front-end templates.
Luckily for you the modification is in the right file, assuming you're using the default Admin template Isis simply copy
/administrator/components/com_content/views/article/tmpl/edit.php
to:
/administrator/templates/isis/html/com_content/article/edit.php
You may want to revert your original file but as mentioned it's almost certainly to get updated in either a security update or version update.
found a solution to your problem (and mine) in another article here solution to your problem hope it helps. It appears that the example plugin contains an error
I'm having the following two classes:
Class I:
<?php
/**
* Wrapper class for the Envato marketplaces API
*/
class envato_api_wrapper {
protected $api_key;
protected $cache_dir = 'cache';
public $cache_expires = 2;
protected $public_url = 'http://marketplace.envato.com/api/edge/set.json';
public function __construct($api_key = null) {
if ( isset($api_key) ) $this->api_key = $api_key; // allow the user to pass the API key upon instantiation
}
/**
* Attach your API key.
*
* #param string $api_key Can be accessed on the marketplaces via My Account
* -> My Settings -> API Key
*/
public function set_api_key($api_key)
{
$this->api_key = $api_key;
}
/**
* Retrieve the value of your API KEY, if needed.
*
* #return string The requested API Key.
*/
public function get_api_key()
{
if ( ! isset($this->api_key) ) return 'No API Key is set.';
return $this->api_key;
}
/**
* Sets the cache directory for all API calls.
*
* #param string $cache_dir
*/
public function set_cache_dir($cache_dir)
{
$this->cache_dir = $cache_dir;
}
/**
* Retrieve the value of your cache directory, if needed.
*
* #return string The requested cache directory.
*/
public function get_cache_dir()
{
return $this->cache_dir;
}
/**
* Available sets => 'vitals', 'earnings-and-sales-by-month', 'statement', 'recent-sales', 'account', 'verify-purchase', 'download-purchase'
*
*/
public function private_user_data($user_name, $set, $purchase_code = null)
{
if ( ! isset($this->api_key) ) exit('You have not set an api key yet. $class->set_api_key(key)');
if (! isset($set) ) return 'Missing parameters';
$url = "http://marketplace.envato.com/api/edge/$user_name/$this->api_key/$set";
if ( !is_null($purchase_code) ) $url .= ":$purchase_code";
$url .= '.json';
$result = $this->fetch($url);
if ( isset($result->error) ) return 'Username, API Key, or purchase code is invalid.';
return $result->$set;
}
/**
* Can be used to verify if a person did in fact purchase your item.
*
* #param $user_name Author's username.
* #param $purchase_code - The buyer's purchase code. See Downloads page for
* receipt.
* #return object|bool If purchased, returns an object containing the details.
*/
public function verify_purchase($user_name, $purchase_code)
{
$validity = $this->private_user_data($user_name, 'verify-purchase', $purchase_code);
return isset($validity->buyer) ? $validity : false;
}
/**
* Retrieve details for your most recent sales.
*
* #param string $user_name The username attached to your API KEY.
* #param int $limit The number of sales to return.
* #return array A list of your recent sales.
*/
public function recent_sales($user_name, $limit = null)
{
$sales = $this->private_user_data($user_name, 'recent-sales');
return $this->apply_limit($sales, $limit);
}
/**
* Retrieve your account information -- balance, location, name, etc.
*
* #param string $user_name The username attached to your API KEY.
* #return array A list of account information for the user.
*/
public function account_information($user_name)
{
$private_data = $this->private_user_data($user_name, 'account');
return json_decode(json_encode($private_data), true);
}
/**
* Grab quick monthly stats - number of sales, income, etc.
*
* #param string $user_name The username attached to your API KEY.
* #param int $limit The number of months to return.
* #return array A list of sales figures, ordered by month.
*/
public function earnings_by_month($user_name, $limit = null)
{
$earnings = $this->private_user_data($user_name, 'earnings-and-sales-by-month');
return $this->apply_limit($earnings, $limit);
}
/**
* Generic method, to be used in combination with the marketplace API docs.
*
* #param string $user_name The user name of the seller to track.
* #return array The returned data wrapped in an array.
*/
public function public_user_data($user_name)
{
$url = preg_replace('/set/i', 'user:' . $user_name, $this->public_url);
return $this->fetch($url, 'user');
}
/**
* Retrieve the details for a specific marketplace item.
*
* #param string $item_id The id of the item you need information for.
* #return object Details for the given item.
*/
public function item_details($item_id)
{
$url = preg_replace('/set/i', 'item:' . $item_id, $this->public_url);
return $this->fetch($url, 'item');
}
/**
* Similar to new_files, but focuses on a specific author's files.
*
* #param string $user_name The desired username.
* #param string $marketplace_name The desired marketplace name.
* #param int $limit The number of files to return.
* #return array A list of recently added files by one user.
*/
public function new_files_from_user($user_name, $marketplace_name = 'themeforest', $limit = null)
{
$cache_path = "$this->cache_dir/$user_name-$marketplace_name-new_files";
$url = preg_replace('/set/i', 'new-files-from-user:' . $user_name . ',' . $marketplace_name, $this->public_url);
return $this->apply_limit( $this->fetch($url, 'new-files-from-user'), $limit );
}
/**
* Display the number of items the author has for sale by marketplace
*
* #param string $user_name The desired username.
*/
public function user_items_by_site($user_name)
{
$cache_path = "$this->cache_dir/$user_name";
$url = preg_replace('/set/i', 'user-items-by-site:' . $user_name, $this->public_url);
return $this->fetch($url, 'user-items-by-site');
}
/**
* Retrieves general marketplace member information.
*
* #param string $user_name The username to query.
* #return object Contains the requested user information.
*/
public function user_information($user_name)
{
$url = preg_replace('/set/i', 'user:' . $user_name, $this->public_url);
return $this->fetch($url, 'user');
}
/*
* Either fetches the desired data from the API and caches it, or fetches the cached version
*
* #param string $url The url to the API call
* #param string $set (optional) The name of the set to retrieve.
*/
protected function fetch($url, $set = null)
{
// Use the API url to generate the cache file name.
// So: http://marketplace.envato.com/api/edge/collection:739793.json
// Becomes: collection-739793.json
$cache_path = $this->cache_dir . '/' . str_replace(':', '-', substr(strrchr($url, '/'), 1));
if ( $this->has_expired($cache_path) ) {
// get fresh copy
$data = $this->curl($url);
if ($data) {
$data = isset($set) ? $data->{$set} : $data; // if a set is needed, update
} else exit('Could not retrieve data.');
$this->cache_it($cache_path, $data);
return $data;
} else {
// if available in cache, use that
return json_decode(file_get_contents($cache_path));
}
}
/**
* Filters returned result, according to the supplied $limit.
*
* #param string $orig_arr The original array to work on.
* #param int $limit Specifies the number of array items in the result.
* #return array A new array with a count equal to the passed $limit.
*/
public function apply_limit($orig_arr, $limit)
{
if ( !is_int($limit) ) return $orig_arr;
// Make sure that there are enough items to filter through...
if ( $limit > count($orig_arr) ) $limit = count($orig_arr);
$new_arr = array();
for ( $i = 0; $i <= $limit - 1; $i++ ) {
$new_arr[] = $orig_arr[$i];
}
return $new_arr;
}
/**
* General purpose function to query the marketplace API.
*
* #param string $url The url to access, via curl.
* #return object The results of the curl request.
*/
protected function curl($url)
{
if ( empty($url) ) return false;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
$data = json_decode($data);
return $data; // string or null
}
/*
* Caches the results request to keep from hammering the API
*
* #param string $cache_path - A path to the cache file
* #param string $data - The results from the API call - should be encoded
*/
protected function cache_it($cache_path, $data)
{
if ( !isset($data) ) return;
!file_exists($this->cache_dir) && mkdir($this->cache_dir);
file_put_contents( $cache_path, json_encode($data) );
return $cache_path;
}
/*
* Determines whether the provided file has expired yet
*
* #param string $cache_path The path to the cached file
* #param string $expires - In hours, how long the file should cache for.
*/
protected function has_expired($cache_path, $expires = null)
{
if ( !isset($expires) ) $expires = $this->cache_expires;
if ( file_exists($cache_path) ) {
return time() - $expires * 60 * 60 > filemtime($cache_path);
}
return true;
}
/*
* Helper function that deletes all of the files in your cache directory.
*/
public function clear_cache(){
array_map('unlink', glob("$this->cache_dir/*"));
}
}
Class II:
<?php
/**
* Operation Class for Envato API Wrapper
*/
class envato_api_class {
protected $api_key;
protected $username;
public $envato_api_wrapper;
public $path_to_envato_api_wrapper;
public function __construct($api_key = null, $username = null) {
if ( isset($api_key) ) {
$this->api_key = $api_key;
} elseif ( isset($username) ) {
$this->username = $username;
}
$this->path_to_envato_api_wrapper = 'envato_api_wrapper.php';
require($this->path_to_envato_api_wrapper);
$this->envato_api_wrapper = new envato_api_wrapper($api_key);
}
public function get_all_items_by_site() {
$items_by_marketplace = $this->envato_api_wrapper->user_items_by_site($this->username);
$marketplaces = array();
foreach ($items_by_marketplace as $key) {
$marketplaces[] = array(
'Marketplace' => $key->site,
'Items' => $key->items
);
}
foreach ($marketplaces as $key) {
$items[$key['Marketplace']] = $this->envato_api_wrapper->new_files_from_user($this->username, $key['Marketplace']);
}
return json_decode(json_encode($items), true);
}
public function get_all_items() {
$items_by_marketplace = $this->envato_api_wrapper->user_items_by_site($this->username);
$marketplaces = array();
$items = array();
$item = array();
foreach ($items_by_marketplace as $key) {
$marketplaces[] = array(
'Marketplace' => $key->site,
'Items' => $key->items
);
}
foreach ($marketplaces as $key) {
$items[$key['Marketplace']] = $this->envato_api_wrapper->new_files_from_user($this->username, $key['Marketplace']);
}
foreach ($items as $main_key) {
foreach ($main_key as $secondary_key) {
$item[] = array(
'ID' => $secondary_key->id,
'Item' => $secondary_key->item,
'URL' => $secondary_key->url,
'User' => $secondary_key->user,
'Thumb' => $secondary_key->thumbnail,
'Sales' => $secondary_key->sales,
'Rating' => $secondary_key->rating,
'Cost' => $secondary_key->cost,
'Uploaded' => $secondary_key->uploaded_on,
'Tags' => $secondary_key->tags,
'Category' => $secondary_key->category,
'Preview' => $secondary_key->live_preview_url
);
}
}
return $item;
}
}
?>
And I'm trying to execute the following code in another file, three levels above where the classes are located:
<?php
require 'assets/class/envato/envato_api_class.php';
$api_key = 'some_key_here';
$username = 'some_username_here';
$envato = new envato_api_class($api_key, $username);
$items = $envato->get_all_items();
function rating($cluster) {
for ($i = 1; $i <= $cluster; $i++) {
echo '<img src="assets/gfx/filled-star.png" alt="Rating" />';
}
$empty = 5 - $cluster;
if ($empty > 0) {
for ($i = 0; $i < $empty; $i++) {
echo '<img src="assets/gfx/empty-star.png" alt="Rating" />';
}
}
}
// Adding Rows instead of altogether...
$halfway = floor(count($items)/2);
$count=0;
echo '<div class="item-row">';
foreach ($items as $key) {
// Check if we can add the second row
if($count==$halfway){
echo '</div><div class="item-row">';
}
$count++;
echo '<div class="product id-'.$key['ID'].'">';
echo '<div class="description">';
echo '<div class="thumb">';
echo '<i class="icon"><img src="'.$key['Thumb'].'" alt="Thumb"/><span class="preview" data-image-link="'.$key['Preview'].'"><img src="assets/gfx/zoom-icon.png" alt="Zoom"/></span></i>';
echo '</div>';
echo '<div class="info">';
echo '<div class="sales">';
echo '<div class="icon">';
echo '<img src="assets/gfx/sales-icon.png" alt="Sales Icon"/>';
echo '</div>';
echo '<div class="text">';
echo '<p>'.$key['Sales'].'</p>';
echo '</div>';
echo '</div>';
echo '<div class="rating">';
rating($key['Rating']);
echo '</div>';
echo '</div>';
echo '</div>';
echo '<div class="purchase">';
echo '<div class="info">';
echo '<i class="icon"><span class="tooltip">$ '.$key['Cost'].'</span></i>';
echo '</div>';
echo '<div class="proceed">';
echo '<a class="button" href="'.$key['URL'].'?ref='.$username.'">Purchase</a>';
echo '</div>';
echo '</div>';
echo '</div>';
}
echo '</div>'; // End Item Row
?>
But when testing on localhost I get the following error:
Notice: Undefined property: stdClass::$user-items-by-site in C:\xampp\htdocs\Envato\assets\class\envato\envato_api_wrapper.php on line 233
Can someone tell me why am I getting that error ? What am I doing wrong there ?
You get that error because of this line (198):
return $this->fetch($url, 'user-items-by-site');
In combination with line 233:
$data = isset($set) ? $data->{$set} : $data; // if a set is needed, update
You're apparently trying to access a member that does not exist.
Because the data comes from a remote source and is then parsed as JSON, we probably can't help much more.
I'm getting the following warning when try to view list_of_holidays.pdf from the remote server:
Warning (2): Cannot modify header information - headers already sent by (output started
at /home/aquinto1/app/views/helpers/flash.php:155) [APP/vendors/tcpdf/tcpdf.php, line 8541]
TCPDF ERROR: Some data has already been output to browser, can't send PDF file
line 155 is the last line in flash.php ie the closing tag for php (?>). Before that it is the code to embedSWF. I don't see anything wrong with that.
However, it is displaying fine on the local server.
I've checked for whitespaces and yet the error is still there.
i'm already using ob_clean before the output.
can someone tell me on what i'm doing wrong. FYI i'm using cakephp with tcpdf.
The following is flash.php
class FlashHelper extends AppHelper {
var $helpers = array('Javascript');
/**
* Used for remembering options from init() to each renderSwf
*
* #var array
*/
var $options = array(
'width' => 100,
'height' => 100
);
/**
* Used by renderSwf to set a flash version requirement
*
* #var string
*/
var $defaultVersionRequirement = '9.0.0';
/**
* Used by renderSwf to only call init if it hasnt been done, either
* manually or automatically by a former renderSwf()
*
* #var boolean
*/
var $initialized = false;
/**
* Optional initializing for setting default parameters and also includes the
* swf library. Should be called once, but if using several groups of flashes,
* MAY be called several times, once before each group.
*
* #example echo $flash->init();
* #example $flash->init(array('width'=>200,'height'=>100);
* #return mixed String if it was not able to add the script to the view, true if it was
*/
function init($options = array()) {
if (!empty($options)) {
$this->options = am($this->options, $options);
}
$this->initialized = true;
$view =& ClassRegistry::getObject('view');
if (is_object($view)) {
$view->addScript($this->Javascript->link('swfobject'));
return true;
} else {
return $this->Javascript->link('swfobject');
}
}
/**
* Wrapper for the SwfObject::embedSWF method in the vendor. This method will write a javascript code
* block that calls that javascript method. If given a dom id as fourth parameter the flash will
* replace that dom object. If false is given, a div will be placed at the point in the
* page that this method is echo'ed. The last parameter is mainly used for sending in extra settings to
* the embedding code, like parameters and attributes. It may also send in flashvars to the flash.
*
* For doucumentation on what options can be sent, look here:
* http://code.google.com/p/swfobject/wiki/documentation
*
* #example echo $flash->renderSwf('counter.swf'); // size set with init();
* #example echo $flash->renderSwf('flash/ad.swf',100,20);
* #example echo $flash->renderSwf('swf/banner.swf',800,200,'banner_ad',array('params'=>array('wmode'=>'opaque')));
* #param string $swfFile Filename (with paths relative to webroot)
* #param int $width if null, will use width set by FlashHelper::init()
* #param int $height if null, will use height set by FlashHelper::init()
* #param mixed $divDomId false or string : dom id
* #param array $options array('flashvars'=>array(),'params'=>array('wmode'=>'opaque'),'attributes'=>array());
* See SwfObject documentation for valid options
* #return string
*/
function renderSwf($swfFile, $width = null, $height = null, $divDomId = false, $options = array()) {
$options = am ($this->options, $options);
if (is_null($width)) {
$width = $options['width'];
}
if (is_null($height)) {
$height = $options['height'];
}
$ret = '';
if (!$this->initialized) {
$init = $this->init($options);
if (is_string($init)) {
$ret = $init;
}
$this->initialized = TRUE;
}
$flashvars = '{}';
$params = '{wmode : "opaque"}';
$attributes = '{}';
if (isset($options['flashvars'])) {
$flashvars = $this->Javascript->object($options['flashvars']);
}
if (isset($options['params'])) {
$params = $this->Javascript->object($options['params']);
}
if (isset($options['attributes'])) {
$attributes = $this->Javascript->object($options['attributes']);
}
if ($divDomId === false) {
$divDomId = uniqid('c_');
$ret .= '<div id="'.$divDomId.'"></div>';
}
if (isset($options['version'])) {
$version = $options['version'];
} else {
$version = $this->defaultVersionRequirement;
}
if (isset($options['install'])) {
$install = $options['install'];
} else {
$install = '';
}
$swfLocation = $this->webroot.$swfFile;
$ret .= $this->Javascript->codeBlock(
'swfobject.embedSWF
("'.$swfLocation.'", "'.$divDomId.'", "'.$width.'", "'.$height.'", "'.$version.'",
"'.$install.'", '.$flashvars.', '.$params.', '.$attributes.');');
return $ret;
}
}
?>
Simply do what the error tells you: Check app/views/helpers/flash.php line 155 and see what it is outputting there and fix it. There must be some code that outputs something.
Could it be one of the return statements?
if (is_object($view)) {
$view->addScript($this->Javascript->link('swfobject'));
return true;
} else {
return $this->Javascript->link('swfobject');
}
$ret .= $this->Javascript->codeBlock(
'swfobject.embedSWF
("'.$swfLocation.'", "'.$divDomId.'", "'.$width.'", "'.$height.'", "'.$version.'",
"'.$install.'", '.$flashvars.', '.$params.', '.$attributes.');');
return $ret;
}
What other code is on the page calling flash?