0

初めてフェッチされたときにメッセージを「フラッシュ」する一種のフラッシュメッセージクラスを作成しようとしています。したがって、次の HTTP 要求では、たとえば、あるコントローラー アクションから別の (同じ HTTP 要求の) コントローラー アクションに転送される場合は、そうではありません。

これが私のクラスの設計です:

<?php
namespace MartynBiz;

/**
 * Flash messages. Slight variation in that this will store a message until it
 * is accessed - whether that is a next http request, or same request. Simply
 * when get method is called the message is wiped from session.
 * TODO move this to martynbiz\php-flash
 */
class Flash
{
    /**
     * Message storage
     *
     * @var ArrayObject
     */
    protected $storage;

    /**
     * @param string $storage Name to store messages in session
     */
    public function __construct($storage=null)
    {
        // if storage is not defined, create ArrayObject (not persistent)
        if (is_null($storage)) {
            $storage = new \ArrayObject();
        }

        $this->storage = $storage;
    }

    /**
     * Add flash message
     *
     * @param string $key The key to store the message under
     * @param string $message Message to show on next request
     */
    public function addMessage($key, $message)
    {
        // create entry in the session
        $this->storage[$key] = $message;
    }

    /**
     * Get flash messages, and reset storage
     * @return array Messages to show for current request
     */
    public function flushMessages()
    {
        $messages = $this->storage->getArrayCopy();

        // clear storage items
        foreach ($this->storage as $key => $value) {
            unset($this->storage[$key]);
        }

        return $messages;
    }
}

Flash クラスの使用方法を示す PHPUnit テストをいくつか作成しました。

<?php

// TODO test with an ArrayAccess/Object $storage passed in

use MartynBiz\Flash;
use Zend\Session\Container;

class FlashTest extends PHPUnit_Framework_TestCase
{
    protected $flash;

    public function testInstantiation()
    {
        $flash = new Flash();

        $this->assertTrue($flash instanceof Flash);
    }

    public function testGettingSetting()
    {
        $flash = new Flash();

        $flash->addMessage('key1', 'value1');
        $flash->addMessage('key2', 'value2');
        $flash->addMessage('key2', 'value3');

        $expected = array(
            'key1' => 'value1',
            'key2' => 'value3',
        );

        // assert first time to access messages
        $messages = $flash->flushMessages();
        $this->assertEquals($expected, $messages);

        // assert messages have been cleared
        $messages = $flash->flushMessages();
        $this->assertEquals(array(), $messages);
    }

    public function testCustomStorage()
    {
        $container = new Container('mycontainer');
        $flash = new Flash($container);

        $flash->addMessage('key1', 'value1');

        $expected = array(
            'key1' => 'value1',
        );

        // assert first time to access messages
        $messages = $flash->flushMessages();
        $this->assertEquals($expected, $messages);

        // assert messages have been cleared
        $messages = $flash->flushMessages();
        $this->assertEquals(array(), $messages);
    }
}

カスタムの $storage (Zend セッション コンテナー インスタンス) も渡していることがわかりますが、これは私が希望するオプションの 1 つです。これらのテストはパスしているように見えますが、他のテストでは次のエラーが発生し、問題の内容がよくわかりません。

$ ./vendor/bin/phpunit tests/library/FlashTest.php 1
PHPUnit 4.8.21-4-g7f07877 by Sebastian Bergmann and contributors.

.E.

Time: 68 ms, Memory: 4.50Mb

There was 1 error:

1) FlashTest::testGettingSetting
MartynBiz\Flash::flushMessages(): ArrayIterator::next(): Array was modified outside object and internal position is no longer valid

/var/www/crsrc-slimmvc/app/library/MartynBiz/Flash/Flash.php:53
/var/www/crsrc-slimmvc/tests/library/FlashTest.php:33

FAILURES!
Tests: 3, Assertions: 3, Errors: 1.

このエラーを探し回り、いくつかの代替手段 ( $this->storage->getIterator() など) を試しましたが、それでも同じエラーが発生します。私が間違っているアイデアはありますか?私はArrayObjectに少し慣れていないと思います。

4

0 に答える 0