Gii CRUD generation problem with spaces in field names

I have a PostgreSQL database with spaces in both table names and field names. I have no control over this database structure. Here’s an example:

CREATE TABLE "public"."MILESTONES 4 FORM TABLE" (

"Estimate ID" varchar(250) NOT NULL DEFAULT 'None'::character varying COLLATE "default",


"MS 4 Name" varchar(100) NOT NULL COLLATE "default",


"MS 4 Begin" varchar(50) COLLATE "default",


"MS 4 End" varchar(50) COLLATE "default",


"MS 4 Weight" float4 DEFAULT 0.0,


"MS 4 % Oct" float4 DEFAULT 0.0,


"MS 4 % Nov" float4 DEFAULT 0.0,

…the other months here… deleted for brevity

"MS 4 % Sep" float4 DEFAULT 0.0,


"Change Control Choice" varchar(50) COLLATE "default",


"CV% MS Oct Cum" varchar(50) COLLATE "default",


"SV% MS Oct Cum" varchar(50) COLLATE "default",


"CV% MS NOV Cum" varchar(50) COLLATE "default",


"SV% MS NOV Cum" varchar(50) COLLATE "default",

…the other months here… deleted for brevity

"CV% MS Sep Cum" varchar(50) COLLATE "default",


"SV% MS Sep Cum" varchar(50) COLLATE "default"

);

Gii generated the following for the model (I had to comment out the @property declarations because PHPStorm marked each as an error for some reason):




<?php


namespace app\models;


use Yii;


/**

 * This is the model class for table "MILESTONES 4 FORM TABLE".

 *

//* @property string $Estimate ID

//* @property string $MS 4 Name

//* @property string $MS 4 Begin

//* @property string $MS 4 End

//* @property double $MS 4 Weight

//* @property double $MS 4 % Oct

//* @property double $MS 4 % Nov

...deleted for brevity

//* @property double $MS 4 % Sep

//* @property string $Change Control Choice

//* @property string $CV% MS Oct Cum

//* @property string $SV% MS Oct Cum

...deleted for brevity...

//* @property string $CV% MS Sep Cum

//* @property string $SV% MS Sep Cum

 */

class Milestone4AR extends \yii\db\ActiveRecord

{

    /**

     * @inheritdoc

     */

    public static function tableName()

    {

        return 'MILESTONES 4 FORM TABLE';

    }


    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['Estimate ID', 'MS 4 Name'], 'required'],

            [['MS 4 Weight', 'MS 4 % Oct', 'MS 4 % Nov', 'MS 4 % Dec', 'MS 4 % Jan', 'MS 4 % Feb', 'MS 4 % Mar', 'MS 4 % Apr', 'MS 4 % May', 'MS 4 % Jun', 'MS 4 % Jul', 'MS 4 % Aug', 'MS 4 % Sep'], 'number'],

            [['Estimate ID'], 'string', 'max' => 250],

            [['MS 4 Name'], 'string', 'max' => 100],

            [['MS 4 Begin', 'MS 4 End', 'Change Control Choice', 'CV% MS Oct Cum', 'SV% MS Oct Cum', 'CV% MS NOV Cum', 'SV% MS NOV Cum', 'CV% MS Dec Cum', 'SV% MS Dec Cum', 'CV% MS Jan Cum', 'SV% MS Jan Cum', 'CV% MS Feb Cum', 'SV% MS Feb Cum', 'CV% MS Mar Cum', 'SV% MS Mar Cum', 'CV% MS Apr Cum', 'SV% MS Apr Cum', 'CV% MS May Cum', 'SV% MS May Cum', 'CV% MS Jun Cum', 'SV% MS Jun Cum', 'CV% MS Jul Cum', 'SV% MS Jul Cum', 'CV% MS Aug Cum', 'SV% MS Aug Cum', 'CV% MS Sep Cum', 'SV% MS Sep Cum'], 'string', 'max' => 50],

        ];

    }


    /**

     * @inheritdoc

     */

    public function attributeLabels()

    {

        return [

            'Estimate ID' => 'Estimate  ID',

            'MS 4 Name' => 'Ms 4  Name',

            'MS 4 Begin' => 'Ms 4  Begin',

            'MS 4 End' => 'Ms 4  End',

            'MS 4 Weight' => 'Ms 4  Weight',

            'MS 4 % Oct' => 'Ms 4 %  Oct',

            'MS 4 % Nov' => 'Ms 4 %  Nov',

...deleted for brevity...

            'MS 4 % Aug' => 'Ms 4 %  Aug',

            'MS 4 % Sep' => 'Ms 4 %  Sep',

            'Change Control Choice' => 'Change  Control  Choice',

            'CV% MS Oct Cum' => 'Cv%  Ms  Oct  Cum',

            'SV% MS Oct Cum' => 'Sv%  Ms  Oct  Cum',

...deleted for brevity...

            'CV% MS Sep Cum' => 'Cv%  Ms  Sep  Cum',

            'SV% MS Sep Cum' => 'Sv%  Ms  Sep  Cum',

        ];

    }

}

I then used Gii to generate the CRUD code from the model. You can see the problem with the $query->andFilterWhere section.

For example, … andFilterWhere([‘like’, ‘MS 4 Name’, $this->MS 4 Name]) will not parse.

What have I done wrong, and how can I fix it?

This isn’t production code (yet) so I can easily blow away what I’ve already done, but I can’t alter the original database table structure (boy, do I wish I could! I really dislike working on legacy code). I have over 100 tables using this same naming convention, so need a fix that can be applied over all of them.


<?php


namespace app\models;


use Yii;

use yii\base\Model;

use yii\data\ActiveDataProvider;

use app\models\Milestone4AR;


/**

 * Milestone4Search represents the model behind the search form about `app\models\Milestone4AR`.

 */

class Milestone4Search extends Milestone4AR

{

    /**

     * @inheritdoc

     */

    public function rules()

    {

        return [

            [['Estimate ID', 'MS 4 Name', 'MS 4 Begin', 'MS 4 End', 'Change Control Choice', 'CV% MS Oct Cum', 'SV% MS Oct Cum', 'CV% MS NOV Cum', 'SV% MS NOV Cum', 'CV% MS Dec Cum', 'SV% MS Dec Cum', 'CV% MS Jan Cum', 'SV% MS Jan Cum', 'CV% MS Feb Cum', 'SV% MS Feb Cum', 'CV% MS Mar Cum', 'SV% MS Mar Cum', 'CV% MS Apr Cum', 'SV% MS Apr Cum', 'CV% MS May Cum', 'SV% MS May Cum', 'CV% MS Jun Cum', 'SV% MS Jun Cum', 'CV% MS Jul Cum', 'SV% MS Jul Cum', 'CV% MS Aug Cum', 'SV% MS Aug Cum', 'CV% MS Sep Cum', 'SV% MS Sep Cum'], 'safe'],

            [['MS 4 Weight', 'MS 4 % Oct', 'MS 4 % Nov', 'MS 4 % Dec', 'MS 4 % Jan', 'MS 4 % Feb', 'MS 4 % Mar', 'MS 4 % Apr', 'MS 4 % May', 'MS 4 % Jun', 'MS 4 % Jul', 'MS 4 % Aug', 'MS 4 % Sep'], 'number'],

        ];

    }


    /**

     * @inheritdoc

     */

    public function scenarios()

    {

        // bypass scenarios() implementation in the parent class

        return Model::scenarios();

    }


    /**

     * Creates data provider instance with search query applied

     *

     * @param array $params

     *

     * @return ActiveDataProvider

     */

    public function search($params)

    {

        $query = Milestone4AR::find();


        // add conditions that should always apply here


        $dataProvider = new ActiveDataProvider([

            'query' => $query,

        ]);


        $this->load($params);


        if (!$this->validate()) {

            // uncomment the following line if you do not want to return any records when validation fails

            // $query->where('0=1');

            return $dataProvider;

        }


        // grid filtering conditions

        $query->andFilterWhere([

            'MS 4 Weight' => $this->'MS 4 Weight',

            'MS 4 % Oct' => $this->'MS 4 % Oct',

            'MS 4 % Nov' => $this->'MS 4 % Nov',

 ...deleted for brevity...

          'MS 4 % Jul' => $this->'MS 4 % Jul',

            'MS 4 % Aug' => $this->'MS 4 % Aug',

            'MS 4 % Sep' => $this->'MS 4 % Sep',

        ]);


        $query->andFilterWhere(['like', 'Estimate ID', $this->Estimate ID])

            ->andFilterWhere(['like', 'MS 4 Name', $this->MS 4 Name])

            ->andFilterWhere(['like', 'MS 4 Begin', $this->MS 4 Begin])

            ->andFilterWhere(['like', 'MS 4 End', $this->MS 4 End])

            ->andFilterWhere(['like', 'Change Control Choice', $this->Change Control Choice])

            ->andFilterWhere(['like', 'CV% MS Oct Cum', $this->CV% MS Oct Cum])

            ->andFilterWhere(['like', 'SV% MS Oct Cum', $this->SV% MS Oct Cum])

            ->andFilterWhere(['like', 'CV% MS NOV Cum', $this->CV% MS NOV Cum])

            ->andFilterWhere(['like', 'SV% MS NOV Cum', $this->SV% MS NOV Cum])

            ->andFilterWhere(['like', 'CV% MS Dec Cum', $this->CV% MS Dec Cum])

 ...deleted for brevity...

            ->andFilterWhere(['like', 'CV% MS Aug Cum', $this->CV% MS Aug Cum])

            ->andFilterWhere(['like', 'SV% MS Aug Cum', $this->SV% MS Aug Cum])

            ->andFilterWhere(['like', 'CV% MS Sep Cum', $this->CV% MS Sep Cum])

            ->andFilterWhere(['like', 'SV% MS Sep Cum', $this->SV% MS Sep Cum]);


        return $dataProvider;

    }

}