1. If you update to Joomla 3.8.10, please make sure that you either do a full GitHub update of Fabrik, or disable caching for your lists (in the Advanced settings) or turn off Joomla's System Cache setting. A change in Joomla's cache code in 3.8.10 required a fix in Fabrik, which will be rolled in to the next release, but is currently only available in GitHub.
    Dismiss Notice
  2. We will be performing an update of XenForo (the forum software use on this site) this afternoon, Fri 8/17/2018. The forums will be unavailable for a (hopefully!) short time.
    Dismiss Notice

Declaring variables once

Discussion in 'Professional Support' started by ahmedo, Feb 13, 2018.

  1. ahmedo

    ahmedo Member

    Level: Community
    Hi,

    Is there a way to declare variables once upon loading a Form so that can be reused across different Calc fields?

    Basically, I have four calculated fields which display our cost for a product in 4 different currency. At the moment, I go to each Calc field and declare the exchange rate in each one of them. And it works. But if the exchange rate changes, I will have to go to each Calc field and change the rate. Which is not really a good approach.

    Thank you.
     
  2. cheesegrits

    cheesegrits Support Gopher Staff Member

    Level: Professional
    What I usually do is create a class somewhere, like in the PHP form plugin script folder, as a "Helper" class, and put common things I'm doing in there, then use it from wherever I need it (calcs, form submission scripts, etc), like ...

    Code (Text):

    class MyHelper
    {
       public static function getExchangeRate($currency = "USD")
       {
          // whatever code you want here that returns a value.  If you want it could even call an online API to get spot rates
          switch ($currency):
             case "UKP":
                return "0.000001";
                break;
             case "USD":
             case default:
                return "1.34";
       }
    }
     
    Then in your calc ...

    Code (Text):

    require_once JPATH_ROOT . '/plugins/com_fabrik/php/scripts/myhelper.php';
    $rxRate = MyHelper::getExchangeRate('YEN');
     
    Then as you find other stuff you find yourself doing repeatedly, you can put that in your helper class as well.

    I'm thinking for 3.9 of adding namespace support for a custom helper class into our autoloading, so if you add Custom.php to our ./libraries/fabrik/fabrik/helpers folder, you could then just automagically call Fabrik\Helpers\Custom::whatever(). But that doesn't exist yet.

    -- hugh
     
    ahmedo likes this.
  3. cheesegrits

    cheesegrits Support Gopher Staff Member

    Level: Professional
    Another thing I've been thinking about, as exchange rates are something we've had a lot of questions about over the years, is adding this Composer lib to our libraries:

    https://github.com/florianv/swap

    ... which lets you very easily get up to date exchange rates from Fixer or Google, with code like ...

    Code (Text):

    use Swap\Builder;
    $swap = (new Builder())->add('fixer')->build();
    $rate = $swap->latest('EUR/USD');
     
    -- hugh
     
  4. ahmedo

    ahmedo Member

    Level: Community
    Thank you for your help. Sadly I could not do it successfully.
    Firstly, the path you gave I cannot find (/plugins/com_fabrik/php/scripts/) so I assumed it is this one (/plugins/fabrik_form/php/scripts/). If so, this is where I placed the myhelp.php

    Next, when I try to view the List data (not even the form), I get this message on my browser instead without the "
    "class MyHelper { public static function getExchangeRate($currency = "USD") { switch ($currency): case "UKP": return "0.000001"; break; case "USD": case default: return "1.34"; } }"

    So I know the script is being called, but when nothing else is shown, I know I made a big blunder somewhere.

    My Calc field has this
    require_once JPATH_ROOT . '/plugins/fabrik_form/php/scripts/myhelper.php';
    $rxRate = MyHelper::getExchangeRate('UKP');

    BTW, the test is done on Fabrik Playground
    Thanks anyway.
     
  5. cheesegrits

    cheesegrits Support Gopher Staff Member

    Level: Professional
    Oops, put a php tag at the start of the file...

    Code (Text):

    <?php
     
    And in the calc, return a value. That was just an example fragment, I presume you'll multiply some other element's value by the exchange rate.

    And the function itself is just example code, I don't know if you are dealing with multiple currencies. You could just have one line that returns a single value.

    Sent from my HTC6545LVW using Tapatalk
     
  6. ahmedo

    ahmedo Member

    Level: Community
    Getting closer to getting right. Just one more question and I will post the whole thing. (had to go to w3school to know more about php) :)
    I have an element called currency (dropbox type) -storing the Value
    Value 1 Label USD
    Value 2 Label SGD

    I can get the value of the currency by using this {products___currency_raw)
    I want to know how do I get the label value (example USD). I could throw few If statements, but I am thinking there must a better way. I tried {products_currency_label} but it did not work.
     
  7. cheesegrits

    cheesegrits Support Gopher Staff Member

    Level: Professional
    You can't really rely on being able to get at the labels for dropdowns or joins. Long story.

    I would suggest rather than a dropdown, use a join element. Create a list for currencies, and put your exchange rate in that (relative to the base currency), so something like ...

    id, code, rate
    1, USD, 1
    2, UKP, 1.23
    3, SGD, 0.76

    ... etc. Obviously my example assumes USD is the base currency.

    Then just pass the 'raw' currency id to your function, and do a database lookup in that ...

    Code (Text):

    function getExchangeRate ($currencyId)
    {
       $db = JFactory::getDbo();
       $query = $db->getQuery(true);
       $query->select('rate')->from('currencies')->where('id = ' . (int)$currencyId);
       $db->setQuery($query);
       return $db->loadResult();
    }
     
    The advantage of doing it this way is, when the exchange rates change, you only have to update the values in the list (which you can do through a simple Fabrik list/form), rather than modifying code.

    You could also very easily add a scheduled task PHP plugin to update your currency table once a day (or whatever) from some trusted API source.

    This assumes you are working on costs from a base currency, so are always converting from that to some other currency. If you need to convert between arbitrary currencies, that could still be done with a table based approach, although the table would then need to have more fields (id, from_code, to_code, rate), and a lot more rows (one, or perhaps two, for each currency pairing).

    You might also want to improve that getExchangeRate() function to cache the result, to cut down on database queries. Or rather, I might want to, if you want to go this route.

    -- hugh
     
  8. cheesegrits

    cheesegrits Support Gopher Staff Member

    Level: Professional
    Meh, apparently I'm a little OCD ... here's the function, with caching. So it only does the database lookup once, and loads the whole table one time, and if called again will use the cached value.

    Code (Text):

    function getExchangeRate ($currencyId)
    {
       static $currencies = null;

       if (!is_array($currencies))
       {
          $db = JFactory::getDbo();
          $query = $db->getQuery(true);
          $query->select('*')->from('currencies');
          $db->setQuery($query);
          $currencies = $db->loadObjectList('id');
       }

       return $currencies[$currencyId]->rate;
    }
     
    The reason it's best to cache database qeuries when doing stuff from calc elements is that the calc code can wind up being run multiple times. Especially if you have "Calc on save only" set to No, so it's calc'ing every element in a list view.

    -- hugh
     
  9. ahmedo

    ahmedo Member

    Level: Community
    From the start, I thought of putting the currency in a different list. But I was so scared of being unable to do what you wrote. It is a huge learning curve for me to code in a language that I never coded one line before. I know exactly what I want to do, and the options available. But it is the ability to code that fails me. So I am taking it a step at a time, considering my other responsibilities including running my own business.

    I just managed to achieve what I want with you recommend before with the myhelp.ph. Along the way, I learnt few things. I can now talk to my PHP developers and ask them to do more.

    Thank you once again.
     

Share This Page