0

私はこのスキーマ構造を持っています:

  • レポート-> ID、予測
  • 予測-> id、user_id、ブリック、製品
  • ブリック-> ID、リージョン、プラン
  • プラン-> ID、エリア、ターゲット
  • ターゲット-> id、商品、valueA、valueB、コメント
  • コメント-> id、ターゲット、ユーザー、メッセージ、createdAt
  • 製品-> id、予測、ターゲット、valueC
  • リージョン-> ID、名前、ブリック
  • エリア-> ID、名前、プラン

そして、カスタム FormTypeでForecastを編集しています。

ForecastGrid タイプ:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('bricks', 'collection', array(
        'type' => 'forecast_grid_brick',
    ));

    $builder->add('products', 'collection', array(
        'type' => 'forecast_grid_product',
    ));
}

ForecastGridBrickType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('plans', 'collection', array(
        'type' => 'forecast_grid_plan',
    ));
}

ForecastGridProductType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('valueC', 'number', array(
            'autocomplete'  => false,
            'attr'          => array(
                'class' => 'grid-mini positive-integer'
            ),
        ));
}

ForecastGridPlanType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('targets', 'collection', array(
        'type' => 'forecast_grid_target',
    ));
}

ForecastGridTargetType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('valueA', 'number', array(
            'autocomplete'  => false,
            'attr'          => array(
                'class' => 'grid-mini positive-integer'
            )
        ))
        ->add('valueB', 'number', array(
            'autocomplete'  => false,
            'attr'          => array(
                'class' => 'grid-mini positive-integer'
            )
        ))
        ->add('comments', 'collection', array(
            'type'          => 'forecast_grid_comment',
            'allow_add'     => true,
            'allow_delete'  => false
        ));
}

ForecastGridCommentType:

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
        ->add('message', 'text', array(
            'autocomplete'  => false,
            'required'      => false,
            'attr'          => array(
                'class'       => 'grid-mini',
                'disabled'    => 'disabled',
            ),
        ));
}

もちろん、すべてのフォーム タイプはdata_class対応するクラスに設定されていますが、これをできるだけ短くするために他のメソッドは含めませんでした。

フォームの作成と表示は問題ではなく、symfony はすばやく処理します (0.5 秒未満)。問題は、フォームを送信するときです。

public function updateAction($id)
{
    $forecast = $this->getDoctrine()
        ->getRepository('AcmeForecastBundle:Forecast')
        ->find($id);

    $this->checkCredentials('canEditForecastGrid(object)', $forecast);

    if (!$forecast) {
        throw new NotFoundHttpException("The Acme\ForecastBundle\Entity\Forecast with id $id can't be found");
    }

    $form = $this->createForm('forecast_grid', $forecast);

    $form->handleRequest($this->getRequest()); // this makes my server hang

    echo 'This part is never reached'; exit;
    if ($form->isValid()) {
        // etc

だから..私が持っているPOSTで:

[forecast_grid] => array(
    [products] => array(
        // contains 6 products each with 1 field: valueC, example below
        [0] => array(
            [valueC] => "X"
        )
    ),
    [bricks] => array(
        // contains 10 bricks, each with 1 field: plans, example below
        [0] => array(
            [plans] => array(
                // contains various amount of plans
                // some bricks have 2 plans, some have 30
                // all together there are approx 120 plans in the form
                [0] => array(
                    [targets] => array(
                        // contains 6 targets, 1 for each product
                        // each with 3 fields: valueA, valueB, comments, example:
                        [0] => array(
                             [valueA] = "Y",
                             [valueB] = "Z",
                             [comments] => array(
                                 // contains  1 or 0 comments,
                                 // only one (new) comment is submitted
                                 // existing comments don't need to be 
                                 // submitted becouse of "allow_delete" => false
                                 // option, example below:
                                 [0] => array(
                                     [message] => "My comment"
                                 )
))))))))

つまり、120 プラン x 6 ターゲット x 2 フィールド => 1440 フィールド、プラス 6 製品 x 1 フィールド = 6 フィールド、プラス (最大) 120 プラン x 6 ターゲット x 1 コメント = 720 フィールドがあります。

これにより、2166 個のフィールドが得られます。今は多すぎますか?

私はいくつかのテストを行い、10000 stdClasses を Instatiationg し、20 フィールドを割り当て、各フィールドで preg_match を実行しました...瞬時に。フレームワークがそれ以上のことを行うことは知っていますが、その量のフィールドは PHP にとって問題にはならないと思います。

max_execution_time エラー (symfony プロファイラーがありません :<) または apache2 がハングするだけの場合、デバッグは困難です。

致命的なエラー: 943 行目の (...)/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php で最大実行時間が 30 秒を超えました

私の質問は:

  • 一度に多くのフィールドを送信しようとするとエラーになります (symfony2 フォームコンポーネントは、そのようなタスクを処理するために構築されたことはありません)?
  • またはsymfony2問題なくそのフォームを処理する必要があります。つまり、エラーの根本は別の場所にあります(doctrine2 hydration?)..もしそうなら..それはどこにあり、それが事実であるかどうかをどのようにテストできますか?

一部の人々は、AJAX を使用して各計画 (6 つのターゲット) を個別に送信することを提案しました。あまり時間がないのでおそらくそうするでしょうが、それでも答えを知りたいと思います -> symfony2 フォームコンポーネントに既知のパフォーマンス制限はありますか?

4

1 に答える 1

2

多くのアプローチを検討およびテストした後、AJAX を使用して項目を 1 つずつ保存することにしました。2000 以上のフィールドを保存するアクション時間を 5 秒に短縮することができました (これは、symfony がどれだけの能力を持っているかを証明しています!)。パフォーマンスを改善する余地がまだあると思いますが、それを行うには、 :

  • 最大入力、最大実行時間、最大アップロード サイズなどの php.ini および apache2.conf 制限を非常に高い値に引き上げます。
  • 多くのOWASPルールを無効にします (さまざまな種類の攻撃に対するサーバーの保護を弱めます)
  • アプリケーション ロジックとデータベース スキーマを読みにくく、保守しにくいものに変更します (ただし、パフォーマンスは向上します)。
  • このような単純な機能の作業とテストに多くの時間を費やしています

私の結論は次のとおりです。それは可能ですが、手間をかける価値はありません。AJAXでそれを行う方が良いです。

質問に答えると、はい、限界があります。多くの変数に依存しますが、一般に、一度に 1000 以上のフィールドを保存しようとすると、問題が発生することが予想されます。

于 2013-08-29T09:31:18.900 に答える