1

私は現在自分のMVCを改善していますが、次のシナリオの適切な解決策を見つけることができません:ほとんどのモデルでは、いくつかの(別のモデルによってすでに検証されている)ユーザーベースの入力を使用しており、それらを渡す必要がありますもちろん、コントローラー(基本的にモデルに入力をどう処理するかを指示します)からさまざまなモデルまで。現時点では、すべてのユーザー入力をプロパティに入れています。

    foreach($this->properties as $property => $empty)
    {
        if(isset($_POST[$property]))
        {
            $this->properties[$property] = htmlspecialchars(trim($_POST[$property]));
        }
    }

最終的に、何かをするために新しいモデルが必要になったとき、私はそれを次のように呼びます。

    new view('calendar',$data,$this->properties);

そして最後に、モデルで入力/変数をモデルのプロパティに配置することで受け取ります…</ p>

class validation
{   

    public function __construct($values)
    {
        foreach($values as $property => $value)
        {
            $this->{$property} = $value;
        }
    }
}

そうすれば、変数がどこから来たのかを考える必要がなくなり(ユーザー入力が検証された後は、もう気になりません)、いつでもクリーンで読みやすいバージョンの$this->user_input

しかし、私はどういうわけか、これは最も簡単な方法ではなく、おそらく良い方法でもないと感じています。私が最も気になるのは、新しいクラス/モデルを作成するときは、常にモデルに入力を独自のプロパティに取り込むように指示する必要があり、新しいクラスを呼び出すときは常にパラメーターを渡す必要があることです。

コントローラーを親クラスにすることなく、新しいクラスが呼び出されたときにユーザーからこれらの変数を継承できる方法はありますか?それとも、コントローラーを親にするのに実際に意味がありますか?別のコントローラーがモデルを使用する場合、混乱するだろうと思います。

4

5 に答える 5

1

より良い解決策は、すべての入力をオブジェクトに格納することです。それを呼び出すだけdataです。各モデルはdataプロパティを持つことができます。コントローラが入力検証を完了した後、オブジェクトを最初のモデルに渡してそこに保存できます。その時点で、モデル間でオブジェクトを自由に渡すことができます。で値を変更する場合dataは、後でコントローラーオブジェクトをなどのメソッド呼び出しで更新する必要があります$this->data = $Model->GetData();

MVCパラダイムでは、モデルがコントローラーのプロパティにアクセスすることは賢明ではありません。コントローラは基本的にすべての通信を開始する必要があります。つまり、コントローラはデータを操作を行うモデルに渡し、次にコントローラはそのデータを要求してビューに配置します。コントローラーにデータを保持させ、モデルを直接操作することはお勧めできません。

于 2012-12-26T21:59:55.350 に答える
1

必要に応じて、ユーザー入力をシングルトンクラス(たとえば、UserRequestクラス)のプロパティに格納することが理にかなっている場合があります。

class UserRequest extends Singleton
{
    protected $userProperties;
    public function getUserProperties()
    {
        return $this->userProperties;
    }
    ...other methods...
}

ブートストラップまたはルーティングクラスで、ユーザー入力をキャプチャするときに、それらをRequestインスタンスに保存してから、すべてのコントローラーにこのプロパティを読み取る基本クラスを拡張させます。

class baseController
{
    protected $userProperties;
    public function __construct()
    {
        $this->userProperties = Request::getInstance()->getUserProperties();
    }
}

そうすれば、すべてのコントローラーがそれにアクセスできるようになり、キャプチャする必要があるのは1回だけです。

于 2012-12-26T21:46:00.560 に答える
1

私が最も気になるのは、新しいクラス/モデルを作成するときは、常にモデルに入力を独自のプロパティに取り込むように指示する必要があり、新しいクラスを呼び出すときは常にパラメーターを渡す必要があることです。

したがって、ここで2つの問題があるとしましょう。

  1. 各クラス定義ごとにプロパティを定義するための繰り返し。
  2. クラス作成ごとにパラメーターを渡します。

最も素朴で基本的な意味では、両方を回避することはできません。クラスに(少なくともどういうわけか)それが表すプロパティを教えないと、それはわかりません。2番目の点については多少似ていますが、データがクラスに設定されていない場合は機能しません。

したがって、これら2つを完全に防ぐことは技術的に不可能であるため、問題は、可能であれば、それをより快適にし、繰り返しを減らす方法です。

進むべき1つのルートは、これらすべてのオブジェクトを同じタイプにすることです。実は、これらは改良されたアレイにすぎませんね。

したがって、配列のインポートやプロパティの定義など、必要なすべてのコードを含む、拡張可能な基本クラスを自分で作成できます。

したがって、コードを1回記述して、必要な数のオブジェクトとさまざまな「タイプ」を作成するだけで済みます。

いくつかの例では、その仕事をする基本クラスを持つそのようなオブジェクトを1つ作成しましょう。

class TestModel extends SelfDefinedVariableObjectBase
{
    protected $properties = ['bar' => 'hello world'];
}

それだけです。オブジェクトが定義されています。それを使用しましょう:

// $_POST['bar'] = '<h1>test</h1> let\'s throw some HTML in';

$foo = new TestModel($_POST);
echo $foo->bar, "\n";

$_POSTこれは、オブジェクトのプロパティと一致するデータをインポートします(あなたが持っているものと同様です)。ただし、出力は同じです。

<h1>test</h1> let's throw some HTML in

あなたは今それが欲しいかもしれません。したがって、たとえば、コールバック関数で動作するデコレータを作成できます。

class VariableObjectCallbackDecorator
{
    private $subject;
    private $callback;

    public function __construct(VariableObjectBase $object, callable $callback) {
        $this->subject = $object;
        $this->callback = $callback;
    }
    public function __get($name) {
        return call_user_func($this->callback, $this->subject->__get($name));
    }
}

前の例のテストオブジェクトで使用してみましょう。

$bar = new VariableObjectCallbackDecorator($foo, 'htmlspecialchars');
echo $bar->bar, "\n";

そして今度は出力は次のとおりです。

&lt;h1&gt;test&lt;/h1&gt; let's throw some HTML in

これがお役に立てば幸いです。あなたはここでコードを見つけることができます:デモ

于 2012-12-28T13:55:42.130 に答える
1

ここで覚えておくべき重要なことは、コントローラーが変数コンテナーである(または「である」)のとは対照的に、コントローラーに「変数コンテナー」(すべてのプロパティを保持する)があるということです。したがって、まず、継承ではなく、合成を使用する必要があります。

以下のスニペットは、より詳細に説明するためにコメント化されています。いくつかのメモ:

  • InputDataインスタンスは、質問の主要部分に答えるコントローラーレベルより上に作成できます(たとえば、別のコントローラーで作成できるため、多くのコントローラー間で共有できます)。重要なのは、一度だけ書いているということです。そこに入れたら、安全に言うことができます。

  • InputDataの役割はデータを安全に格納/保存することであるため、すべての検証メソッドをInputData内に含めることができます。これは、私の意見では、適切なレベルの抽象化です。入力データ、どこを見ればいいかわかります」

  • 最後に、少し余分な輝きを与えるために、いくつかのビット演算を追加して、input_data-> addを介して値を追加するときに、複数の型に対して検証できるようにしました(たとえば、数値と投稿の両方として検証する必要がある何かを追加できます)コード)。

index.php

require_once( "Controller.php" );

$controller = new Controller();
$controller->print_current_user();

Controller.php

<?
require_once( "Input_Data.php" );

class Controller 
{
    // Variables    
    private $input_data;

    // Models
    // private $model_user;

    public function __construct() 
    {
        $this->input_data = new Input_Data();
        //$this->model_user = new Model_User();

        // Process input (might not happen in the constructor,
        // in fact, it might happen higher up, so it can be shared

        // Possibly looping over GET / POST data
        // for each one, add it to the inputData
        $_GET[ 'name' ] = 'Chris';
        $_GET[ 'country' ] = 'Australia';        

        // example iteration 1        
        $this->input_data->add( 'name', $_GET[ 'name' ], Input_Data::TYPE_VALIDATE_NAME | Input_Data::TYPE_VALIDATE_TEXT );
        // example iteration 2
        $this->input_data->add( 'country', $_GET[ 'country' ], Input_Data::TYPE_VALIDATE_COUNTRY );
    }

    // later on in controller, model needs to find the user by name
    public function print_current_user() 
    {
        // Example Usage to Model:
        // $this->$model_user->get_by_name( $this->input_data->get( 'name' ) );
        //
        // For now, we'll settle with just printing it out
        echo $this->input_data->get( 'name' );
    }
}
?>

入力データ

<?
class Input_Data 
{
    const TYPE_VALIDATE_TEXT = 0;
    const TYPE_VALIDATE_NAME = 1;
    const TYPE_VALIDATE_EMAIL = 2;
    const TYPE_VALIDATE_ADDRESS = 4;
    const TYPE_VALIDATE_COUNTRY = 8;

    protected $data;

    public function __construct() {
        $this->data = array();
    }

    public function add( $name, $value, $type )
    {
        if( $type & TYPE_VALIDATE_TEXT )        
        {
            // validate input as text
            // if valid, flag as such, to be inserted
            // or alternatively return a safe version
            // depending on your application, an empty string
        }    
        if( $type & TYPE_VALIDATE_NAME )        
        {
            // validate input as name
        }
        if( $type & TYPE_VALIDATE_EMAIL )        
        {
            // validate input as email
        }    
        if( $type & TYPE_VALIDATE_ADDRESS )        
        {
            // validate input as address
        }    
        if( $type & TYPE_VALIDATE_COUNTRY )        
        {
            // validate input as country
        }    

        // If its valid or is now santised
        // insert into the $data variable
        // if( $valid ) {
        $this->data[ $name ] = $value;
        // }
        // data[ name ] now contains a safe value that can be accessed
    }

    public function get( $name )
    {
        // do checking to ensure it exists
        // then return it
        return $this->data[ $name ];
    }
}
?>
于 2013-01-01T12:45:41.150 に答える
-1

これは、コントローラーを親にするのに実際に意味がありますか?

はい、それはおそらく私がそれを行う方法とまったく同じです。次に、共有/継承するプロパティに保護を使用できます。

于 2012-12-22T17:41:47.300 に答える