How to create a Yii2 model without a database

2019-04-21 04:39发布

问题:

I would like to create a yii2 model without a database. Instead, the data is generated dynamically and not stored, just displayed to the user as a json. Basically, I would just like a get a simple, basic example of a non-database Model working but I can't find any documentation on it.

So how would I write a model without a database? I have extended \yii\base\Model but I get the following error message:

<?xml version="1.0" encoding="UTF-8"?>
<response>
   <name>PHP Fatal Error</name>
   <message>Call to undefined method my\app\models\Test::find()</message>
   <code>1</code>
   <type>yii\base\ErrorException</type>
   <file>/my/app/vendor/yiisoft/yii2/rest/IndexAction.php</file>
   <line>61</line>
   <stack-trace>
      <item>#0 [internal function]: yii\base\ErrorHandler->handleFatalError()</item>
      <item>#1 {main}</item>
   </stack-trace>
</response>

To implement find(), I must return a database query object.

My Model is completely blank, I'm just looking for a simple example to understand the principal.

<?php
namespace my\app\models;

class Test extends \yii\base\Model{
}

回答1:

This is a Model from one of my projects. This Model is not connected with any database.

<?php
/**
 * Created by PhpStorm.
 * User: Abhimanyu
 * Date: 18-02-2015
 * Time: 22:07
 */

namespace backend\models;

use yii\base\Model;

class BasicSettingForm extends Model
{
    public $appName;
    public $appBackendTheme;
    public $appFrontendTheme;
    public $cacheClass;
    public $appTour;

    public function rules()
    {
        return [
            // Application Name
            ['appName', 'required'],
            ['appName', 'string', 'max' => 150],

            // Application Backend Theme
            ['appBackendTheme', 'required'],

            // Application Frontend Theme
            ['appFrontendTheme', 'required'],

            // Cache Class
            ['cacheClass', 'required'],
            ['cacheClass', 'string', 'max' => 128],

            // Application Tour
            ['appTour', 'boolean']
        ];
    }

    public function attributeLabels()
    {
        return [
            'appName'          => 'Application Name',
            'appFrontendTheme' => 'Frontend Theme',
            'appBackendTheme'  => 'Backend Theme',
            'cacheClass' => 'Cache Class',
            'appTour'    => 'Show introduction tour for new users'
        ];
    }
}

Use this Model like any other. e.g. view.php:

<?php
/**
 * Created by PhpStorm.
 * User: Abhimanyu
 * Date: 18-02-2015
 * Time: 16:47
 */

use abhimanyu\installer\helpers\enums\Configuration as Enum;
use yii\caching\DbCache;
use yii\caching\FileCache;
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/** @var $this \yii\web\View */
/** @var $model \backend\models\BasicSettingForm */
/** @var $themes */

$this->title = 'Basic Settings - ' . Yii::$app->name;
?>

<div class="panel panel-default">
    <div class="panel-heading">Basic Settings</div>

    <div class="panel-body">

        <?= $this->render('/alert') ?>

        <?php $form = ActiveForm::begin([
                                        'id'                   => 'basic-setting-form',
                                        'enableAjaxValidation' => FALSE,
                                    ]); ?>

        <h4>Application Settings</h4>

        <div class="form-group">
            <?= $form->field($model, 'appName')->textInput([
                                                           'value'        => Yii::$app->config->get(
                                                               Enum::APP_NAME, 'Starter Kit'),
                                                           'autofocus'    => TRUE,
                                                           'autocomplete' => 'off'
                                                       ])
            ?>
        </div>

        <hr/>

        <h4>Theme Settings</h4>

        <div class="form-group">
            <?= $form->field($model, 'appBackendTheme')->dropDownList($themes, [
            'class'   => 'form-control',
            'options' => [
                Yii::$app->config->get(Enum::APP_BACKEND_THEME, 'yeti') => ['selected ' => TRUE]
            ]
        ]) ?>
    </div>

    <div class="form-group">
        <?= $form->field($model, 'appFrontendTheme')->dropDownList($themes, [
            'class'   => 'form-control',
            'options' => [
                Yii::$app->config->get(Enum::APP_FRONTEND_THEME, 'readable') => ['selected ' => TRUE]
            ]
        ]) ?>
    </div>

    <hr/>

    <h4>Cache Setting</h4>

    <div class="form-group">
        <?= $form->field($model, 'cacheClass')->dropDownList(
            [
                FileCache::className() => 'File Cache',
                DbCache::className()   => 'Db Cache'
            ],
            [
                'class'   => 'form-control',
                'options' => [
                    Yii::$app->config->get(Enum::CACHE_CLASS, FileCache::className()) => ['selected ' => TRUE]
                ]
            ]) ?>
    </div>

    <hr/>

    <h4>Introduction Tour</h4>

    <div class="form-group">
        <div class="checkbox">
            <?= $form->field($model, 'appTour')->checkbox() ?>
        </div>
    </div>

    <?= Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>

    <?php $form::end(); ?>
</div>



回答2:

The reason for using a model is to perform some kind of logic on data that you are getting from somewhere. A model can be used to perform data validation, return properties of the model and their labels, and allows for massive assignment. If you don't need these features for your data model, then don't use a model!

If you are not requiring data validation (i.e. you are not changing any data via forms or other external source), and you are not requiring access to behaviors or events, then you probably need to just use yii\base\Object. This will give you access to getters and setters for properties of the object, which seems to be all you need.

So your class ends up looking like this. I've included getting data from another model, in case that's what you want to do;

<?php
namespace my\app\models;
use \path\to\some\other\model\to\use\OtherModels;

class Test extends \yii\base\Object{

    public function getProperty1(){
        return "Whatever you want property1 to be";
    }

    public function getProperty2(){
        return "Whatever you want property2 to be";
    }

    public function getOtherModels(){
        return OtherModels::findAll();
    }

}

You would then simply use it like this;

$test = new Test;
echo $test->property1;
foreach ($test->otherModels as $otherModel){
    \\Do something
}

The function you have tried to use, find(),is only relevant to a database and so won't be available to your class if you've extended yii\base\Model, yii\base\Component or yii\base\Object, unless you want to define such a function yourself.



回答3:

A lightweight way to create models without database backend is to use a DynamicModel:

DynamicModel is a model class primarily used to support ad hoc data validation.

Just write in your controller:

$model = new DynamicModel(compact('name', 'email'));
$model->addRule(['name', 'email'], 'string', ['max' => 128])
    ->addRule('email', 'email')
    ->validate();

and then pass $model to your view.

A full example can be found in http://www.yiiframework.com/wiki/759/create-form-with-dynamicmodel/.

This is perfect for user input for calling APIs, creating forms on the fly, etc.



回答4:

As has been pointed out in the comments and other answers, your model needs to extend \yii\db\BaseActiveRecord. That said you can store your json as a nosql database such as MongoDb or in a key-value cache such as Redis instead. Both have Yii implementions: \yii\mongodb\ActiveRecord and \yii\redis\ActiveRecord



标签: php yii2