Yii2: вспомогательная функция статуса «включена» и «отключена» — динамическое использование

Я хотел бы объединить 2 функции вместе, чтобы объединить код и быть динамичным в зависимости от того, как он используется. Я не знаю, возможно ли это.

Во-первых, давайте выложим основное использование. В моем примере у меня есть модели Post и PostCategory (и построенные CRUD). Вы создаете категорию, затем создаете новый пост и назначаете его категории. Пост может быть enabled или disabled. По сути, вы можете создать несколько новых сообщений и сделать их недоступными для просмотра конечными пользователями, пока вы не будете готовы. Одним из вариантов использования может быть система капельной подачи, в которой вы можете добавить 100 сообщений и переключаться на enabled каждые x дней. Это выходит за рамки этого.

представления\post\_form.php

<div class="post-form">

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'category_id')->dropDownList(
            $model->getPostCategoryConst(),
            ['prompt'=> '- Category -']
        )->label('Category')
    ?>

    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>

    <?= $form->field($model, 'text')->textarea(['rows' => 6]) ?>

    <?= $form->field($model, 'status')->dropDownList(
        $model->getPostStatusConst(),
        ['prompt'=> '- Status -']
    ) ?>

    <div class="form-group">
        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

Обратите внимание на раскрывающиеся списки для category_id и status и функций, которые они вызывают

\common\models\Post.php

const STATUS_ENABLED = 1;
const STATUS_DISABLED = 0;

public function getCategory()
{
    return $this->hasOne(PostCategory::className(), ['id' => 'category_id']);
}

/* -- Added -- */

public function getPostCategoryConst()
{
    return ArrayHelper::map(PostCategory::find()->orderBy('name DESC')->all(), 'id', 'name');
}

public function getPostStatusConst()
{
    return [
        self::STATUS_DISABLED => 'Disabled',
        self::STATUS_ENABLED => 'Enabled',
    ];
}

Теперь это работает просто отлично :) Однако мне не нравится использовать get, как в getPostStatusConst(), поскольку к нему нет доступа, как $model->postStatusConst, аналогично тому, как отношения с «геттером».

Я хотел бы использовать их как "геттеры". В индексе и представлении было бы неплохо также вызывать одни и те же функции. Вместо того, чтобы возвращать массив, возвращать «красивое имя», например «Включено» или «Отключено».

Ради этого я не буду переименовывать функцию, так как не хочу еще больше вносить путаницу.

представления\post\view.php

<?= DetailView::widget([
    'model' => $model,
    'attributes' => [
        'id',
        'category.name',
        'name',
        'text:ntext',
        'postStatusConst',  // <-- Calls getPostStatusConst()
        'created_at:datetime',
        'updated_at:datetime',
    ],
]) ?>

Обратите внимание, что postStatusConst — это та же функция, которую мы использовали в _form для нашего действия по созданию. В _form нужно было вернуть массив для выпадающего списка. На наш взгляд, ему просто нужно вернуть красивое имя, такое как Enabled или Disabled.


Я старался

Я попробовал эту функцию в модели Post:

public function getPostStatusConst()
{
    if ( isset($this) ) {
        return ($this->status === self::STATUS_ENABLED) ? 'Enabled' : 'Disabled';
    }

    return [
        self::STATUS_DISABLED => 'Disabled',
        self::STATUS_ENABLED => 'Enabled',
    ];
}

Это явно не сработало :) Я этого не ожидал, потому что я знаю, что $this ссылается на себя в классе. Это просто показывает, к чему я иду.

В отношениях hasOne(), похоже, знает, используем ли мы его как прямой вызов (Post::getCategory) или встроенный ($model->category->name)..

Вопрос

Возможно ли, чтобы getPostStatusConst() сделал то же самое? Использовать как $model->postStatusConst для красивого отображения Enabled или Disabled или как Post::getPostStatusConst() для получения массива для раскрывающегося списка.


person Wade    schedule 03.08.2016    source источник


Ответы (2)


Это возможно, но на самом деле не стоит всех изменений в коде. Вам придется переопределить магический метод __get() и подумать о каком-то способе хранения и доступа к обоим возвращаемым значениям в одной структуре.

Я бы оставил getPostStatusConst() с текущим именем статуса и добавил другой метод (даже статический) со списком статусов для выпадающего списка.

person Bizley    schedule 03.08.2016
comment
Спасибо за ваше время. Я согласен, то, что вы сказали, того не стоит. В прошлых проектах я использовал 2 отдельные функции. По мере продвижения я стараюсь делать вещи лучше, круче и эффективнее :) Мне показалось, что я где-то читал, что отношения, такие как построенные с помощью Gii (например, hasOne()), знают разницу между тем, как они используются. Я пробежался по коду, но не перепрыгивал через многие обручи, потому что каждый файл ссылается на другой, который ссылается на другой, лол. - person Wade; 04.08.2016
comment
На самом деле, я был очень близок :) Я решил это! Я отмечу свой ответ, когда SO позволит мне (думаю, 2 дня). До тех пор я открыт для любых других решений. Может быть, какая-то основная функция Yii или лучший способ. - person Wade; 04.08.2016
comment
Это хороший хак, но вызывает ошибку/предупреждение в зависимости от версии и конфигурации PHP. Отвечая, я думал о том же решении, которое доступно для методов и атрибутов отношений в Yii 2. - person Bizley; 04.08.2016
comment
Это выдает ошибку, как в моем другом комментарии. Я думал о том же, это работает с отношениями. Это должно быть воспроизводимо. Я просмотрел источник, но не смог найти, где они это делают. - person Wade; 05.08.2016
comment

Я был довольно близко. Я думал не о строках PHP OOP, а больше о Yii. Несколько поисковых запросов в Google, и я хлопнул себя по лбу. При использовании фреймворков вы иногда даже забываете писать на PHP;)

public function getPostStatus()
{
    if ( isset($this) && get_class($this) == __CLASS__) {
        // not static
        return ($this->status === self::STATUS_ENABLED) ? 'Enabled' : 'Disabled';
    }

    return [
        self::STATUS_DISABLED => 'Disabled',
        self::STATUS_ENABLED => 'Enabled',
    ];
}

Я переименовал функцию, чтобы она имела больше смысла.

Это работает везде. Давайте посмотрим индекс моего CRUD:

просмотры\пост\index.php

    <?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],

        'id',
        'category.name',
        'name',
        //'text:ntext',
        'postStatus',
        // 'created_at',
        // 'updated_at',

        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

представления\post\view.php

<?= DetailView::widget([
    'model' => $model,
    'attributes' => [
        'id',
        'category.name',
        'name',
        'text:ntext',
        'postStatus',
        'created_at:datetime',
        'updated_at:datetime',
    ],
]) ?>

и представления\post\_form.php

<?= $form->field($model, 'status')->dropDownList(
    Post::getPostStatus(),
    ['prompt'=> '- Status -']
) ?>

Все эти случаи, кажется, работают нормально. У кого-нибудь есть случаи, когда это не работает?

person Wade    schedule 04.08.2016
comment
Вы не получаете ошибку Strict standards: Non-static method Post::getPostStatus() should not be called statically? В зависимости от вашей конфигурации и/или версии PHP ваши журналы (и, что еще хуже, ваш вывод) могут быть запутанными. - person Bizley; 04.08.2016
comment
Твое право. Я переустановил xampp несколько недель назад и забыл изменить сообщение об ошибке на E_ALL. Это исключало строгое и устаревшее. Так что, хотя это работает просто отлично, strict будет жаловаться на это. - person Wade; 05.08.2016