Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing virtual fields and getters on associated entities #8246

Closed
kyleweishaupt opened this issue Feb 12, 2016 · 17 comments
Closed

Missing virtual fields and getters on associated entities #8246

kyleweishaupt opened this issue Feb 12, 2016 · 17 comments
Assignees
Labels
Milestone

Comments

@kyleweishaupt
Copy link

After upgrading my Cake 3.1.x project to 3.2.x, I can no longer get values besides (null) for virtual properties made through getter functions on my find() associated entities.

Here is a simple example of my problem using my Patients model finding their Client association.

Controller code:

    /**
     * Index method
     *
     * @return void
     */
    public function index()
    {   
        $this->paginate['contain'] = [
            'Clients'
        ];
        $patients = $this->Patients->find('all');

        $this->set('patients', $this->paginate($patients));
        $this->set('_serialize', ['patients']); 
    }

Here is the virtual property I have set in my Client entity:

    /**
     * Exposed virtual fields
     *
     * @var array
     */
    protected $_virtual = [
        'ListIdName'
    ];   

    protected function _getListIdName()
    {
        return $this->_properties['OrganizationName'] . ' [' . $this->_properties['ClientId'] . ']';
    } 

This is returning (null) for $patient->client->listIdName which I can't seem to figure out.

I have tried changing the getter functions to public scope, which does not help. I've also tried using the paginate() method after adding the contain() to the original query as opposed to in $this->paginate[]. The result keeps coming back null.

Here is the relevant output of pr($patients->first()) on my query before pagination:

App\Model\Entity\Patient Object
(
    [PatientId] => 1
    [ClientId] => 2
    [FirstName] => First
    [LastName] => Last
    [client] => App\Model\Entity\Client Object
        (
            [ClientId] => 2
            [OrganizationName] => Some Client
            [[new]] => 
            [[accessible]] => Array
                (
                    [*] => 1
                )

            [[dirty]] => Array
                (
                )

            [[original]] => Array
                (
                )

            [[virtual]] => Array
                (
                    [0] => ListIdName
                )

            [[errors]] => Array
                (
                )

            [[invalid]] => Array
                (
                )

            [[repository]] => Clients
        )

    [[new]] => 
    [[accessible]] => Array
        (
            [*] => 1
        )

    [[dirty]] => Array
        (
        )

    [[original]] => Array
        (
        )

    [[virtual]] => Array
        (
            [0] => FullName
            [1] => ListName
            [2] => ListIdName
        )

    [[errors]] => Array
        (
        )

    [[invalid]] => Array
        (
        )

    [[repository]] => Patients
)

As you can see, the virtual fields are not there. These worked in CakePHP 3.1.10 but are not working in 3.2.1 or 3.2.2 that was just released.

I didn't see anything in the changelog about this functionality changing so I'm hoping this is just a bug and not something I'm doing wrong. Any help would be greatly appreciated.

@lorenzo lorenzo added the defect label Feb 12, 2016
@lorenzo lorenzo added this to the 3.2.3 milestone Feb 12, 2016
@dakota
Copy link
Member

dakota commented Feb 12, 2016

Ok, looks like what happened is that 6c5c6cb started caching the accessor methods. However, it builds the cache using the underscored property names (Since that is the cakephp convention), using $entity->list_id_name will work in the mean time.

@markstory markstory self-assigned this Feb 12, 2016
@markstory
Copy link
Member

I can take a look.

markstory added a commit that referenced this issue Feb 12, 2016
This fixes a regression introduced in while optimizing entity accessors.

Refs #8246
@markstory
Copy link
Member

Pull request open now.

@kyleweishaupt
Copy link
Author

Still having this issue as of 3.2.3 with the same code. The schema I'm forced to use isn't camel cased, but title cased. i.e. ClientId, PatientId, FirstName, etc... I'm sorry I had it listed as listIdName, camel cased, earlier.

I'm looking to output using the same format ($patient->client->ListIdName) but I'll change things over to @dakota's solution for now. Thanks!

@holisticnetworking
Copy link

I'm working on 3.3.8 and having a similar issue. Not sure when it started becoming a problem, but virtual fields. Any virtual fields, actually. Associated Models or not.

@markstory
Copy link
Member

@holisticnetworking So no virtual fields are working?

@holisticnetworking
Copy link

holisticnetworking commented Nov 22, 2016

Yes, sorry. I should have been more specific.

Here is one virtual field declaration for a Model called "Client"

protected function _getFullName() {
        return trim( $this->_properties['first_name'] ) . '  ' .
            trim( $this->_properties['last_name'] );
    }

However, when I access a page - either for this Model or one of it's associated Models - the field does not show up. For example, this json string:

{
    "clients": [
        {
            "id": 1,
            "first_name": "Adriano",
            "last_name": "Manocchia",
            "institution_id": 2,
            "department_id": 2,
            "pi_id": 788,
            "dept": "",
            "email": "am33@cornell.edu",
            "address": "Cornell University\r\n154 Biotech Building\r\nIthaca, NY 14853",
            "billaddress": "",
            "street1": "463 Troy Road",
            "street2": "",
            "city": "Ithaca",
            "state": "NY",
            "zip": "14850",
            "country": "United States",
            "sstreet1": "Cornell University",
            "sstreet2": "143 Biotechnology Building",
            "scity": "Ithaca",
            "sstate": "NY",
            "szip": "14853",
            "scountry": "United States",
            "phone": "607 255-0366",
            "billphone": "607 277-5952",
            "fax": "",
            "seqresname": "Manocchia_Adriano",
            "verified": true,
            "su": 0,
            "updatedinfo": true,
            "training": "1",
            "failedlogins": 0,
            "lastlogin": "2016-08-24T16:26:46-05:00",
            "slims": true,
            "emailverified": true,
            "imaging_hazards": "None",
            "imaging_project": "Stuff",
            "imaging_position": "Staff",
            "staff_comments": "Testing",
            "imaging_survey": true,
            "created": null,
            "modified": null
        },

And so on. I can't seem to backtrack it - I've been working in areas for which virtual fields are not needed for a few weeks. But disabling any but the default plugins does not seem to resolve the issue, either.

The Clients query above includes no special custom queries or other razmatazz.

@markstory
Copy link
Member

Ok. Is full_name in your Entity's _virtual property list? It should look something like

protected $_virtual = ['full_name'];

@holisticnetworking
Copy link

Ok.. Is this a new requirement? Because I swear they were working a few months ago without a $_virtual definition? Probably not.

Either way, thanks for the help @markstory and sorry about the issue report!

@inoas
Copy link
Contributor

inoas commented Nov 22, 2016

If it is a requirement could you add it here @holisticnetworking http://book.cakephp.org/3.0/en/orm/entities.html#creating-virtual-fields
Edit: Sorry, it is already there: http://book.cakephp.org/3.0/en/orm/entities.html#exposing-virtual-properties
E.g. you might be able to access it like $clientEntity->yourVirtualField or $clientEntity->get('yourVirtualField')

@markstory
Copy link
Member

VirtualFields have always required to be listed in the $_virtual property if you want them to be in array conversions.

@holisticnetworking
Copy link

In array conversions? So, not in objects created by the query builder?
Because if that's the case, it may be a distinction too subtle for most?
I've never seem or documented, for example, under Virtual Fields in the
cookbook?

On Tue, Nov 22, 2016, 2:55 PM Mark Story notifications@github.com wrote:

VirtualFields have always required to be listed in the $_virtual property
if you want them to be in array conversions.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#8246 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABGFsKR-vYYUto8yMyQWFqXL2VlpUJPiks5rA0iOgaJpZM4HZFET
.

@markstory
Copy link
Member

Sorry, I was unclear. By 'Array Conversions' I meant in the results of $entity->toArray() or json_encode($entity).

I'll update the documentation as you're right that requirement is not clear.

@markstory
Copy link
Member

I found the existing section in the documentation. What would make this section easier to find? Perhaps a link in the Virtual Fields section?

markstory added a commit to cakephp/docs that referenced this issue Nov 23, 2016
Using both fields and properties can be confusing.

Refs cakephp/cakephp#8246
markstory added a commit to cakephp/docs that referenced this issue Nov 23, 2016
Using both fields and properties can be confusing.

Refs cakephp/cakephp#8246
@holisticnetworking
Copy link

holisticnetworking commented Nov 23, 2016

I think that simply adding a highlighted callout here, like you do for other docs (class="admonition note") that says "Note: special rules apply for array and JSON conversions" with a jump link to the relevant text below is sufficient.

May I ask why this distinction exists? To me, unless you specifically protect a field with $_hidden, the data is what the data is. Regardless of what's done with it?

@markstory
Copy link
Member

@holisticnetworking Knowing all the virtual properties on an entity would require non-free reflection if we didn't have the explicit list, as virtual fields aren't defined anywhere other than by implementing methods via a naming convention.

@holisticnetworking
Copy link

Thanks for the explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants