Using cells and retrieving data

Hello,

I’m trying to create a plugin called ‘Partners’ the idea is I have several type of Partners and depending on the type of Partner they are I wish to display certain information based on Partner Type on the following url: sitename/partners/view/partner-name (Guest View)
following url: sitename/partners/dashboard/partner-name (Partner Logged in)

I’ve manage to create the following structure using cake bake

  • plugins>Partners
  • plugins>Partners>src>Model
  • plugins>Partners>src>View
  • plugins>Partners>src>Controller
  • plugins>Partners>src>View>Cell
  • plugins>Partners>src>View>Cell>GuestViewCell.php
  • plugins>Partners>src>View>Cell>DashboardCell.php
  • plugins>Partners>templates>cell>GuestView
    - plugins>Partners>templates>cell>GuestView>
    PHP files for each cell on the view page for sitename/partners/view/partner-name
  • plugins>Partners>templates>cell>Dashboard
    - plugins>Partners>templates>cell>Dashboard>
    PHP files for all the dashboard cells on the dashboard/index

I currently have all the data displaying as it should on templates>Partners>view.php
all the code is on this page and what to split it out to the cells so easier to mange I can load the plugin cell using the following code

<?= $cell = $this->cell('Partners.Guestview::header'); ?>

but can only seem to load static text

header loaded

I have tried moving the following code from templates>Partners>view.php to templates>cell>GuestView>header.php

<div class="container-fluid partnerView" style="background: url('/img/<?= h($partner->background) ?>') no-repeat;
    background-size: 100%;">
    <div class="row" >
    <div class="col-lg-1 justify-text-center"></div>
    <div class="col-lg-3 justify-text-center parterHead"><h1><?= h($partner->partner_name) ?></h1>
    <?= $this->Html->image(h($partner->logo), array('class' => 'img-fluid rounded', 'alt' => h($partner->partner_name) ));?>
    </div>
    <div class="col-lg-8"></div>
    </div>
    <div class="row" >
    <div class="col-lg-4"></div>
    <div class="col-lg-8"><i class="fas fa-map-marker-alt"></i> <?= h($partner->address) ?> <?= h($partner->street) ?> <?= h($partner->city) ?> <?= h($partner->region) ?> <?= h($partner->country) ?> <?= h($partner->postcode) ?> <i class="fas fa-phone"></i> <?= h($partner->contact_number) ?></div>
</div>
</div>

Then go to the browser it isn’t displaying the the cell but is showing the the following type of error’s in the source code where the cell should appear:
[ Notice (8)](javascript:void(0);): Undefined variable: partner [ ROOT\plugins\Partners\templates\cell\GuestView\header.php , line 6 ]

I have tried adding the code from public function view() in scr>Controller>PartnersController.php
to public function header() in scr>View>GuestViewCell.php

with the following code:

public function header($slug = null)
    {
        $this->loadModel('Partners');
        $partner = $this->Partners->findBySlug($slug)
         ->where(['Partners.status' => '1'])
         ->firstOrFail();
        $this->set('partners', $partners);
    }

but then get the follow error:

Warning (512): Could not render cell - Expression is missing operator (IS, IS NOT) with null value. [C:\apps\vanilla\vendor\cakephp\cakephp\src\Database\Expression\QueryExpression.php, line 782] [CORE\src\View\Cell.php, line 271]
Code Context
                $e->getLine()
            ), E_USER_WARNING);
$e = object(InvalidArgumentException) {
[protected] message => ‘Expression is missing operator (IS, IS NOT) with null value.’
[protected] code => (int) 0
[protected] file => ‘C:\apps\vanilla\vendor\cakephp\cakephp\src\Database\Expression\QueryExpression.php’
[protected] line => (int) 782
}
Cake\View\Cell::__toString() - CORE\src\View\Cell.php, line 271
include - ROOT\plugins\Partners\templates\Partners\view.php, line 7
Cake\View\View::_evaluate() - CORE\src\View\View.php, line 1164
Cake\View\View::_render() - CORE\src\View\View.php, line 1125
Cake\View\View::render() - CORE\src\View\View.php, line 751
Cake\Controller\Controller::render() - CORE\src\Controller\Controller.php, line 691
Cake\Controller\Controller::invokeAction() - CORE\src\Controller\Controller.php, line 533
Cake\Controller\ControllerFactory::invoke() - CORE\src\Controller\ControllerFactory.php, line 79
Cake\Http\BaseApplication::handle() - CORE\src\Http\BaseApplication.php, line 229
Cake\Http\Runner::handle() - CORE\src\Http\Runner.php, line 77
Authentication\Middleware\AuthenticationMiddleware::process() - ROOT\vendor\cakephp\authentication\src\Middleware\AuthenticationMiddleware.php, line 122
Cake\Http\Runner::handle() - CORE\src\Http\Runner.php, line 73
Cake\Routing\Middleware\RoutingMiddleware::process() - CORE\src\Routing\Middleware\RoutingMiddleware.php, line 156
Cake\Http\Runner::handle() - CORE\src\Http\Runner.php, line 73
Cake\Routing\Middleware\AssetMiddleware::process() - CORE\src\Routing\Middleware\AssetMiddleware.php, line 68

What is the correct way to get the cell to display correctly without erroring so I can then do the same for around 20 functions

Thanks in advance

Mal

1 Like

The approach is correct. One issue seems to be that there’s something wrong with the query (probably in the slug finder). Also the variable name should be $partners.

1 Like

you are not passing slug to your cell render code
https://book.cakephp.org/3/en/views/cells.html#passing-arguments-to-a-cell
and its header($slug = null) so the findBySlug($slug) tries to generate query that it cant handle
you can

  1. pass argument to render call
  2. change query to handle null
1 Like

Directory structure also seems weird. plugins>Partners>templates>cell>GuestView should be plugins>Partners>src>Template>Cell>GuestView?

Hi Sorry that was a Typo the structure is right, I was using copy & paste when typing out the structure :wink:

Hi I’m trying to develop it in CakePHP 4

I copied the code from plugins>Partners>src>Controllers>PartnersController.php from the view function

public function view($slug = null)

    {

       $partner = $this->Partners->findBySlug($slug)

    ->contain(['PartnerTypes', 'SubscriptionTypes', 'PartnerFacilities', 'PartnerPegs', 'PartnerWatersSpecies', 'PartnersWaters', 'PartnerTicketTypes', 'PartnerGalleries'])

    ->firstOrFail();

    $this->viewBuilder()->setLayout('partnersguest');

        $this->set('partner', $partner); 

    }

src>View>GuestViewController.php header function

public function header($slug = null)

    {

       $partner = $this->Partners->findBySlug($slug)

    ->firstOrFail();

        $this->set('partner', $partner); 

    }

The first code works correctly and pulls the content to the view page correctly if I leave it in , if I copy the above code to the plugins>Parnters>src>View>GuestController.php

then if I remove the following code from plugins>Partners>templates>Partners>view.php and place it in plugins>Partners>templates>cell>GuestView>header.php

<div class="container-fluid partnerView" style="background: url('/img/<?= h($partner->background) ?>') no-repeat; background-size: 100%;">
    <div class="row" >
    <div class="col-lg-1 justify-text-center"></div>
    <div class="col-lg-3 justify-text-center parterHead"><h1><?= h($partner->partner_name) ?></h1>
    <?= $this->Html->image(h($partner->logo), array('class' => 'img-fluid rounded', 'alt' => h($partner->partner_name) ));?>
    </div>
    <div class="col-lg-8"></div>
    </div>
    <div class="row" >
    <div class="col-lg-4"></div>
    <div class="col-lg-8"><i class="fas fa-map-marker-alt"></i> <?= h($partner->address) ?> <?= h($partner->street) ?> <?= h($partner->city) ?> <?= h($partner->region) ?> <?= h($partner->country) ?> <?= h($partner->postcode) ?> <i class="fas fa-phone"></i> <?= h($partner->contact_number) ?></div>
</div>
</div>

and use the following route in plugin>Partners>src>Plugin.php

$builder->connect('/view/**', ['plugin' => 'Partners', 'controller' => 'Partners', 'action' => 'view']);

I get an error.

What is the correct way of doing it, I have read the documents from start to finish on routings & cells and tried every variation mentioned each one triggers an error where the cell content should display and can’t for the life of me work out how to get it working the rest of the page displays correctly.

on another note before I decided to create the Partner Plugin split the view.php out and create logical files, I used to be able to view the page in the browser at vanilla/partners/slug-name I have now had to revert back to vanilla/partners/view/slug-name

I have gone through my old code to see what I did where and what I have actually done different and the only difference from setting it up is the route I used to pass from vanilla>config>routes.php

Any help appreciated

Thanks Mal

your code is ok you just need to pass your slug from controller to cell

in controller
{
...
$this->set('slug', $slug);
}

in view
...
<?= $cell = $this->cell('Partners.Guestview::header', [$slug]); ?>
...

How do I set this out in src>View>GuestViewController.php ??

public function header($slug = null)

    {

       $partner = $this->Partners->findBySlug($slug) //line 40

    ->firstOrFail();

        $this->set('partner', $partner); 

        $this->set('slug', $slug);

    }

As I now have the error of

# Could not render cell - Call to a member function findBySlug() on null [C:\apps\thefishingnetwork\plugins\Partners\src\View\Cell\GuestViewCell.php, line 40]📋

Thanks in advance

Mal

Why have you got something named as a Controller in your View folder? Does anything in whatever that is ever load the Partners model? Seems that ($this->Partners) is the thing that’s null.

Hi either I have misread something and done something very wrong?

my understanding is when using a Cell, when making a plugin the controller for the Cell is stored in

AppName>PluginName>src>View>Cell>CellControllerName.php in my case GuestViewController.php
and the associated display file would be as follows:
AppName>PluginName>templates>cell>CellName>display.php or in my case header.php

which would be the same as using a Cell in the main CakePHP application structure of:

AppName>src>View>Cell>CellControllerName.php
and the associated display file would be as follows:
AppName>templates>cell>CellName>display.php

I currently have the following structure for the Partner Index & View in the plugin
AppName>PluginName>src>Controller>Partners.php -this controller has the following 2 public functions index (lists ALL partners) and view which has the following code:

public function view($slug = null)
    {
       $partner = $this->Partners->findBySlug($slug)
    ->contain(['PartnerTypes', 'SubscriptionTypes', 'PartnerFacilities', 'PartnerPegs', 'PartnerWatersSpecies', 'PartnersWaters', 'PartnerTicketTypes', 'PartnerGalleries'])
    ->firstOrFail();
    $this->viewBuilder()->setLayout('partnersguest');
        $this->set('partner', $partner); 
    }

AppName>templates>Partners>index.php -lists all partners
AppName>templates>Partners>view.php -view the individual partner details from the partners table and related table.

Currently ALL the display data is in AppName>templates>Partners>view.php which is around 500 lines of code with various foreach for each section of the page, all I want to do is split this in to an individual cell view for each section making it in my head more logical and easier to maintain, so it will be as following rather that using public function view() as the above code for everything, it will be called from
AppName>PluginName>src>View>Cell>GuestView.php

public function header() {
 //related partner name, logo, background image (Partners table)
}
public function description() {
 //related partner description (Partners Table)
}
public function tickets() {
 //related partner ticket info (related Tickets table using partner_id FK)
}

// other functions for the rest of the relevant parts making the view.php file

Then in
AppName>PluginName>templates>cell>GuestView>header.php

<div class="container-fluid partnerView" style="background: url('/img/<?= h($partner->background) ?>') no-repeat;background-size: 100%;">
    <div class="row" >
    <div class="col-lg-1 justify-text-center"></div>
    <div class="col-lg-3 justify-text-center parterHead"><h1><?= h($partner->partner_name) ?></h1>
    <?= $this->Html->image(h($partner->logo), array('class' => 'img-fluid rounded', 'alt' => h($partner->partner_name) ));?>
    </div>
    <div class="col-lg-8"></div>
    </div>
    <div class="row" >
    <div class="col-lg-4"></div>
    <div class="col-lg-8"><i class="fas fa-map-marker-alt"></i> <?= h($partner->address) ?> <?= h($partner->street) ?> <?= h($partner->city) ?> <?= h($partner->region) ?> <?= h($partner->country) ?> <?= h($partner->postcode) ?> <i class="fas fa-phone"></i> <?= h($partner->contact_number) ?></div>
</div>
</div>

AppName>PluginName>templates>cell>GuestView>description.php

AppName>PluginName>templates>cell>GuestView>tickets.php
and so on…

I have the following routes set up in App>PluginName>src>Plugin.php

public function routes(RouteBuilder $routes): void

    {

        $routes->plugin(

            'Partners',

            ['path' => '/partners'],

            function (RouteBuilder $builder) {

                #Guest Views

                $builder->connect('/', ['controller' => 'Partners']);

                $builder->connect('/view/**', ['plugin' => 'Partners', 'controller' => 'Partners', 'action' => 'view']);

               $builder->fallbacks();
            }
        );
        parent::routes($routes);
    }

how hard can this be to get the cell to display without errors??

Thanks in advance

Mal

You should have AppName/plugins/PluginName/src/View/Cell/GuestViewCell.php and AppName/plugins/PluginName/src/Template/Cell/GuestView/header.php. Your directory structure, naming scheme, capitalization and pluralization are all off. Despite you reassuring us that such errors in the initial post were due to copy and paste issues, you repeat the same errors in the latest version. Either there’s a serious lack of attention to detail in writing your responses (a problem because the details are everything here), or you’ve somehow got pretty much everything in the wrong place.

Hi @Zuluru
Sometimes I get a bit muddled up trying to work off one screen and going back and forth from my source code to this window to type…

As per documentation for cakephp 4x the plugin folder should be as follows?
I assume from the documentation and the code baked /src/plugins represents /app-name/plugins otherwise the documentation is wrong or /bin/cake is creating the wrong structure when baking a plugin but in my mind as from my understanding a plugin is a self contained application which you can plugin to other CakePHP applications, so would follow the same structure as the main application??

/src 
/plugins
    /PluginName
        /config
        /src
            /Plugin.php
            /Controller
                /Component
            /Model
                /Table
                /Entity
                /Behavior
            /View
                /Helper
        /templates
            /layout
        /tests
            /TestCase
            /Fixture
        /webroot

so in your reply this is technically wrong or is the documentation wrong?

To get the details correct despite previously mentioning copy & paste I have the folder structure as follows from the outset of baking the plugin in the plugins folder, which to me is correct as per documentation all code so far has been generated in terminal /bin/cake bake except the slug part and routes as I copied the code I previously had in the original structure

/app-name
    /plugins
        /Partners
            /config
            /src
                /Plugin.php
                /Controller
                    /AppController.php
                    /PartnerController.php
                /Model
                    /Behavior
                    /Entity
                        /Partner.php
                    /Table
                        /PartnersTable.php
                /View
                    /Cell
                        /GuesViewCell.php
                    /Helper
            /templates
                /cell
                    /GuestView
                        /header.php
                /layout
            /tests
                /TestCase
                /Fixture
            /webroot

When copying the code from public function view() { ....} set out in this file

/app-name
    /plugins
        /Partners
            /config
            /src
                /Controller
                    /PartnerController.php

And placing it in the following file:

/app-name
    /plugins
        /Partners
            /src
                /Controller
                    /View
                        /Cell
                         /GuesViewCell.php

public function header() { .... }

then copying the section of code from

/app-name
    /plugins
        /Partners
            /templates 
                /Partners
                    /view.php

to the header.php set in the following folder:

/app-name
    /plugins
        /Partners
            /templates
                /cell
                    /GuestView
                        /header.php

I get the errors as previously mentioned in this thread, If you can help solving the error and get it working that would be most grateful.

Regards

Mal

What version of Cake are you using? I’ve been assuming 3.x, but the directory structure may have changed a bit in 4.x.

V 4.x as I haven’t used CakePHP before I figured I’d use the latest version, so only started learning about 4 weeks ago and only getting to grips with PHP7 so been a bit of a struggle to work some stuff out.

As I mentioned in a previous post, the documentation, I’ve noticed seems to give you several options/ways to do stuff which is great, but also confusing and some points are hard to digest because of it, the problem I face is as I’m not doing it full time, but trying to learn it, then trying to build something on my own, out side the tutorials.

If you go to the documentation in some parts of it, you think you are reading the same thing but it turns out to be a complete different way to what you started, no consistency!

Take the Authentication, In book 4.x I was following the CMS tutorial, had to leave it, opened the document up and thought I was still following the CMS tutorial, turns out there was something similar online book as well, written slightly differently around the login part of the tutorial so when I thought I’d done the login part, I had missed parts of it out… :smile:

when I back tracked, my code changed completely half way through which was a bit frustrating, but once I crack it and confident using it, I shall and will be more than willing to help others out

Some things have definitely changed between v3 and v4, so always be sure that you’re looking at the correct version of the documentation for everything.

Why not simply call your cell HeaderCell.php. And then use the display function?

namespace App\View\Cell;

use Cake\View\Cell;

class HeaderCell extends Cell
{

public function display($slug = null)
{

}
}

I gave up my understanding was a cell could be used for lets say a page made up of several sections,
I should be able to split each section in to it’s own cell, then depending what is called it should display that cell using it’s own model, despite reading the book about 8 times I couldn’t get it to work :frowning:

All I wanted was it to do the following:
view page:
partner description cell - ALL partner Types - pulled from main partner table
partners booking cell - display when a partner allows bookings pulled from related table
partners facility cell - display what facilities a partner has pulled from another related table.
so on…

Currently everything is on 1 view page and a lot of code to work through…
so I was going to split it out.

Cheers

Mal