1

This is related to here, but, as I don't currently have the reputation to comment there, I decided to ask my somewhat different question here.

I am writing a plugin to connect to a RESTful API (using Basic Authentication). I have been following the examples on the aforementioned link (above); however, the dot notation in calling the plugin is puzzling to me.

(note: prior to installing this custom plugin (which successfully installed), I installed the Guzzle plugin.)

When I leave the code as it appeared in the example ("_entry.html") at the link ('craft.theater.get'), I receive the error message here:

Fatal error: Class 'Craft\TheaterVariable' not found in craft\app\variables\CraftVariable.php on line 55

Is there a way to use 'craft.theater.get' successfully in the index.html template? Does 'theater' refer to the entire theater plugin, here?

Additionally, for looping through the XML, is there something in Craft CMS similar to the PHP SimpleXML Parser for looping through the XML nodes?

Thanks.

Here is the code (thanks to the link mentioned before):

Index.html (located in craft/templates/theater/ ):

{#
 # Theater index template
 # -------------------
 #
 # This template is loaded whenever http://example.com/news is
 # requested, because it is located at Theater/index.html in your
 # craft/templates/ folder.
 #
 # See this page for more details on how Craft routes requests:
 # http://craftcms.com/docs/routing
 #}

{% extends "_layout" %}
{% set title = "Theater" %}

{% block content %}
    <h1>Theater</h1>

{# begin - plugin test detection and confirmation #}
{% if craft.theater is defined %}
    Never fear... theater is here.
{% else %}
    I'm missing my theater.
{% endif %}

{% set plugin = craft.plugins.getPlugin('theater', false) %}

{{ plugin.isEnabled() ? 'plugin enabled' : 'plugin disabled'}}<br/>
{{ plugin.isInstalled() ? 'plugin installed' : 'plugin not installed'}}<br/>

{{ craft.theater is defined ? 'plugin true' : 'plugin false' }}
{# end - plugin test detection and confirmation #}


 {# below - I commented out the version with 'craft.theater.get'... when I replaced it with 'craft.guzzle.get' it worked, but unsure why #}
{# set showtimes  = craft.theater.get({ url: 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys' }) #}   
{% set showtimes  = craft.guzzle.get({ url: 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22nome%2C%20ak%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys' }) %}

 {# below - commented out original for statement 'showtimes.data' ... removed '.data' and it works #}
{# for show in showtimes.data #}
{% for show in showtimes %}

<h1>{{ show.created }}</h1>

{% endfor %}
{% endblock %}

The code for the plugin file: TheaterPlugin.php (located in craft/plugins/theater/ ):

<?php


namespace Craft;

class TheaterPlugin extends BasePlugin
{
    /**
     * @return mixed
     */
    public function init()
    {
        parent::init();
    }

    /**
     * @return mixed
     */
    public function getName()
    {
         return Craft::t('TheaterVariable');
    }

    /**
     * @return mixed
     */
    public function getDescription()
    {
        return Craft::t('TheaterVariable');
    }

    /**
     * @return string
     */
    public function getDocumentationUrl()
    {
        return '???';
    }

    /**
     * @return string
     */
    public function getReleaseFeedUrl()
    {
        return '???';
    }

    /**
     * @return string
     */
    public function getVersion()
    {
        return '1.0.0';
    }

    /**
     * @return string
     */
    public function getSchemaVersion()
    {
        return '1.0.0';
    }

    /**
     * @return string
     */
    public function getDeveloper()
    {
        return 'jw';
    }

    /**
     * @return bool
     */
    public function hasCpSection()
    {
        return false;
    }

    /**
     */
    public function onBeforeInstall()
    {
    }

    /**
     */
    public function onAfterInstall()
    {
    }

    /**
     */
    public function onBeforeUninstall()
    {
    }

    /**
     */
    public function onAfterUninstall()
    {
    }

    public function get($options){

        $url = $options['url'];
        $limit = array_key_exists('limit', $options) ? NumberHelper::makeNumeric($options['limit']) : null;
        $offset = array_key_exists('offset', $options) ? NumberHelper::makeNumeric($options['offset']) : 0;

        try {

            //API Credentials
            //$login = 'USERNAME';
            //$password = 'PASSWORD';


            $client = new \Guzzle\Http\Client();
            $request = $client->get($url);

            //cURL Options for Basic Authentication
            $request->getCurlOptions()->set(CURLOPT_RETURNTRANSFER, true);
            $request->getCurlOptions()->set(CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
            $request->getCurlOptions()->set(CURLOPT_USERPWD, "$login:$password");

            $response = $request->send();

            if (!$response->isSuccessful()) {
                return;
            }

            $items = $response->json();

            $items = array_slice($items, $offset, $limit);

            return $items;

        } catch (Exception $e) {

            return;

        }
    }



}
2

I'll try to explain you how this thing works.

1. The most important thing: Twig is a template language
Many people who are not used to PHP - or those who don't want to learn it/or coming from other CMS - like to abuse Twig and try to accomplish things that should not be accomplished.
Even if you can use it for some logic you should not try to force it to do such things. Sooner or later it is going to be messy and requires more resources.

Thus your templates should not contain too much business logic.

2. Therefore there are PluginVariables

To be able to access custom PHP Code Craft has the ability to offer you several methods to access your business logic from your template. One method is your PluginsVariable. You can insert a TheaterVariable.php in your /theater/variables/ folder that could look like this Doc

But - you should not implement too much logic in those either. Of course you can no one will ever say you must not do it, but the better solution is to create a Service. Because these files are the place where your logic belongs

3. Phew why should I even listen to that guy... it works the way I do it, so what?
Of course you can create your website like you want, but maybe you'll want to create another site in the future - maybe a bigger project that requires a better structure. Then you'll be happy to have a good boilerplate and knowledge. Since most people do it in the intended way you'll be able to understand other plugins much better and can change them too.

The reason why we separate our code in Variables, Controllers, Services and templates is the ability to change things more easily and to access everything from everywhere.

When you want to update an API you only have to change one single service so your controllers and your templates don't consume any time. You don't need to restructure your template when your REST Api changes, everyone will know for sure he/she has to go into the services folder and modificate a few lines there instead of the entire project here and there. So you'll save much time and don't have to search for too long.

You can access your service from within your template (via variable), from URL requests (via controllers), via Ajax request (via controller) -> you have one function that you use everywhere :D

Just imagine: in halve a year you would like to add certain content to your Rest responses. So you receive a response, title, description or whatever and you want to be able to update things here and there. That way you only have to create a new record/element type to insert the content from your API calls and pull those instead of the response directly. Think about the required time to do this with your current approach.

4. I know... I said many things until now but they don't really concern your problem

The Craft variable you can access from your template contains all needed services (craft.entries, craft.request....) and of course your pluginVariable so craft.theater does not access your plugin. It tries to call the file theather/variables/TheaterVariable and tries to call the get function there. Your TheaterPlugin file is only meant to be the container for some configurations (name, description, routings, cp hooks..) for your plugin. There is no real need to access it from twig when you leave your development environment.

So - I think I answered all your questions, but still if you did not get it I'll resume.

'craft.guzzle.get'

I assume this works because the guzzle plugin has a GuzzleVariable with the get function. So you access that one.

Additionally, for looping through the XML, is there something in Craft CMS similar to the PHP SimpleXML Parser for looping through the XML nodes?

Craft has actually to be really specific nothing to do with Twig. It only provides certain objects in it and even so, you should parse your response in your PHP logic and pass the objects to twig.

Fatal error: Class 'Craft\TheaterVariable' not found in craft\app\variables\CraftVariable.php on line 55

Appears because you probably don't have the file.... like the error says

Is there a way to use 'craft.theater.get' successfully in the index.html template?

namespace Craft;

class TheaterVariable
{
    public function get()
    {
        return craft()->yourCustomServiceName->get();
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.