Я пытаюсь создать своего рода класс флеш-сообщений, который будет «сбрасывать» сообщения при первой их загрузке. Так что не при следующем 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;
}
}
Я написал несколько тестов PHPUnit, которые также демонстрируют, как можно использовать класс Flash:
<?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);
}
}
Вы можете видеть, что я также передаю пользовательское хранилище $ (экземпляр контейнера сеанса Zend), которое мне бы хотелось. Эти тесты, кажется, проходят, однако я получаю следующую ошибку на других, и я не совсем понимаю, в чем проблема:
$ ./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.
Задача ещё не решена.
Других решений пока нет …