Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Data Model Questions /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Virtual "name" attribute


Go to End


7 Posts   3633 Views

Avatar
Judge

Community Member, 79 Posts

21 February 2010 at 2:25pm

Edited: 21/02/2010 2:32pm

If a data object has a "Name" attribute, then the name is displayed in the automatically generated default admin screens when listing data for that object. This is all nice and handy.

I have an object that does not have a Name attribute stored in the database, but instead I would like the name to be derived from other data in that object (e.g. for an address, the name could be the house number, street name and town concatenated). This only needs to be constructed when the object is fetched from the database, but then it needs to look like it originally came from the database so that it gets used in the admin screens.

Thinking as I write this, would the solution be to create my set of fields using the getCMSFields() method, including a mix of real database fields and non-database fields as required?

-- Jason

Edit: No. A 'ReadonlyField' with the name "Name" unfortunately does not appear in the default admin screens for that object.

Avatar
Hamish

Community Member, 712 Posts

21 February 2010 at 2:32pm

Simply create a method called getName() that returns the name of the object.

Avatar
Judge

Community Member, 79 Posts

21 February 2010 at 2:50pm

Perfect. Thank you.

I'm rewriting something that I started in Kohana. Already I've got more functionality in SS with under 100 lines of code than I managed in Kohana in over a thousand. I think it strikes the balance well between providing a decent programmers framework, and enough CMS functionality that you don't need to spend any time on getting the basic admin screens up and running.

Loving it so far :-)

-- Jason

Avatar
Judge

Community Member, 79 Posts

24 February 2010 at 12:26am

Edited: 24/02/2010 1:23am

Hamish,

I've had some success with that method on most of my data objects, but one is giving me a strange error. The data model is simple enough:

class NaceTitles extends DataObject {
    static $db = array(
        'Title' => 'Varchar(255)',
        'NaceField' => 'Int',
        'NaceGroup' => 'Int',
        'NaceSubGroup' => 'Int',
    );

    static $singular_name = 'NACE Title';
    static $plural_name = 'NACE Titles';

    // FIXME: Why is this erroring???
    function getName() {
        return 'xxx';
        // return $this->NaceField . '.' . $this->NaceGroup . '.' . $this->NaceSubGroup;
    }
}

The error I get, when trying to do a search in the admin screen is:

Error: "Uncaught Exception: Unable to traverse to related object field [Name] on [NaceTitles]" at line 2211 of /var/www/vhosts/.../httpdocs/sapphire/core/model/DataObject.php

I'm stumped as to what it could be. The code around the error implies that the model must have a "Name" attribute in order for this to work, but I have other working models that don't have a Name attribute.

Any clues?

-- Jason

Edit: if I add a 'Name' attribute to the model, then it works, i.e. 'Name' => 'Varchar'. However, I don't want a name attribute, so am puzzled as to why I'm getting this error. I have also tried changing the "Title" attribute to something less reserved (NaceTitle) and that makes no difference - same error.

Edit2: the only difference between the working and non-working data models that I can think of, is that this non-working model is a master object, and the working ones are all detail objects. Detail objects display differently to master objects (there are different icons on the RHS for a start) so that may be where the problem lies.

Avatar
Judge

Community Member, 79 Posts

24 February 2010 at 3:37am

Edited: 24/02/2010 3:44am

I think this is a bug. At least, I can understand why it is happening, but SS could handle it easily without raising an error.

The problem is that SS makes assumptions on what fields are searchable. If you don't list the searchable fields in the model for AdminModel to use, it will assume that any mention of Name, Title, FirstName or Description will be searchable. So long as these fields are listed as a part of the data model, i.e. are real database columns, then it works fine.

However, if you create a virtual field called Name using the GetName() method, SS will assume that this should be searchable and will assume that it is a real database column. It fails when looking for the object that represents that database column.

The fix is to define your own set of searchable fields, including *only* those that exist in the database. For example:

class NaceTitles extends DataObject {
    static $db = array(
        'Title' => 'Varchar(255)',
        'NaceField' => 'Int',
    };

    static $summary_fields = array(
        'Name' => 'Name', // Displayed, but not in the database. We will generate this on-the-fly.
    );

    // Only allow searches on the title. Without this, SS errors trying to make Name searchable.
    static $searchable_fields = array(
        'Title',
    );

    // Now define the value of the constructed virtual column.
    function getName() {
        return $this->NaceField . ': ' . $this->Title;
    }
}

This is actually a cut-down version of what really happens in my module, but it gives you an idea.

SS could handle this condition by not assuming Name is a database column if it happens to be a displayed column. There is the static db array it can use to check.

Edit: the column does not have to be called "Name" - it could be a Varchar of any name.

-- Jason

Avatar
sheadawson

Community Member, 49 Posts

8 October 2012 at 2:52am

Thanks for sharing that Judge, this problem has me up way too late and I can now finally retire for the day!

Avatar
Jare

Community Member, 39 Posts

30 September 2015 at 12:50am

Hi,

I would like to ask about something quite similar as what Judge asked in his first post to this topic. I would like to create a virtual database field that is based on an SQL expression. If I take for example a field named Name, I would write an SQL expression like FirstName+' '+FamilyName AS Name (or ClassName.FirstName+' '+ClassName.FamilyName AS Name) somewhere in the PHP code and that would define how to fetch content for that field.

I know that I could make a method namedName() and combine the name there, but I would like to make it work on a lower level so that it would work out everywhere out of the box (particularly in $searchable_fields).

Thank you for your support!