Radovan Černý
News on Facebook

Model and View

for your pure PHP projects

Motivation

In the past I was asked to help with a WordPress project. In WordPress one does not code much, but they created their own theme with many PHP files containing forms which were to be completed by users and then sent via SOAP to an external server. Nice idea, but the implementation was reminding me of late 90s ...

Why? ... Check this nightmare: PHP files with 2000 rows combining HTML, PHP, JS and CSS. No signs of OOP, not even methods, one long spaghetti code, tons of repeated code and many useless, badly named or unused variables. No real data validation, only a simple validation in JavaScript which is not enought - a backend programmer must NOT rely on JavaScript. JavaScript was used to do much of the logic (redirection, inserting values into inputs by echoing <script> tags etc) ... while these things can be done directly by PHP.

I was truly shocked when I saw what software can be delivered to customers in year 2020. So I said STOP! This must be optimised as many problems were arising from the chaos in the code and I didn't want to debug and fix this mess.

Inspiration

Resulting model handling

The result is simple, but powerfull. Check following snippet:

$model = new MyForm();
$model->setScenario(MyForm::SCENARIO_UPDATE_DATA_ADMIN);
if (isset($_POST['submit'])) {

  // Note that all the inputs have names like this: name="MyForm[attribute]"
  $model->setAttributes($_POST['MyForm']);
  $valid = $model->validate();
  if ($valid) {
    // send to SOAP
    return;
  }
   // else continue and render the form again with automated error messages ...
}

// This method was copied from the Yii framework and only slightly modififed
echo renderPhpFile('MyFormView', [
      'model' => $model,
]);

Resulting view handling

echo $model->beginForm();

$isTestedScenario = $model->hasScenario(MyForm::SCENARIO_UPDATE_DATA_ADMIN);

if ($isTestedScenario) {
  echo $model->getInput('password', [
    'placeholder' => 'Enter a new pasword',
    'type' => 'password',
  ]);
  echo $model->getInput('passwordRepeat', [
    'placeholder' => 'Repeat the new pasword',
    'type' => 'password',
  ]);
}

echo $model->getInput('email', [
  'enabled' => $isTestedScenario,
  'placeholder' => 'Enter your email adress',
]);

echo $model->getInput('name', ['placeholder' => 'Enter your name']);

echo $model->getSelect('state',MyForm::getListOfStates(), [
  'class' => 'form-control',
]);

echo $model->getCheckbox('iAgreeWithAllRules')

echo '<button type="submit" value="submit" name="submit">Submit</button>';

echo $model->endForm();

Class MyForm

All the important rules are defined in class MyForm. These rules are used for both PHP and JS validation. Scenarios help us to use different rules in different situations. Currently 3 basic validators are supported: regex, compare and boolean.

class MyForm extends Model {

  const SCENARIO_UPDATE_DATA_ADMIN = 1;

  public $password;
  public $paswordRepeat;
  public $email;
  public $name;
  public $state;
  public $iAgreeWithAllRules;

  public static function getListOfStates() {
    return [
        '' => 'no state',
        '1' => 'Alabama',
        '2' => 'Alaska',
        '3' => 'Arizona',
        // ...
    ];
  }

  public function rules() {
    if ($this->scenario === self::SCENARIO_UPDATE_DATA_ADMIN) {
      return [
        [['password', 'paswordRepeat', 'email', 'name', 'state', 'iAgreeWithAllRules'], 'required'],
        ['password', 'match', 'pattern' => '/ some regular expression /', 'message'=> 'Invalid password'],
        ['paswordRepeat', 'compare', 'operator' => '==', 'compareAttribute' => 'password'],
        ['name, 'match', 'pattern' => '/ some regular expression /, 'message'=>'Invalid name'],
        ['email, 'match', 'pattern' => '/ some regular expression /, 'message'=>'Invalid email'],
        ['state, 'match', 'pattern' => '/^[0-9]+$/, 'message'=>'Invalid state'], 
        ['iAgreeWithAllRules', 'boolean'],
      ];
    }
    return [];
  }
}

Are you interested?

Feel free to contact me.

Contact