Search code examples
phparraysfunctionduplicatesyii2

Yii2 How do I use multiple array keys with the same value inside attributeLabels function


I am creating a column inside a table that can have 0, 1, 2 or 3. All these numbers have a certain value, in my case 0 = DOG, 1 = CAT, 2 = FISH, 3 = FROG. To get the names inside the table instead of the numbers I do the following:

public function attributeLabels(): array
{
    return [
        Pet::DOG => 'Dog',
        Pet::CAT => 'CAT',
        Pet::FISH => 'Fish',
        Pet::FROG => 'Frog',
        Pet::TYPE_LAND => 'Land',
        Pet::TYPE_WATER => 'Water'
}

And in the Gridview

[
    'attribute' => 'Animal',
    'header' => Icon::show('beast', ['title' => Yii::t('backend', 'animal')]),
    'value' => function ($model) use ($petSearch) {
         return $petSearch->getAttributeLabel($model['Animal']);
     },
     'filter' => [
         Pet::DOG => $PetSearch->getAttributeLabel(Pet::DOG),
         Pet::CAT => $PetSearch->getAttributeLabel(Pet::CAT),
         Pet::FISH => $PetSearch->getAttributeLabel(Pet::FISH),
         Pet::FROG => $PetSearch->getAttributeLabel(Pet::FROG),
     ]
],

This should show me the column with the right translations and it does, but there is a problem. Sinds TYPE_LAND and TYPE_WATER also have the values 0 and 1 it gives me a mix of the 2 so the column makes no sense for instance instead of dog I see Land. I also get the following message in my code:

Duplicate array key with value '0' 

Is there a way to make this work correctly


Solution

  • You don't have to use attributeLabels() method for this. That method is supposed to label model's attributes not its values.

    You can create two public methods for translating values into proper labels in your PetSearch model for example like this:

    public function animalLabel($animal) {
        $map = [
            Pet::DOG => 'Dog',
            Pet::CAT => 'CAT',
            Pet::FISH => 'Fish',
            Pet::FROG => 'Frog',
        ];
    
        if (isset($map[$animal])) {
            return $map[$animal];
        }
        // ... do something if the value is not present in map
        // for example throw an exception, return empty/default label or something...
    }
    
    public function animalTypeLabel($type) {
        $map = [
            Pet::TYPE_LAND => 'Land',
            Pet::TYPE_WATER => 'Water'
        ];
    
        if (isset($map[$type])) {
            return $map[$type];
        }
        // ... do something if the value is not present in map
        // for example throw an exception, return empty/default label or something...
    }
    

    Then in your GridView config use those methods to replace numeric value with label:

    [
        'attribute' => 'Animal',
        'header' => Icon::show('beast', ['title' => Yii::t('backend', 'animal')]),
        'format' => function ($value) use ($petSearch) {
             return $petSearch->animalLabel($value);
        },
        'filter' => [
            Pet::DOG => $petSearch->animalLabel(Pet::DOG),
            Pet::CAT => $petSearch->animalLabel(Pet::CAT),
            Pet::FISH => $petSearch->animalLabel(Pet::FISH),
            Pet::FROG => $petSearch->animalLabel(Pet::FROG),
        ],
    ],
    [
        // asuming the type value is in `AnimalType` attribute - change to match your attribute names
        'attribute' => 'AnimalType',
        'header' => Icon::show('beast', ['title' => Yii::t('backend', 'animal')]),
        'format' => function ($value) use ($petSearch) {
             return $petSearch->animalTypeLabel($value);
         },
        'filter' => [
            Pet::TYPE_LAND => $petSearch->animalTypeLabel(Pet::TYPE_LAND),
            Pet::TYPE_WATER => $petSearch->animalTypeLabel(Pet::TYPE_WATER),
        ],
    ],