XF 2.2 PHP Callback Widget

Lee

Well-known member
Looking for some hand holding as it may be.

I want to create a widget with a PHP callback to run a query to select all the children of node "x".

Can someone help point me in the right direction?

Where do I create the file for callback? What is the appropriate way to run the query and display the results in the widget?

Thank you.
 

Lee

Well-known member
Not to worry, I have resolve this.

I maybe haven't implemented building the link to the node in the most graceful way, but it works for my application.

In my case, each node has a custom url portion so I have referenced the column node_name in my url and built the link that way.

Permissions are also not an issue as each node is visable to everybody.

For future reference, what would be the correct way to build the url and perform a permission check?
 

Lee

Well-known member
My PHP:

Code:
<?php

namespace HMH;

class GetCats
{
    public static function fetchcats(\XF\Pub\Controller\AbstractController $controller, \XF\Mvc\Reply\AbstractReply &$reply)
    {
        $db = \XF::db();

        $results = $db->fetchAll('
                SELECT *
                FROM `xf_node`
                WHERE parent_node_id = 55
                ORDER BY title ASC
        ');

$reply->setParam('results', $results);

    }
}

Then the pagenode:

Code:
    <xf:foreach loop="$results" value="$result">
           <a href="https://www.helpmindsheal.com/forums/{$result.node_name}">{$result.title|raw}</a><br />
    </xf:foreach>
 

Lawrence

Well-known member
If you use the finder, then most of what you need done will be done for you (permission checks, fetching child nodes, etc).

In your widget, something like this:

PHP:
$node = $this->em()->find('XF:Node', 55);
$results = $this->repository('XF:Node')->getFullNodeList($node)->filterViewable()->toArray();

Notice the filterViewable(), that removes nodes members do not have the permission to view.
 
Last edited:

Lee

Well-known member
If you use the finder, then most of what you need done will be done for you (permission checks, fetching child nodes, etc).

In your widget, something like this:

PHP:
$node = $this->em()->find('XF:Node', 55);
$results = $this->repository('XF:Node')->getFullNodeList($node)->filterViewable()->toArray();

Notice the filterViewable(), that removes nodes members do not have the permission to view.

Hi Lawrence, I have done something wrong I think - I get this error:

Error: Using $this when not in object context in src/addons/HMH/GetCats.php at line 9
  1. HMH\GetCats::fetchcats()
  2. call_user_func_array() in src/XF/Pub/Controller/Page.php at line 58
  3. XF\Pub\Controller\Page->actionIndex() in src/XF/Mvc/Dispatcher.php at line 350
  4. XF\Mvc\Dispatcher->dispatchClass() in src/XF/Mvc/Dispatcher.php at line 261
  5. XF\Mvc\Dispatcher->dispatchFromMatch() in src/XF/Mvc/Dispatcher.php at line 113
  6. XF\Mvc\Dispatcher->dispatchLoop() in src/XF/Mvc/Dispatcher.php at line 55
  7. XF\Mvc\Dispatcher->run() in src/XF/App.php at line 2300
  8. XF\App->run() in src/XF.php at line 464
  9. XF::runApp() in index.php at line 20

Code:
<?php

namespace HMH;

class GetCats
{
public function fetchcats()
{
$node = $this->em()->find('XF:Node', 55);
$results = $this->repository('XF:Node')->getFullNodeList($node)->filterViewable()->toArray();
}
}
 

Lawrence

Well-known member
As you are making a widget, then you need to extend the AbstractWidget.
PHP:
<?php

namespace HMH\Widget; // the file path in the addons folder to your widget

use XF\Widget\AbstractWidget;

class GetCats extends AbstractWidget
{
    protected $defaultOptions = [];
    
    public function render()
    {
        // here is where your code goes to fetch a node and their children

        $node = $this->em()->find('XF:Node', 55);
        $results = $this->repository('XF:Node')->getFullNodeList($node)->filterViewable()->toArray();

        $viewParams = [
            'results' => $results
        ];
        return $this->renderer('name_of_your_widget_template', $viewParams);
    }
    
    public function verifyOptions(\XF\Http\Request $request, array &$options, &$error = null)
    {
        // if your widgets have options you would verify them here
        return true;
    }
}
 

Lee

Well-known member
As you are making a widget, then you need to extend the AbstractWidget.
PHP:
<?php

namespace HMH\Widget; // the file path in the addons folder to your widget

use XF\Widget\AbstractWidget;

class GetCats extends AbstractWidget
{
    protected $defaultOptions = [];
   
    public function render()
    {
        // here is where your code goes to fetch a node and their children

        $node = $this->em()->find('XF:Node', 55);
        $results = $this->repository('XF:Node')->getFullNodeList($node)->filterViewable()->toArray();

        $viewParams = [
            'results' => $results
        ];
        return $this->renderer('name_of_your_widget_template', $viewParams);
    }
   
    public function verifyOptions(\XF\Http\Request $request, array &$options, &$error = null)
    {
        // if your widgets have options you would verify them here
        return true;
    }
}

Thank you! I now have this in my file:

Code:
<?php

namespace HMH\Widget; // the file path in the addons folder to your widget

use XF\Widget\AbstractWidget;

class GetCats extends AbstractWidget
{
    protected $defaultOptions = [];
    
    public function render()
    {
        // here is where your code goes to fetch a node and their children

        $node = $this->em()->find('XF:Node', 55);
        $results = $this->repository('XF:Node')->getFullNodeList($node)->filterViewable()->toArray();

        $viewParams = [
            'results' => $results
        ];
        return $this->renderer('hmh_ams_cats', $viewParams);
    }
    
    public function verifyOptions(\XF\Http\Request $request, array &$options, &$error = null)
    {
        // if your widgets have options you would verify them here
        return true;
    }
}

When trying to create the PHP Callback Widget, it wont save. No error message, just nothing happpens at all pressing save.
 

Lawrence

Well-known member
I was just trying to use the premade widget "PHP Callback Widget". Is that not appropriate?

It's appropriate, I read the whole thread wrong, so my apologies. On the bright side, you now have a widget created and there is only a few steps left. If you still want to use the callback widget, let me know, and I'll take a look, as I haven't used that widget before.
 

Lee

Well-known member
It's appropriate, I read the whole thread wrong, so my apologies. On the bright side, you now have a widget created and there is only a few steps left. If you still want to use the callback widget, let me know, and I'll take a look, as I haven't used that widget before.
Thanks for your help Lawrence, I'll try creating a widget definition and see if I can figure out the rest.
 

Lawrence

Well-known member
Using the callback widget, finally, :)

The test widget I placed here: \src\addons. The only difference compared to the above is the data you need is retrieved through the $widget object:

PHP:
<?php

class TestWidget
{
    public static function getCat(\XF\Widget\AbstractWidget $widget)
    {
        $node = $widget->app()->find('XF:Node', 10);
        $results = $widget->app()->repository('XF:Node')->getFullNodeList($node)->filterViewable()->toArray();

        $viewParams = [
            'node' => $node,
            'results' => $results
        ];   
        return $widget->renderer('category_test_widget', $viewParams);
    }
}

Then template category_test_widget just contains {{ dump($node) }} {{ dump($results) }} for testing and the result screen shot:
 

Attachments

  • test_result.png
    test_result.png
    51.8 KB · Views: 15
Top