I'm relatively new to Smarty and can't seem to figure this out.
In my php controller I instanciate a class "Product" as many times as I will need to display it. For instance if I have 5 different items on my page I will instanciate "Product" 5 times. I then create an array containing these. It goes something like this :
(my objects are filled with infos on the product).
Code:
$product_array = array (
0 => Object1,
1 => Object2); etc.
I then assign that array to a smarty variable {$product_array}.
Once in my .tpl I go through a loop of the displayed products. That's when I would need to assign $products_array[0] or {$products_array.0} to another variable $products that would display everything I need about the product. Then it will go through the loop again and show me {$products_array.1} and so on.
However this seems impossible seeing that any way I try and achieve this (and I even tried using {php} shame on me) I can't seem to figure it out.
I get this error : Object of class Product could not be converted to string.
Im pretty sure you cant mix in smarty stuff within a {php} tag. But the questions is why do this? Why not create all the products and put them in an array, and then assign that to smarty and loop over it in smarty syntax?
{php}
$accesories = $GLOBALS['accessories'];
$products = array();
foreach($accesories as $k => $v)
{
var_dump($instantProduct = new Product($accesories[$k], TRUE));
$products[$k] = new Product($accesories[$k], TRUE);
}
$smarty->assign('products', $products);
{/php}
// now loop and conditions in smarty
That said you really should just fix this now and move this logic into whatever youre using as a "controller". It may reveal more widespread problems with your design that you are going to have to solve one way or another.
Related
I have a Laravel app where I am using a bit of code which feels really unintuitive.
In the code I return a list of objects ($occupied) which all have the the column 'property'. I then go on to create an array of the list of objects 'property's ($occupiedproperty) just to use it in a whereNotIn call.
if ($occupied = Residency::currentResidents()){
// Here is the pointless part //////
$occupiedproperty = array();
foreach ($occupied as $occ) {
array_push($occupiedproperty, $occ->property);
}
///////////////////////////////////
return Property::whereNotIn('id', $occupiedproperty)->get();
}
This code works fine to do the job but creating a new array when I already have a list of objects seems lazy. I tried looking at eloquent's documentation but I couldn't figure this out.
I need to be able to access the 'property' column of $occupied so I can run something like whereNotIn('id', $occupied->property)
Thank you
Can't test it right now, but this should work (it should work even without casting to array the $occupied collection):
$occupiedProperties = array_pluck((array)$occupied, 'property');
It uses the array_pluck() helper method: http://laravel.com/docs/4.2/helpers#arrays
I am trying to get all stores on a Magento shop. By all stores, I mean all stores from all websites. I wrote this code and it works, but I'm a little concerned about the complexity of the nested foreach loop. Please take a look at it and advise me if you think I can do something different.
public function getAllStoresCustom(){
$all_stores = array();
foreach (Mage::app()->getWebsites() as $website) {
foreach ($website->getGroups() as $group) {
$all_stores [] = $group->getStores();
}
}
return $all_stores;
}
I've only found these functions in Magento, so I think I had to use those and this seemed the only combination that worked.
Thanks a lot
Try this:
$allStores = Mage::getModel('core/store')->getCollection();
Then loop through $allStores when needed
foreach ($allStores as $store) {
//do something with $store
}
Notice: You will get a store with id 0. That is the admin store view. If you want all stores without the admin store view use this:
$allStores = Mage::getModel('core/store')->getCollection()->setWithoutDefaultFilter()
foreach() is an incredibly efficient PHP function so you can bet that it is not going to be your slowdown. If you are looking to optimize something then look into the code for the getStores() and getGroups() functions because those are being called within the iterations whereas getWebsites() gets called only once.
If you want more guidance then please feel free to update your question with the contents of those functions.
You may also want to try https://codereview.stackexchange.com/ for more experienced opinions especially since you don't have any specific programming issue/error =)
I'm hoping someone can point me to the right direction in this.
Lets say I store Smarty template in database. It can look like this:
{currentusername UserID="5"}
The currentusername is a custom function to get the username. All displays correctly when used in a template. But what if I wanted to get the resolved currentusername function in my php code?
Basically I would get the template from the database, resolve it through smarty and then used the currentusername further in the code.
Is that possible?
Edit so it can be better understood. I have a this piece of code:
require('smarty/libs/Smarty.class.php');
$smarty = new Smarty;
$macro = '{currentusername UserID="5"}';
$resolvedmacro = ""; // this should contain the "Jerry";
function smarty_function_currentusername($params, &$smarty){
$UserID = $params["UserID"];
if ($UserID == 5){
return "Jerry";
}
else{
return "I dont know this guy";
}
}
Can I somehow resolve the $macro through smarty so the variable $resolvedmacro would contain the correct value?
Smarty can render a string as though it was a template using the string: or eval: "resource types" - see the documentation on String Template Resources for details.
You can then use $smarty->fetch() to get the output of that "template" into a normal PHP variable:
require('smarty/libs/Smarty.class.php');
$smarty = new Smarty;
$macro = '{currentusername UserID="5"}';
$resolvedmacro = $smarty->fetch('string:' . $macro);
There is a wider question of why you want to do this, and whether Smarty is the right tool for the job - for instance, if there are a limited number of callbacks possible, it might be over-complicating things to use Smarty to resolve them rather than just storing the name of the callback and its arguments and running it through a switch statement.
Note: The string: and eval: resource types were added in Smarty 3; if for some reason you need to use Smarty 2, you will need to write or find a resource plugin to do the same job. You could also write a resource plugin for either version which fetched a particular macro from the database and rendered it in one step; the docs for Smarty 3 are here.
Ok, the subject makes no sense so Ill try to better describe it here.
Zend Frame work in use here. And I have run into a problem passing variables to my views, well the views included into the "top.phtml" that make up the template. What I am trying to do is implement a breadcrumb concept. The bread crumb file is included into the top.phtml before the content view file. So the breadcrumb variable isn't defined as far as the breadcrumb file is concerned.
I can print_r my array of settings for the breadcrumbs within the controllers view, no problem so it is working I know that much, just anything above that view in particular in the order of things can't get the variable. So I guess what I am looking to have answered is is there a means off passing a variable to the overall scheme of things similar in concept to
$this->view->variable_name = blah;
where something as high as the top.phtml can pick it up for use?
You may be looking for Placeholders.
Example:
Setting a placeholder value from a controller:
$this->view->placeholder('some_placeholder_name')->set('blah');
Setting a placeholder value from a view
$this->placeholder('some_placeholder_name')->set('blah');
Retrieving the placeholder value in a view script or layout:
$value = $this->placeholder('some_placeholder_name');
Placeholder content is rendered towards the end of your application execution so the value set in your controller should be available in your top level top.phtml view script.
I think this will work:
$this->layout()->breadcrumbs = ...
And then print $this->layout()->breadcrumbs in your top.phtml.
Zend Layout
After sending hours trying to get placeholder() to work with partialLoop(), I finally gave up and hacked a fix to pass vars to a partial:
$vars = (array) $this->getVars();
foreach ($this->rows as $row) {
$partialVars = array(
'row' => $row,
'vars' => $vars,
);
echo $this->partial('row.phtml', $partialVars);
}
ugly, but it worked.
+1 for everyone for giving me a clue, however none of the above worked well in my favor. However between them all, they lead me towards finding my answer which is
Zend_Registry
In my Controller I built my array and passed it to Zend_Registry like
$breadArray = array(
array("icon"=>"i_robot", "href"=>"systems/"),
array("href"=>"metrics","text"=>"Metrics")
);
Zend_Registry::set('breaded_crumbs', $breadArray);
Then in my breadcrumb.phtml which is loaded before the content and view I used
print_r(Zend_Registry::get('breaded_crumbs'));
to see if it was working, and it gave me the array's so I for anyone in the future looking to extend a variable outside of the view itself, the registry seems to be the way to go. I tried placeholder and layout, both gave me errors about not being something or another, and when I got them to work in part I wasn't getting what I was expecting.
I'm using this code in a views field template (in this case views-view-field--all-members--uid.tpl.php):
<?php
$users_friends = flag_friend_get_friends($user->uid);
$users_friends_ids = array();
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
?>
It basically gets the user ids of friends and puts them in an array so I can check if the field matches any of the user ids.
So my problem is that I don't want to have this within this template (for a few reasons), but if I don't I can't access the array. How can I make this array globally accessible?
Without knowing your "few reasons", I can't say if this is the answer for sure. My own reasons would probably be that I don't want the same code executing a bunch of times, and I'd rather not have the same exact code in multiple places.
I would then create a function with a static variable to hold the friends array.
function mymodule_get_friends_ids() {
// pull in the current global user variable
global $user;
// call up the static variable
static $users_friends_ids;
// return if this static var has already been set
if (is_array($users_friends_ids)) {
return $users_friends_ids;
}
// if we hit here, then this function has not been
// run yet for this page load.
// init array
$users_friends_ids = array();
// if user is anon, no need to go on
if (user_is_anonymous()) {
return $users_friends_ids;
}
// get friends array
$users_friends = flag_friend_get_friends($user->uid);
// build ids array
foreach ($users_friends as $id => $value) {
$users_friends_ids[] = $id;
}
return $users_friends_ids;
}
Now in your templates, you can call mymodule_get_friends_ids() in as many places as you want, and the working code below the first return will only get executed the first time it is called.
Coder1's advice is very good - it keeps you from populating your global variable namespace with a lot of junk. It's probably the most "elegant." It might not be the easiest to use if you are rather new to PHP (which I'm guessing might be the case if it's hard to get your head around returning arrays, but that's ok).
However, if this is really a priority, you probably don't care about having one extra global variable.
I suppose I may be stating the obvious here - but you can, at pretty much any point in execution (provided the information you need has already been generated - e.g., the $user variable has been populated), do this:
$GLOBALS['users_friends_ids'] = /* your code goes here */
Then in your template, you access this by ...
$friendsArray = $GLOBALS['users_friends_ids'];
Or you can simply use the construct
global $user_friends_ids;
when you want to initialize the variable, or access it inside a function or class (which is the case for your template files - they are called inside functions, so you need to globalize or use the $GLOBALS array, which is "automagically" all of the variables active in the global namespace).
The most "logical" place to do this would be inside a module using one of the many hooks available, to execute this code only once. hook_init() might do it for you, if the user object is already loaded at this point (not sure, you'll have to test). But you might not want to figure out making Drupal modules (it's not that difficult).
If you are doing this inside a template (and though it's not good practice, many Drupal site owners with a beginning knowledge of PHP put everything in templates), you'll want to know which template code is being executed when. Node template code tends to be executed before page template code - which is logical, since otherwise the variables for node content in the page template wouldn't be populated.
If you have listings of nodes, they'll be calling this code multiple times, so you'll end up doing something similar to what Coder1 is describing. If you don't want to create your own small module, you could put the function declaration he's written in your theme's template.php file, since it's called only once. You don't want to put function declarations in the tpl.php files, since they are sometimes called more than once (and you aren't allowed to declare functions more than once).
If you have a hard time understanding the function and the return, you can always do something like this in your code (which is very, very inelegant - but it's better to have inelegant code that you do understand, than elegant code that's you don't).
if(!isset($GLOBALS['users_friends_ids'])) {
$GLOBALS['users_friends_ids'] = /* your code here */
}