yiisoft / yii-dataview

Data widgets
https://www.yiiframework.com/
BSD 3-Clause "New" or "Revised" License
38 stars 22 forks source link

Undefined property: App\Invoice\Entity\Inv Cycle ORM Proxy::$id #140

Closed rossaddison closed 9 months ago

rossaddison commented 9 months ago

What steps will reproduce the problem? Testing

What is the expected result? Smooth run

What do you get instead? Error

Additional info

Q A
Version 1.0.?
PHP version 8.2
Operating system Windows 11

..resources/view/invoice/inv/index.php

<?php
    $read_with_iterable_type = $paginator_with_readabledatainterface_type->read();
    /**
     * @var ColumnInterface[] $columns
     */
    $columns = [
          new DataColumn(
              'id'
          )   
    ];
?>
<?php  echo GridView::widget()
    // unpack the contents within the array using the three dot splat operator    
    ->columns(...$columns)
    ->dataReader($paginator_with_readabledatainterface_type)    
?>

Hi Vijk, If I pass an empty array for $columns, the GridView attempts to build the ActionColumns ie. view etc and I get the following error as well:

image

I thought this might be of interest. The code appears not to be accepting the DataColumn's first argument id because it has no property type associated with it ie. undefined property. This appears to be a Cycle issue.

vjik commented 9 months ago

Thanks for report 👍

rossaddison commented 9 months ago

No probs Vijk. Keep up the hard development work. You are making amazing contributions to the Php community.

vjik commented 9 months ago

@rossaddison I updated package, can you try now?

rossaddison commented 9 months ago

Ok just seen your message. Will try.

rossaddison commented 9 months ago

No change unfortunately.

It would be great if I could insert a 'property' annotation in the 'model' or use a getter or setter in the model to reflect the integer property of the id as in Yii2 models but then again the $model variable was previously input into a static function although not passed from the controller. I have never figured out how the previous Yii3 GridView got the $model variable since it was not passed by means of the InvController.php. Injected? Perhaps you could explain how the $model variable was passed previously just as a matter of interest and unrelated to the issue here.

....previous Yii3 GridView using DataColumn

DataColumn::create()
                ->attribute('id')
                ->label($s->trans('id'))
                ->value(static fn(object $model) => $model->getId()),

It is not a problem getting the DataColumns into the VarDumper::dump by means of the following code:

$read_with_iterable_type = $paginator_with_readabledatainterface_type->read();
$array = $read_with_iterable_type instanceof \Traversable ? iterator_to_array($read_with_iterable_type, true) : (array)$read_with_iterable_type;
    foreach ($array as $record) {
        /**
         * @var ColumnInterface[] $columns
         */    
        $columns = [
                        new DataColumn(
                            'id',
                            'header_string',
                            'footer_string',
                            [
                                'label' => $s->trans('id'),
                                'value' => $record->getId()
                            ]
                        )   
                    ];     
    }
    echo \Yiisoft\VarDumper\VarDumper::dump($columns);

[ 0 => Yiisoft\Yii\DataView\Column\DataColumn#3951 ( [property] => 'id' [header] => 'header_string' [footer] => 'footer_string' [columnAttributes] => [ 'label' => 'ID' 'value' => '1' ] [headerAttributes] => [] [filterAttributes] => [] [bodyAttributes] => [] [withSorting] => true [content] => null [filter] => null [filterProperty] => null [filterType] => 'text' [filterInputAttributes] => [] [filterModelName] => null [filterValueDefault] => null [filterInputSelectItems] => [] [filterInputSelectPrompt] => '' [Yiisoft\Yii\DataView\Column\DataColumn:visible] => true ) ]

I think the problem is that the code is trying to iterate over an array that contains different levels of relational data with Cycle property types but I think the problem is that a $model is needed to instantiate properties. Just my opinion.

The $array value still keeps the cycle properties eg. deeper down the array. Could a model be introduced which can replace mitigate these values perhaps?

Ok just tested the $model variable with other $variable names and it is a local static function input parameter that is unrelated to $model global value which explains why it cannot be passed from the Contoller. If i substitute $any with $model in

DataColumn::create()
                ->attribute('id')
                ->label($s->trans('id'))
                ->value(static fn(object $any) => $any->getId()),

it still gives the same value. So the issue cannot be model related.

rossaddison commented 9 months ago
Yiisoft\ErrorHandler\Exception\ErrorException: Undefined property: App\Invoice\Entity\Inv Cycle ORM Proxy::$id in C:\wamp64\www\invoice\vendor\cycle\orm\src\Mapper\Proxy\EntityProxyTrait.php:28
Stack trace:
#0 C:\wamp64\www\invoice\vendor\yiisoft\error-handler\src\ErrorHandler.php(133): Yiisoft\ErrorHandler\Exception\ErrorException->__construct(message: ''Undefined prop...', code: '2', severity: '2', filename: ''C:\\\\wamp64\\\\ww...', line: '28', previous: '???')
#1 C:\wamp64\www\invoice\vendor\cycle\orm\src\Mapper\Proxy\EntityProxyTrait.php(28): Yiisoft\ErrorHandler\ErrorHandler->Yiisoft\ErrorHandler\{closure:C:\wamp64\www\invoice\vendor\yiisoft\error-handler\src\ErrorHandler.php:123-134}(severity: '2', message: ''Undefined prop...', file: ''C:\\\\wamp64\\\\ww...', line: '28')
#2 C:\wamp64\www\invoice\vendor\yiisoft\arrays\src\ArrayHelper.php(264): App\Invoice\Entity\Inv Cycle ORM Proxy->__get(name: ''id'')
#3 C:\wamp64\www\invoice\vendor\yiisoft\arrays\src\ArrayHelper.php(227): Yiisoft\Arrays\ArrayHelper::getRootValue(array: 'class App\\Invoi...', key: ''id'', default: 'NULL')
#4 C:\wamp64\www\invoice\vendor\yiisoft\yii-dataview\src\Column\DataColumnRenderer.php(97): Yiisoft\Arrays\ArrayHelper::getValue(array: 'class App\\Invoi...', key: ''id'', default: '???')
#5 C:\wamp64\www\invoice\vendor\yiisoft\yii-dataview\src\GridView.php(497): Yiisoft\Yii\DataView\Column\DataColumnRenderer->renderBody(column: 'class Yiisoft\\Y...', cell: 'class Yiisoft\\Y...', context: 'class Yiisoft\\Y...')
#6 C:\wamp64\www\invoice\vendor\yiisoft\yii-dataview\src\BaseListView.php(481): Yiisoft\Yii\DataView\GridView->renderItems()
#7 C:\wamp64\www\invoice\vendor\yiisoft\yii-dataview\src\BaseListView.php(465): Yiisoft\Yii\DataView\GridView->renderGridTable()
#8 C:\wamp64\www\invoice\vendor\yiisoft\yii-dataview\src\BaseListView.php(402): Yiisoft\Yii\DataView\GridView->renderGrid()
#9 C:\wamp64\www\invoice\vendor\yiisoft\widget\src\Widget.php(133): Yiisoft\Yii\DataView\GridView->render()
#10 C:\wamp64\www\invoice\resources\views\invoice\inv\index.php(143): Yiisoft\Yii\DataView\GridView->__toString()
#11 C:\wamp64\www\invoice\vendor\yiisoft\view\src\PhpTemplateRenderer.php(28): Yiisoft\View\WebView->unknown()
#12 C:\wamp64\www\invoice\vendor\yiisoft\view\src\PhpTemplateRenderer.php(37): Yiisoft\View\WebView->Yiisoft\View\{closure:C:\wamp64\www\invoice\vendor\yiisoft\view\src\PhpTemplateRenderer.php:24-29}(''C:\\\\wamp64\\\\ww...', '['assetManager'...')
#13 C:\wamp64\www\invoice\vendor\yiisoft\view\src\ViewTrait.php(441): Yiisoft\View\PhpTemplateRenderer->render(view: 'class Yiisoft\\V...', template: ''C:\\\\wamp64\\\\ww...', parameters: '['assetManager'...')
#14 C:\wamp64\www\invoice\vendor\yiisoft\view\src\ViewTrait.php(393): Yiisoft\View\WebView->renderFile(viewFile: ''C:\\\\wamp64\\\\ww...', parameters: '['page' => 1, '...')
#15 C:\wamp64\www\invoice\vendor\yiisoft\yii-view\src\ViewRenderer.php(313): Yiisoft\View\WebView->render(view: ''/invoice/inv/i...', parameters: '['page' => 1, '...')
#16 C:\wamp64\www\invoice\vendor\yiisoft\yii-view\src\ViewRenderer.php(101): Yiisoft\Yii\View\ViewRenderer->renderProxy(view: ''/invoice/inv/i...', contentParameters: '['page' => 1, '...', injectCommonParameters: '['url' => class...', injectLayoutParameters: '['brandLabel' =...', metaTags: '['csrf' => ['na...', linkTags: '['favicon' => [...')
#17 C:\wamp64\www\invoice\vendor\yiisoft\data-response\src\DataResponse.php(326): Yiisoft\Yii\View\ViewRenderer->Yiisoft\Yii\View\{closure:C:\wamp64\www\invoice\vendor\yiisoft\yii-view\src\ViewRenderer.php:101-108}()
#18 C:\wamp64\www\invoice\vendor\yiisoft\data-response\src\Formatter\HtmlDataResponseFormatter.php(43): Yiisoft\DataResponse\DataResponse->getData()
#19 C:\wamp64\www\invoice\vendor\yiisoft\data-response\src\DataResponse.php(355): Yiisoft\DataResponse\Formatter\HtmlDataResponseFormatter->format(dataResponse: 'class Yiisoft\\D...')
#20 C:\wamp64\www\invoice\vendor\yiisoft\data-response\src\DataResponse.php(108): Yiisoft\DataResponse\DataResponse->formatResponse()
#21 C:\wamp64\www\invoice\vendor\yiisoft\cookies\src\CookieMiddleware.php(148): Yiisoft\DataResponse\DataResponse->getHeader(name: ''Set-Cookie'')
#22 C:\wamp64\www\invoice\vendor\yiisoft\cookies\src\CookieMiddleware.php(85): Yiisoft\Cookies\CookieMiddleware->encodeResponseSetCookieHeaders(response: 'class Yiisoft\\D...')
#23 C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php(93): Yiisoft\Cookies\CookieMiddleware->process(request: 'class HttpSoft\\...', handler: 'class Psr\\Http\\...')
#24 C:\wamp64\www\invoice\vendor\yiisoft\session\src\SessionMiddleware.php(36): {anonymous-class:C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php:71-98}->handle(request: 'class HttpSoft\\...')
#25 C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php(93): Yiisoft\Session\SessionMiddleware->process(request: 'class HttpSoft\\...', handler: 'class Psr\\Http\\...')
#26 C:\wamp64\www\invoice\vendor\yiisoft\yii-sentry\src\SentryMiddleware.php(27): {anonymous-class:C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php:71-98}->handle(request: 'class HttpSoft\\...')
#27 C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php(93): Yiisoft\Yii\Sentry\SentryMiddleware->process(request: 'class HttpSoft\\...', handler: 'class Psr\\Http\\...')
#28 C:\wamp64\www\invoice\vendor\yiisoft\error-handler\src\Middleware\ErrorCatcher.php(124): {anonymous-class:C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php:71-98}->handle(request: 'class HttpSoft\\...')
#29 C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php(93): Yiisoft\ErrorHandler\Middleware\ErrorCatcher->process(request: 'class HttpSoft\\...', handler: 'class Psr\\Http\\...')
#30 C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php(49): {anonymous-class:C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareStack.php:71-98}->handle(request: 'class HttpSoft\\...')
#31 C:\wamp64\www\invoice\vendor\yiisoft\middleware-dispatcher\src\MiddlewareDispatcher.php(48): Yiisoft\Middleware\Dispatcher\MiddlewareStack->handle(request: 'class HttpSoft\\...')
#32 C:\wamp64\www\invoice\vendor\yiisoft\yii-http\src\Application.php(77): Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher->dispatch(request: 'class HttpSoft\\...', fallbackHandler: 'class App\\Handl...')
#33 C:\wamp64\www\invoice\vendor\yiisoft\yii-runner-http\src\HttpApplicationRunner.php(140): Yiisoft\Yii\Http\Application->handle(request: 'class HttpSoft\\...')
#34 C:\wamp64\www\invoice\public\index.php(40): Yiisoft\Yii\Runner\Http\HttpApplicationRunner->run()
#35 {main}
vjik commented 9 months ago

Hm. Does entity contain property id? Or used getId()?

rossaddison commented 9 months ago

Entity Inv.php

#[Column(type: 'primary')]
    private ?int $id = null;

   /**
     * @return null|numeric-string
     */
    public function getId(): string|null {
        return $this->id === null ? null : (string) $this->id;
    }

    public function setId(int $id): void {
        $this->id = $id;
    }

There is nothing in the __construct parameters or the _construct assignments because the id gets created.

This has all been Psalm level 1 tested as well.

vjik commented 9 months ago

I understand. Now GridView getting value from object property, but in your case need to use getter.

But do this cycle entry work with Yii3 GridView before?

rossaddison commented 9 months ago

Yes the cycle entity was working with the Yii3 GridView before.

vjik commented 9 months ago

Yes the cycle entity was working with the Yii3 GridView before.

Hm. It's very strange, because getting of value not changed...

rossaddison commented 9 months ago

I have noticed the yiisoft/form has changed and I have static errors. I am going to fix these first and test. I will get back to you.

vjik commented 9 months ago

Oh. Seems, I understand.

Instead of this code:

DataColumn::create()
    ->attribute('id')
    ->label($s->trans('id'))
    ->value(static fn(object $any) => $any->getId()),

Try it:

new DataColumn(
    'id',
    header: $s->trans('id'),
    content: static fn(object $any) => $any->getId()
);
vjik commented 9 months ago

I have noticed the yiisoft/form has changed and I have static errors. I am going to fix these first and test. I will get back to you.

Now I am actively working on Yii Form and Yii DataView, changes with break BC are possible :( But I hope, result will be good.

rossaddison commented 9 months ago

Thanks Vijk the GridView is working now!

image

I am going to rework the forms. I am sure the result will be good. Take care.