├── .gitignore ├── Resources ├── examples │ └── Application │ │ ├── Resources │ │ ├── views │ │ │ ├── Guestbook │ │ │ │ ├── sign.html.phtml │ │ │ │ └── index.html.phtml │ │ │ └── layout.html.phtml │ │ └── config │ │ │ ├── routing.yml │ │ │ └── routing.ini │ │ ├── Model │ │ ├── DbTable │ │ │ └── Guestbook.php │ │ ├── Guestbook.php │ │ └── GuestbookMapper.php │ │ ├── ApplicationBundle.php │ │ ├── Controller │ │ └── GuestbookController.php │ │ └── Form │ │ └── Guestbook.php ├── views │ └── layout.html.phtml └── config │ └── compat.xml ├── Tests ├── phpunit.dist.xml ├── Router │ └── Loader │ │ ├── fixtures │ │ └── routes.ini │ │ └── ZFRouterLoaderTest.php ├── TestInit.php ├── View │ └── ZendViewEngineTest.php └── Controller │ └── RouteNameParserTest.php ├── Controller ├── Helpers │ ├── ContextSwitch.php │ ├── ViewRenderer.php │ ├── Layout.php │ ├── HelperBroker.php │ ├── Helper.php │ ├── UrlHelper.php │ ├── Redirector.php │ └── FlashMessenger.php ├── CatchAllRequestListener.php ├── ZendResponse.php ├── RouteNameParser.php ├── ZendController.php └── ZendRequest.php ├── WhitewashingZFMvcCompatBundle.php ├── View ├── ParameterBag.php ├── View1.php ├── CoreViewListener.php └── ZendViewEngine.php ├── DependencyInjection └── WhitewashingZFMvcCompatExtension.php ├── Router └── Loader │ └── ZFRouterLoader.php └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | Tests/phpunit.xml 2 | -------------------------------------------------------------------------------- /Resources/examples/Application/Resources/views/Guestbook/sign.html.phtml: -------------------------------------------------------------------------------- 1 | Please use the form below to sign our guestbook! 2 | 3 | form->setAction($this->url()); 5 | echo $this->form->__toSTring(); -------------------------------------------------------------------------------- /Resources/examples/Application/Model/DbTable/Guestbook.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Resources/views/layout.html.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Zend Framework Compatibility Bundle Start 5 | 6 | 7 | 8 | content; ?> 9 | 10 | -------------------------------------------------------------------------------- /Resources/examples/Application/Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | zfmvccompat_guestbook_homepage: 2 | pattern: /zfguestbook 3 | defaults: { _controller: "ApplicationBundle:Guestbook:index" } 4 | 5 | zfmvccompat_guestbook_sign: 6 | pattern: /zfguestbook/sign 7 | defaults: { _controller: "ApplicationBundle:Guestbook:sign" } -------------------------------------------------------------------------------- /Tests/Router/Loader/fixtures/routes.ini: -------------------------------------------------------------------------------- 1 | [routes] 2 | routes.archive.route = "archive/:year/*" 3 | routes.archive.defaults.controller = archive 4 | routes.archive.defaults.action = show 5 | routes.archive.defaults.year = 2000 6 | routes.archive.reqs.year = "\d+" 7 | 8 | routes.news.type = "Zend_Controller_Router_Route_Static" 9 | routes.news.route = "news" 10 | routes.news.defaults.controller = "news" 11 | routes.news.defaults.action = "list" -------------------------------------------------------------------------------- /Resources/examples/Application/Resources/views/Guestbook/index.html.phtml: -------------------------------------------------------------------------------- 1 |

Sign Our Guestbook

5 | 6 | Guestbook Entries:
7 |
8 | entries as $entry): ?> 9 |
escape($entry->email) ?>
10 |
escape($entry->comment) ?>
11 | 12 |
-------------------------------------------------------------------------------- /Resources/examples/Application/Resources/config/routing.ini: -------------------------------------------------------------------------------- 1 | [routes] 2 | zfmvccompat_guestbook_homepage.route = "zfguestbook" 3 | zfmvccompat_guestbook_homepage.defaults.module = "Application" 4 | zfmvccompat_guestbook_homepage.defaults.controller = "Guestbook" 5 | zfmvccompat_guestbook_homepage.defaults.action = "index" 6 | 7 | zfmvccompat_guestbook_sign.route = "zfguestbook/sign" 8 | zfmvccompat_guestbook_sign.defaults.module = "Application" 9 | zfmvccompat_guestbook_sign.defaults.controller = "Guestbook" 10 | zfmvccompat_guestbook_sign.defaults.action = "sign" 11 | -------------------------------------------------------------------------------- /Resources/examples/Application/ApplicationBundle.php: -------------------------------------------------------------------------------- 1 | load("routes.ini"); 15 | 16 | $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('archive')); 17 | $this->assertInstanceOf('Symfony\Component\Routing\Route', $collection->get('news')); 18 | } 19 | } -------------------------------------------------------------------------------- /Resources/examples/Application/Resources/views/layout.html.phtml: -------------------------------------------------------------------------------- 1 | doctype() ?> 2 | 3 | 4 | 5 | Zend Framework Quickstart Application 6 | 7 | 8 | 19 | 20 | content ?> 21 | 22 | 23 | -------------------------------------------------------------------------------- /Resources/examples/Application/Controller/GuestbookController.php: -------------------------------------------------------------------------------- 1 | view->entries = $guestbook->fetchAll(); 12 | } 13 | 14 | public function signAction() 15 | { 16 | $request = $this->getRequest(); 17 | $form = new \Application_Form_Guestbook(); 18 | 19 | if ($this->getRequest()->isPost()) { 20 | if ($form->isValid($request->getPost())) { 21 | $comment = new \Application_Model_Guestbook($form->getValues()); 22 | $mapper = new \Application_Model_GuestbookMapper(); 23 | $mapper->save($comment); 24 | return $this->_helper->redirector('index'); 25 | } 26 | } 27 | 28 | $this->view->form = $form; 29 | } 30 | } -------------------------------------------------------------------------------- /Controller/Helpers/ViewRenderer.php: -------------------------------------------------------------------------------- 1 | noRender = (bool)$flag; 29 | return $this; 30 | } 31 | 32 | public function getNoRender() 33 | { 34 | return $this->noRender || self::$neverRender; 35 | } 36 | 37 | public function setNeverRender($flag = true) 38 | { 39 | self::$neverRender = (bool)$flag; 40 | return $this; 41 | } 42 | } -------------------------------------------------------------------------------- /WhitewashingZFMvcCompatBundle.php: -------------------------------------------------------------------------------- 1 | container->has('whitewashing.zfmvcompat.db')) { 23 | \Zend_Db_Table::setDefaultAdapter($this->container->get('whitewashing.zfmvcompat.db')); 24 | } 25 | 26 | $refl = new \ReflectionClass('Zend_Session'); 27 | $vars = array('_sessionStarted', '_readable', '_writable'); 28 | foreach ($vars AS $var) { 29 | $property = $refl->getProperty($var); 30 | $property->setAccessible(true); 31 | $property->setValue(null, true); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /View/ParameterBag.php: -------------------------------------------------------------------------------- 1 | $v) { 24 | $this->assign($k, $v); 25 | } 26 | } else { 27 | $this->params[$spec] = $value; 28 | } 29 | } 30 | 31 | public function clearVars() 32 | { 33 | $this->params = array(); 34 | return $this; 35 | } 36 | 37 | public function __isset($offset) 38 | { 39 | return isset($this->params[$offset]); 40 | } 41 | 42 | public function __get($offset) 43 | { 44 | return $this->params[$offset]; 45 | } 46 | 47 | public function __set($offset, $value) 48 | { 49 | $this->params[$offset] = $value; 50 | } 51 | 52 | public function __unset($offset) 53 | { 54 | unset($this->params[$offset]); 55 | } 56 | 57 | public function allVars() 58 | { 59 | return $this->params; 60 | } 61 | } -------------------------------------------------------------------------------- /Controller/Helpers/Layout.php: -------------------------------------------------------------------------------- 1 | layout = $defaultLayoutResource; 25 | } 26 | 27 | public function disableLayout() 28 | { 29 | $this->enabled = false; 30 | return $this; 31 | } 32 | 33 | public function enableLayout() 34 | { 35 | $this->enabled = true; 36 | return $this; 37 | } 38 | 39 | public function setLayout($resource, $enable) 40 | { 41 | $this->layout = $resource; 42 | if ($enable) { 43 | $this->enabled = true; 44 | } 45 | return $this; 46 | } 47 | 48 | public function getLayout() 49 | { 50 | return $this->layout; 51 | } 52 | 53 | public function isEnabled() 54 | { 55 | return $this->enabled; 56 | } 57 | 58 | public function getName() 59 | { 60 | return 'layout'; 61 | } 62 | 63 | public function direct() 64 | { 65 | return $this; 66 | } 67 | } -------------------------------------------------------------------------------- /Resources/examples/Application/Form/Guestbook.php: -------------------------------------------------------------------------------- 1 | setMethod('post'); 8 | 9 | // Add an email element 10 | $this->addElement('text', 'email', array( 11 | 'label' => 'Your email address:', 12 | 'required' => true, 13 | 'filters' => array('StringTrim'), 14 | 'validators' => array( 15 | 'EmailAddress', 16 | ) 17 | )); 18 | 19 | // Add the comment element 20 | $this->addElement('textarea', 'comment', array( 21 | 'label' => 'Please Comment:', 22 | 'required' => true, 23 | 'validators' => array( 24 | array('validator' => 'StringLength', 'options' => array(0, 20)) 25 | ) 26 | )); 27 | 28 | // Add a captcha 29 | $this->addElement('captcha', 'captcha', array( 30 | 'label' => 'Please enter the 5 letters displayed below:', 31 | 'required' => true, 32 | 'captcha' => array( 33 | 'captcha' => 'Figlet', 34 | 'wordLen' => 5, 35 | 'timeout' => 300 36 | ) 37 | )); 38 | 39 | // Add the submit button 40 | $this->addElement('submit', 'submit', array( 41 | 'ignore' => true, 42 | 'label' => 'Sign Guestbook', 43 | )); 44 | 45 | // And finally add some CSRF protection 46 | $this->addElement('hash', 'csrf', array( 47 | 'ignore' => true, 48 | )); 49 | } 50 | } -------------------------------------------------------------------------------- /Tests/TestInit.php: -------------------------------------------------------------------------------- 1 | registerNamespaces(array( 18 | 'Symfony' => $GLOBALS['SYMFONY2_SRC'], 19 | )); 20 | $loader->registerPrefixes(array( 21 | 'Zend_' => $GLOBALS['ZF1_LIB'], 22 | )); 23 | $loader->register(); 24 | 25 | $files = array( 26 | "../View/CoreViewListener.php", 27 | "../View/ParameterBag.php", 28 | "../View/View1.php", 29 | "../View/ZendViewEngine.php", 30 | "../WhitewashingZFMvcCompatBundle.php", 31 | "../DependencyInjection/WhitewashingZFMvcCompatExtension.php", 32 | "../Router/Loader/ZFRouterLoader.php", 33 | "../Controller/ZendController.php", 34 | "../Controller/ZendRequest.php", 35 | "../Controller/ZendResponse.php", 36 | "../Controller/RouteNameParser.php", 37 | "../Controller/CatchAllRequestListener.php", 38 | "../Controller/Helpers/Helper.php", 39 | "../Controller/Helpers/HelperBroker.php", 40 | "../Controller/Helpers/Layout.php", 41 | "../Controller/Helpers/ContextSwitch.php", 42 | "../Controller/Helpers/Redirector.php", 43 | "../Controller/Helpers/UrlHelper.php", 44 | "../Controller/Helpers/ViewRenderer.php", 45 | ); 46 | 47 | foreach ($files AS $file) { 48 | require_once($file); 49 | } -------------------------------------------------------------------------------- /Controller/CatchAllRequestListener.php: -------------------------------------------------------------------------------- 1 | parser = $parser; 30 | $this->enabledBundles = $enabledBundles; 31 | } 32 | 33 | public function resolve(GetResponseEvent $event) 34 | { 35 | $request = $event->getRequest(); 36 | 37 | if ($request->attributes->has('_controller')) { 38 | return; 39 | } 40 | 41 | $url = $request->getPathInfo(); 42 | 43 | $parts = explode('/', $url); 44 | if (count($parts) < 4) { 45 | return; 46 | } 47 | 48 | $bundle = sprintf('%sBundle', $this->parser->formatModule($parts[1])); 49 | 50 | if (!in_array($bundle, $this->enabledBundles)) { 51 | return; 52 | } 53 | 54 | $controllerName = sprintf( 55 | '%s:%s:%s', 56 | $bundle, 57 | $this->parser->formatController($parts[2]), 58 | $parts[3] 59 | ); 60 | 61 | $request->attributes->add(array('_controller'=> $controllerName)); 62 | } 63 | } -------------------------------------------------------------------------------- /Controller/Helpers/HelperBroker.php: -------------------------------------------------------------------------------- 1 | get($helper); 37 | $helper->setActionController($controller); 38 | $this->helpers[$helper->getName()] = $helper; 39 | } 40 | } 41 | 42 | public function __get($helper) 43 | { 44 | return $this->getHelper($helper); 45 | } 46 | 47 | public function getHelper($name) 48 | { 49 | $name = strtolower($name); 50 | if (!isset($this->helpers[$name])) { 51 | throw new \RuntimeException("No Zend ActionHelper with name $name registered."); 52 | } 53 | return $this->helpers[$name]; 54 | } 55 | 56 | public function __call($method, $args) 57 | { 58 | $helper = $this->getHelper($method); 59 | return call_user_func_array(array($helper, 'direct'), $args); 60 | } 61 | } -------------------------------------------------------------------------------- /Resources/examples/Application/Model/Guestbook.php: -------------------------------------------------------------------------------- 1 | setOptions($options); 13 | } 14 | } 15 | 16 | public function __set($name, $value) 17 | { 18 | $method = 'set' . $name; 19 | if (('mapper' == $name) || !method_exists($this, $method)) { 20 | throw new Exception('Invalid guestbook property'); 21 | } 22 | $this->$method($value); 23 | } 24 | 25 | public function __get($name) 26 | { 27 | $method = 'get' . $name; 28 | if (('mapper' == $name) || !method_exists($this, $method)) { 29 | throw new Exception('Invalid guestbook property'); 30 | } 31 | return $this->$method(); 32 | } 33 | 34 | public function setOptions(array $options) 35 | { 36 | $methods = get_class_methods($this); 37 | foreach ($options as $key => $value) { 38 | $method = 'set' . ucfirst($key); 39 | if (in_array($method, $methods)) { 40 | $this->$method($value); 41 | } 42 | } 43 | return $this; 44 | } 45 | 46 | public function setComment($text) 47 | { 48 | $this->_comment = (string) $text; 49 | return $this; 50 | } 51 | 52 | public function getComment() 53 | { 54 | return $this->_comment; 55 | } 56 | 57 | public function setEmail($email) 58 | { 59 | $this->_email = (string) $email; 60 | return $this; 61 | } 62 | 63 | public function getEmail() 64 | { 65 | return $this->_email; 66 | } 67 | 68 | public function setCreated($ts) 69 | { 70 | $this->_created = $ts; 71 | return $this; 72 | } 73 | 74 | public function getCreated() 75 | { 76 | return $this->_created; 77 | } 78 | 79 | public function setId($id) 80 | { 81 | $this->_id = (int) $id; 82 | return $this; 83 | } 84 | 85 | public function getId() 86 | { 87 | return $this->_id; 88 | } 89 | } -------------------------------------------------------------------------------- /Resources/examples/Application/Model/GuestbookMapper.php: -------------------------------------------------------------------------------- 1 | _dbTable = $dbTable; 15 | return $this; 16 | } 17 | 18 | public function getDbTable() 19 | { 20 | if (null === $this->_dbTable) { 21 | $this->setDbTable('Application_Model_DbTable_Guestbook'); 22 | } 23 | return $this->_dbTable; 24 | } 25 | 26 | public function save(Application_Model_Guestbook $guestbook) 27 | { 28 | $data = array( 29 | 'email' => $guestbook->getEmail(), 30 | 'comment' => $guestbook->getComment(), 31 | 'created' => date('Y-m-d H:i:s'), 32 | ); 33 | 34 | if (null === ($id = $guestbook->getId())) { 35 | unset($data['id']); 36 | $this->getDbTable()->insert($data); 37 | } else { 38 | $this->getDbTable()->update($data, array('id = ?' => $id)); 39 | } 40 | } 41 | 42 | public function find($id, Application_Model_Guestbook $guestbook) 43 | { 44 | $result = $this->getDbTable()->find($id); 45 | if (0 == count($result)) { 46 | return; 47 | } 48 | $row = $result->current(); 49 | $guestbook->setId($row->id) 50 | ->setEmail($row->email) 51 | ->setComment($row->comment) 52 | ->setCreated($row->created); 53 | } 54 | 55 | public function fetchAll() 56 | { 57 | $resultSet = $this->getDbTable()->fetchAll(); 58 | $entries = array(); 59 | foreach ($resultSet as $row) { 60 | $entry = new Application_Model_Guestbook(); 61 | $entry->setId($row->id) 62 | ->setEmail($row->email) 63 | ->setComment($row->comment) 64 | ->setCreated($row->created); 65 | $entries[] = $entry; 66 | } 67 | return $entries; 68 | } 69 | } -------------------------------------------------------------------------------- /DependencyInjection/WhitewashingZFMvcCompatExtension.php: -------------------------------------------------------------------------------- 1 | load('compat.xml'); 31 | 32 | foreach ($configs AS $config) { 33 | if (isset($config['default_layout_resource'])) { 34 | $container->setParameter( 35 | 'whitewashing.zfmvccompat.default_layout_resource', 36 | $config['default_layout_resource'] 37 | ); 38 | } 39 | if (isset($config['catchall_bundles'])) { 40 | $container->setParameter( 41 | 'whitewashing.zfmvccompat.catchall_bundles', 42 | $config['catchall_bundles'] 43 | ); 44 | } 45 | if (isset($config['db_conn'])) { 46 | $def = new Definition('Zend_Db_Adapter_Abstract'); 47 | $def->setFactoryClass('Zend_Db'); 48 | $def->setFactoryMethod('factory'); 49 | $def->setArguments(array($config['db_conn']['adapter'], $config['db_conn']['params'])); 50 | 51 | $container->setDefinition('whitewashing.zfmvcompat.db', $def); 52 | } 53 | } 54 | } 55 | 56 | public function getAlias() 57 | { 58 | return 'whitewashing_zf_mvc_compat'; 59 | } 60 | } -------------------------------------------------------------------------------- /Controller/Helpers/Helper.php: -------------------------------------------------------------------------------- 1 | _actionController = $actionController; 29 | return $this; 30 | } 31 | 32 | /** 33 | * Retrieve current action controller 34 | * 35 | * @return Zend_Controller_Action 36 | */ 37 | public function getActionController() 38 | { 39 | return $this->_actionController; 40 | } 41 | 42 | /** 43 | * Hook into action controller initialization 44 | * 45 | * @return void 46 | */ 47 | public function init() 48 | { 49 | } 50 | 51 | /** 52 | * Hook into action controller preDispatch() workflow 53 | * 54 | * @return void 55 | */ 56 | public function preDispatch() 57 | { 58 | } 59 | 60 | /** 61 | * Hook into action controller postDispatch() workflow 62 | * 63 | * @return void 64 | */ 65 | public function postDispatch() 66 | { 67 | } 68 | 69 | /** 70 | * getRequest() - 71 | * 72 | * @return Zend_Controller_Request_Abstract $request 73 | */ 74 | public function getRequest() 75 | { 76 | return $this->getActionController()->getRequest(); 77 | } 78 | 79 | /** 80 | * getResponse() - 81 | * 82 | * @return Zend_Controller_Response_Abstract $response 83 | */ 84 | public function getResponse() 85 | { 86 | return $this->getActionController()->getResponse(); 87 | } 88 | 89 | /** 90 | * getName() 91 | * 92 | * @return string 93 | */ 94 | abstract public function getName(); 95 | 96 | public function __call($method, $args) 97 | { 98 | throw new \BadMethodCallException("$method() is not supported."); 99 | } 100 | } -------------------------------------------------------------------------------- /Tests/View/ZendViewEngineTest.php: -------------------------------------------------------------------------------- 1 | locator = $this->getMock('Symfony\Component\Config\FileLocatorInterface'); 18 | $this->container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); 19 | $this->nameParser = $this->getMock('Symfony\Component\Templating\TemplateNameParserInterface'); 20 | $this->view = $this->getMock('Zend_View_Interface'); 21 | $this->engine = new ZendViewEngine($this->locator, $this->container, $this->nameParser, $this->view); 22 | } 23 | 24 | public function testSupports() 25 | { 26 | $templateResource = 'HelloBundle:test:index.html.phtml'; 27 | 28 | $templateReference = $this->getMock('Symfony\Component\Templating\TemplateReferenceInterface'); 29 | $templateReference->expects($this->once())->method('get') 30 | ->with($this->equalTo('engine')) 31 | ->will($this->returnValue('phtml')); 32 | 33 | $this->nameParser->expects($this->once())->method('parse') 34 | ->with($this->equalTo($templateResource)) 35 | ->will($this->returnValue($templateReference)); 36 | 37 | $this->assertTrue($this->engine->supports($templateResource)); 38 | } 39 | 40 | public function testLoad() 41 | { 42 | $templateResource = 'HelloBundle:test:index.html.phtml'; 43 | $parsedTemplate = array( 44 | 'engine' => 'phtml', 'format' => 'html', 45 | 'bundle' => 'HelloBundle', 'controller' => 'test', 'action' => 'index' 46 | ); 47 | $templatePath = '/template.path'; 48 | 49 | $this->nameParser->expects($this->exactly(2))->method('parse') 50 | ->with($this->equalTo($templateResource)) 51 | ->will($this->returnValue($parsedTemplate)); 52 | 53 | $this->locator->expects($this->once())->method('locate') 54 | ->with($this->equalTo($parsedTemplate)) 55 | ->will($this->returnValue($templatePath)); 56 | 57 | $this->assertEquals($templatePath, $this->engine->load($templateResource)); 58 | $this->assertEquals($templatePath, $this->engine->load($templateResource)); 59 | } 60 | } -------------------------------------------------------------------------------- /View/View1.php: -------------------------------------------------------------------------------- 1 | container = $container; 27 | $this->parser = $parser; 28 | } 29 | 30 | public function action($action, $controller, $module, array $params = array()) 31 | { 32 | $options['attributes'] = $params; 33 | 34 | $symfonyController = sprintf('%sBundle:%s:%s', 35 | $this->parser->formatModule($module), $this->parser->formatController($controller), $action 36 | ); 37 | return $this->container->get('http_kernel')->render($symfonyController, $options); 38 | } 39 | 40 | public function baseUrl() 41 | { 42 | return $this->container->get('request')->getUriForPath('/'); 43 | } 44 | 45 | public function partial($resource, array $params = array()) 46 | { 47 | return $this->container->get('templating')->render($resource, $params); 48 | } 49 | 50 | public function partialLoop($resource, array $models = array()) 51 | { 52 | $html = ''; 53 | foreach ($models AS $model) { 54 | $html .= $this->container->get('templating')->render($resource, $model); 55 | } 56 | return $html; 57 | } 58 | 59 | public function url(array $urlOptions = array(), $name = null, $absolute = false) 60 | { 61 | return $this->container->get('whitewashing.zfmvccompat.actionhelper.url')->url($urlOptions, $name, $absolute); 62 | } 63 | 64 | public function flashMessenger() 65 | { 66 | $flashMessenger = $this->container->get('whitewashing.zfmvccompat.actionhelper.flashmessenger'); 67 | 68 | //get messages from previous requests 69 | $messages = $flashMessenger->getMessages(); 70 | 71 | //add any messages from this request 72 | if ($flashMessenger->hasCurrentMessages()) { 73 | $messages = array_merge($messages, $flashMessenger->getCurrentMessages()); 74 | //we don't need to display them twice. 75 | $flashMessenger->clearCurrentMessages(); 76 | } 77 | 78 | return $messages; 79 | } 80 | } -------------------------------------------------------------------------------- /Controller/ZendResponse.php: -------------------------------------------------------------------------------- 1 | headers[$name]) && !$replace) { 28 | return $this; 29 | } 30 | 31 | $this->headers[$name] = $value; 32 | return $this; 33 | } 34 | 35 | public function setRedirect($url, $status = 302) 36 | { 37 | $this->redirect = $url; 38 | $this->status = $status; 39 | } 40 | 41 | public function generateResponse() 42 | { 43 | $response = new Response($this->content, $this->status, $this->headers); 44 | if ($this->redirect) { 45 | $response->setRedirect($this->redirect, $this->status); 46 | } 47 | } 48 | 49 | public function isRedirect() 50 | { 51 | return $this->redirect !== false; 52 | } 53 | 54 | public function getHeaders() 55 | { 56 | return $this->headers; 57 | } 58 | 59 | public function clearHeaders() 60 | { 61 | $this->headers = array(); 62 | return $this; 63 | } 64 | 65 | public function clearHeader($name) 66 | { 67 | unset($this->headers[$name]); 68 | return $this; 69 | } 70 | 71 | public function clearAllHeaders() 72 | { 73 | $this->clearHeaders(); 74 | } 75 | 76 | public function setHttpResponseCode($status) 77 | { 78 | $this->status = $status; 79 | return $this; 80 | } 81 | 82 | public function getHttpResponseCode() 83 | { 84 | return $this->status; 85 | } 86 | 87 | public function setBody($content) 88 | { 89 | $this->content = $content; 90 | return $this; 91 | } 92 | 93 | public function appendBody($content) 94 | { 95 | $this->content .= $content; 96 | return $this; 97 | } 98 | 99 | public function clearBody() 100 | { 101 | $this->content = ""; 102 | return $this; 103 | } 104 | 105 | public function getBody() 106 | { 107 | return $this->content; 108 | } 109 | 110 | public function __call($method, $args) 111 | { 112 | throw new \BadMethodCallException("not implemented"); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Router/Loader/ZFRouterLoader.php: -------------------------------------------------------------------------------- 1 | locator->locate($file); 22 | $type = $type ?: pathinfo($file, PATHINFO_EXTENSION); 23 | switch($type) { 24 | case 'php': 25 | $data = require($file); 26 | $config = new \Zend_Config($data); 27 | break; 28 | case 'xml': 29 | $config = new \Zend_Config_Xml($file); 30 | break; 31 | case 'ini': 32 | $config = new \Zend_Config_Ini($file, "routes"); 33 | break; 34 | } 35 | $data = $config->toArray(); 36 | if (isset($data['routes'])) { 37 | $data = $data['routes']; 38 | } 39 | 40 | $collection = new RouteCollection; 41 | foreach ($data AS $routeName => $config) { 42 | if (isset($config['type']) && $config['type'] == "Zend_Controller_Router_Route_Regex") { 43 | throw new \InvalidArgumentException("Not supported"); 44 | } 45 | 46 | if (!isset($config['reqs'])) { 47 | $config['reqs'] = array(); 48 | } 49 | if (!isset($config['defaults'])) { 50 | $config['defaults'] = array(); 51 | } 52 | if (!isset($config['options'])) { 53 | $config['options'] = array(); 54 | } 55 | 56 | if (!isset($config['defaults']['module'])) { 57 | // TODO: DefaultModule config 58 | $config['defaults']['module'] = 'Default'; 59 | } 60 | if (!isset($config['defaults']['controller'])) { 61 | $config['defaults']['controller'] = 'Index'; 62 | } 63 | if (!isset($config['defaults']['action'])) { 64 | $config['defaults']['action'] = 'index'; 65 | } 66 | $config['defaults']['_controller'] = sprintf('%sBundle:%s:%s', 67 | $config['defaults']['module'], 68 | $config['defaults']['controller'], 69 | $config['defaults']['action'] 70 | ); 71 | 72 | if (preg_match_all('(:([^/]+)+)', $config['route'], $matches)) { 73 | for ($i = 0; $i < count($matches[0]); $i++) { 74 | $config['route'] = str_replace($matches[0][$i], "{" . $matches[1][$i] . "}", $config['route']); 75 | } 76 | } 77 | 78 | $route = new Route($config['route'], $config['defaults'], $config['reqs'], $config['options']); 79 | $collection->add($routeName, $route); 80 | } 81 | 82 | return $collection; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Tests/Controller/RouteNameParserTest.php: -------------------------------------------------------------------------------- 1 | kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface'); 25 | $this->parser = new RouteNameParser($this->kernel); 26 | } 27 | 28 | public function testNotSupportsServices() 29 | { 30 | $this->assertEquals(array(), $this->parser->parse('fos_user_controller.actionName')); 31 | } 32 | 33 | public function testSupportsUncompiledSyntax() 34 | { 35 | $this->assertEquals( 36 | array("module" => "Hello", "controller" => "Test", "action" => "index"), 37 | $this->parser->parse("HelloBundle:Test:index") 38 | ); 39 | } 40 | 41 | public function testSupportsCompiledSyntax() 42 | { 43 | $bundle = $this->getMock('WhitewashingCompatCompiledBundleMock', array('getName', 'getNamespace')); 44 | $bundle->expects($this->at(0)) 45 | ->method('getNamespace') 46 | ->will($this->returnValue('Whitewashing\ZFMvcCompatBundle')); 47 | $bundle->expects($this->at(1)) 48 | ->method('getName') 49 | ->will($this->returnValue('HelloBundle')); 50 | 51 | $this->kernel->expects($this->once()) 52 | ->method('getBundles') 53 | ->will($this->returnValue(array($bundle))); 54 | 55 | $this->assertEquals( 56 | array("module" => "Hello", "controller" => "Test", "action" => "index"), 57 | $this->parser->parse("Whitewashing\\ZFMvcCompatBundle\\Tests\\Controller\\TestController::indexAction") 58 | ); 59 | 60 | // cached? 61 | $this->assertEquals( 62 | array("module" => "Hello", "controller" => "Test", "action" => "index"), 63 | $this->parser->parse("Whitewashing\\ZFMvcCompatBundle\\Tests\\Controller\\TestController::indexAction") 64 | ); 65 | } 66 | 67 | public function testFormatModule() 68 | { 69 | $bundle = $this->getMock('WhitewashingCompatFormatBundleMock', array('getName', 'getNamespace')); 70 | $bundle->expects($this->any()) 71 | ->method('getName') 72 | ->will($this->returnValue('HeLLoBundle')); 73 | 74 | $this->kernel->expects($this->once()) 75 | ->method('getBundles') 76 | ->will($this->returnValue(array($bundle))); 77 | 78 | $this->assertEquals('HeLLo', $this->parser->formatModule('hello')); 79 | } 80 | 81 | public function testFormatController() 82 | { 83 | $this->assertEquals('Test', $this->parser->formatController('test')); 84 | } 85 | } 86 | 87 | class TestController 88 | { 89 | 90 | } -------------------------------------------------------------------------------- /Controller/RouteNameParser.php: -------------------------------------------------------------------------------- 1 | kernel = $kernel; 32 | } 33 | 34 | public function parse($symfonyControllerName) 35 | { 36 | if (isset($this->cache[$symfonyControllerName])) { 37 | return $this->cache[$symfonyControllerName]; 38 | } 39 | 40 | // skip controllers as services 41 | if (strpos($symfonyControllerName, ".") !== false) { 42 | return array(); 43 | } 44 | 45 | if (substr_count($symfonyControllerName, "::") == 1) { 46 | $details = array(); 47 | list($controllerName, $actionName) = explode("::", $symfonyControllerName); 48 | $details['action'] = str_replace("Action", "", $actionName); 49 | $controllerRefl = new \ReflectionClass($controllerName); 50 | $details['controller'] = str_replace("Controller", "", $controllerRefl->getShortName()); 51 | $controllerNamespace = $controllerRefl->getNamespaceName(); 52 | 53 | foreach ($this->kernel->getBundles() AS $bundle) { 54 | if (strpos($controllerNamespace, $bundle->getNamespace()) === 0) { 55 | $details['module'] = str_replace("Bundle", "", $bundle->getName()); 56 | break; 57 | } 58 | } 59 | } else { 60 | list($module, $controller, $action) = explode(":", $symfonyControllerName); 61 | $details['action'] = $action; 62 | $details['controller'] = $controller; 63 | $details['module'] = str_replace("Bundle", "", $module); 64 | } 65 | 66 | return $this->cache[$symfonyControllerName] = $details; 67 | } 68 | 69 | /** 70 | * Get correct casing of the module which is based on the bundle. 71 | * 72 | * @param string $module 73 | * @return string 74 | */ 75 | public function formatModule($module) 76 | { 77 | $module = strtolower($module); 78 | if (isset($this->moduleCache[$module])) { 79 | return $this->moduleCache[$module]; 80 | } 81 | 82 | foreach ($this->kernel->getBundles() AS $bundle) { 83 | if ($module."bundle" == strtolower($bundle->getName())) { 84 | return $this->moduleCache[$module] = str_replace("Bundle", "", $bundle->getName()); 85 | } 86 | } 87 | throw new \RuntimeException("Couldnt find a matching bundle for the module $module"); 88 | } 89 | 90 | public function formatController($controller) 91 | { 92 | return ucfirst($controller); 93 | } 94 | } -------------------------------------------------------------------------------- /Controller/Helpers/UrlHelper.php: -------------------------------------------------------------------------------- 1 | router = $router; 35 | $this->routeNameParser = $routeNameParser; 36 | $this->request = $request; 37 | } 38 | 39 | public function simple($action, $controller = null, $module = null, array $params = array()) 40 | { 41 | $zendRequest = $this->getActionController()->getRequest(); 42 | if (!$controller) { 43 | $controller = $zendRequest->getControllerName(); 44 | } else { 45 | $controller = $this->routeNameParser->formatController($controller); 46 | } 47 | if (!$module) { 48 | $module = $zendRequest->getModuleName(); 49 | } else { 50 | $module = $this->routeNameParser->formatModule($module); 51 | } 52 | 53 | $routes = $this->router->getRouteCollection()->all(); 54 | foreach ($routes AS $route) { 55 | $details = $this->routeNameParser->parse($route->getDefault('_controller')); 56 | if (!isset($details['module']) || !isset($details['controller']) || !isset($details['action'])) { 57 | continue; 58 | } 59 | 60 | $defaults = $route->getDefaults(); 61 | if ($module == $details['module'] && 62 | $controller == $details['controller'] && 63 | $action == $details['action'] && 64 | count(array_intersect_key($defaults, $params)) == (count($defaults)-1) ) { 65 | 66 | /* @var $pattern Route */ 67 | $pattern = $route->getPattern(); 68 | foreach ($params AS $name => $value) { 69 | $pattern = str_replace("{$name}", $value, $pattern); 70 | } 71 | 72 | return $this->request->getUriForPath($pattern); 73 | } 74 | } 75 | throw new \RuntimeException("Did not find a route matching the given module/controller/actions pair."); 76 | } 77 | 78 | public function url($urlOptions = array(), $name = null, $absolute = false) 79 | { 80 | if ($name === null) { 81 | $name = $this->request->get('_route'); 82 | } 83 | 84 | return $this->router->generate($name, $urlOptions, $absolute); 85 | } 86 | 87 | public function getName() 88 | { 89 | return 'url'; 90 | } 91 | 92 | public function direct($action, $controller = null, $module = null, array $params = array()) 93 | { 94 | return $this->simple($action, $controller, $module, $params); 95 | } 96 | } -------------------------------------------------------------------------------- /View/CoreViewListener.php: -------------------------------------------------------------------------------- 1 | templating = $templating; 38 | $this->zendView = $zendView; 39 | } 40 | 41 | public function filterResponse(GetResponseForControllerResultEvent $event) 42 | { 43 | /* @var $request \Symfony\Component\HttpFoundation\Request */ 44 | $request = $event->getRequest(); 45 | 46 | 47 | if ($request->attributes->has('zend_compat_controller') && !$event->hasResponse()) { 48 | /* @var $zendController ZendController */ 49 | $zendController = $request->attributes->get('zend_compat_controller'); 50 | $zendController->postDispatch(); 51 | /* @var $zendRequest ZendRequest */ 52 | $zendRequest = $zendController->getRequest(); 53 | 54 | /* @var $response Symfony\Component\HttpFoundation\Response */ 55 | $response = new Response(); 56 | 57 | /* @var $zendResponse ZendResponse */ 58 | $zendResponse = $zendController->getResponse(); 59 | $response->headers->add($zendResponse->getHeaders()); 60 | $response->setStatusCode($zendResponse->getHttpResponseCode()); 61 | 62 | if ($zendController->getHelper('viewrenderer')->getNoRender() === false) { 63 | // TODO: "html" => ContextSwitch 64 | $viewName = sprintf("%sBundle:%s:%s.%s.%s", 65 | $zendRequest->getModuleName(), 66 | $zendRequest->getControllerName(), 67 | $zendRequest->getActionName(), 68 | "html", "phtml" 69 | ); 70 | 71 | $vars = $zendController->view->allVars(); 72 | foreach ($vars AS $k => $v) { 73 | if ($v instanceof \Zend_Form) { 74 | $v->setView($this->zendView); 75 | 76 | foreach ($v->getElements() as $element) { 77 | $element->setView($this->zendView); 78 | } 79 | } 80 | } 81 | 82 | $content = $this->templating->render($viewName, $vars); 83 | 84 | if ($zendController->getHelper('layout')->isEnabled()) { 85 | $content = $this->templating->render($zendController->getHelper('layout')->getLayout(), array('content' => $content)); 86 | } 87 | $response->setContent($content); 88 | } 89 | $event->setResponse($response); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Controller/Helpers/Redirector.php: -------------------------------------------------------------------------------- 1 | urlHelper = $urlHelper; 38 | } 39 | 40 | public function getName() 41 | { 42 | return "redirector"; 43 | } 44 | 45 | /** 46 | * Return use absolute URI flag 47 | * 48 | * @return boolean 49 | */ 50 | public function getUseAbsoluteUri() 51 | { 52 | return $this->useAbsoluteUri; 53 | } 54 | 55 | /** 56 | * Set use absolute URI flag 57 | * 58 | * @param boolean $flag 59 | * @return Zend_Controller_Action_Helper_Redirector Provides a fluent interface 60 | */ 61 | public function setUseAbsoluteUri($flag = true) 62 | { 63 | $this->useAbsoluteUri = ($flag) ? true : false; 64 | return $this; 65 | } 66 | 67 | public function setGotoSimple($action, $controller = null, $module = null, array $params = array()) 68 | { 69 | $this->response = new RedirectResponse($this->urlHelper->direct($action, $controller, $module, $params)); 70 | } 71 | 72 | public function setGotoRoute(array $urlOptions = array(), $name = null, $absolute = true) 73 | { 74 | $this->response = new RedirectResponse($this->urlHelper->url($urlOptions, $name, $absolute || $this->useAbsoluteUri)); 75 | } 76 | 77 | public function setGotoUrl($url, array $options = array()) 78 | { 79 | if (!isset($options['code'])) { 80 | $options['code'] = null; 81 | } 82 | $this->response = new RedirectResponse($url, $options['code']); 83 | } 84 | 85 | public function gotoSimple($action, $controller = null, $module = null, array $params = array()) 86 | { 87 | $this->setGotoSimple($action, $controller, $module, $params); 88 | return $this->response; 89 | } 90 | 91 | public function gotoSimpleAndExit($action, $controller = null, $module = null, array $params = array()) 92 | { 93 | $this->setGotoSimple($action, $controller, $module, $params); 94 | return $this->response; 95 | } 96 | 97 | public function gotoRoute(array $urlOptions = array(), $name = null, $absolute = true) 98 | { 99 | $this->setGotoRoute($urlOptions, $name, $absolute || $this->useAbsoluteUri); 100 | return $this->response; 101 | } 102 | 103 | public function gotoRouteAndExit(array $urlOptions = array(), $absolute = true) 104 | { 105 | $this->setGotoRoute($urlOptions, $name, $absolute || $this->useAbsoluteUri); 106 | return $this->response; 107 | } 108 | 109 | public function gotoUrl($url, array $options = array()) 110 | { 111 | $this->setGotoUrl($url, $options); 112 | return $this->response; 113 | } 114 | 115 | public function gotoUrlAndExit($url, array $options = array()) 116 | { 117 | $this->setGotoUrl($url, $options); 118 | return $this->response; 119 | } 120 | 121 | public function direct($action, $controller = null, $module = null, array $params = array()) 122 | { 123 | return $this->gotoSimple($action, $controller, $module, $params); 124 | } 125 | } -------------------------------------------------------------------------------- /View/ZendViewEngine.php: -------------------------------------------------------------------------------- 1 | locator = $locator; 71 | $this->container = $container; 72 | $this->parser = $parser; 73 | $this->view = $zendView; 74 | // Zend View is not able to handle absolute paths except with this little trick 75 | $this->view->setScriptPath(''); 76 | } 77 | 78 | public function exists($name) 79 | { 80 | return (file_exists($this->findTemplate($name))); 81 | } 82 | 83 | public function load($name) 84 | { 85 | return $this->findTemplate($name); 86 | } 87 | 88 | public function render($name, array $parameters = array()) 89 | { 90 | $templateName = $this->load($name); 91 | $view = clone $this->view; 92 | $view->assign($parameters); 93 | return $view->render($templateName); 94 | } 95 | 96 | /** 97 | * Renders a view and returns a Response. 98 | * 99 | * @param string $view The view name 100 | * @param array $parameters An array of parameters to pass to the view 101 | * @param Response $response A Response instance 102 | * 103 | * @return Response A Response instance 104 | */ 105 | public function renderResponse($view, array $parameters = array(), Response $response = null) 106 | { 107 | if (null === $response) { 108 | $response = $this->container->get('response'); 109 | } 110 | 111 | $response->setContent($this->render($view, $parameters)); 112 | 113 | return $response; 114 | } 115 | 116 | public function supports($name) 117 | { 118 | $template = $this->parser->parse($name); 119 | return $template && 'phtml' === $template->get('engine'); 120 | } 121 | 122 | protected function findTemplate($name) 123 | { 124 | if (!is_array($name)) { 125 | $name = $this->parser->parse($name); 126 | } 127 | 128 | $key = md5(serialize($name)); 129 | if (isset($this->cache[$key])) { 130 | return $this->cache[$key]; 131 | } 132 | 133 | if (false == $file = $this->locator->locate($name)) { 134 | throw new \RuntimeException(sprintf('Unable to find template "%s".', json_encode($name))); 135 | } 136 | 137 | return $this->cache[$key] = $file; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /Controller/ZendController.php: -------------------------------------------------------------------------------- 1 | container = $container; 48 | $this->request = $container->get('request'); 49 | $this->request->attributes->set('zend_compat_controller', $this); 50 | $this->_request = $this->container->get('whitewashing.zfmvccompat.controller.request'); 51 | $this->_response = new ZendResponse(); 52 | $this->view = new ParameterBag(); 53 | $this->_helper = new HelperBroker($this->container, $this); 54 | 55 | $this->init(); 56 | $this->preDispatch(); 57 | } 58 | 59 | public function init() {} 60 | 61 | public function preDispatch() {} 62 | 63 | public function postDispatch() {} 64 | 65 | /** 66 | * @param string $name 67 | * @return Helper 68 | */ 69 | public function getHelper($name) 70 | { 71 | return $this->_helper->getHelper($name); 72 | } 73 | 74 | protected function _getParam($name, $default = null) 75 | { 76 | $value = $this->_request->getParam($name); 77 | if ((null === $value || '' === $value) && (null !== $default)) { 78 | $value = $default; 79 | } 80 | 81 | return $value; 82 | } 83 | 84 | protected function _setParam($name, $value) 85 | { 86 | $this->_request->setParam($name, $value); 87 | return $this; 88 | } 89 | 90 | protected function _hasParam($name) 91 | { 92 | return null !== $this->_request->getParam($name); 93 | } 94 | 95 | protected function _getAllParams() 96 | { 97 | return $this->_request->getParams(); 98 | } 99 | 100 | /** 101 | * @return ZendRequest 102 | */ 103 | public function getRequest() 104 | { 105 | return $this->_request; 106 | } 107 | 108 | /** 109 | * @return ZendResponse 110 | */ 111 | public function getResponse() 112 | { 113 | return $this->_response; 114 | } 115 | 116 | /** 117 | * Forward to another controller/action. 118 | * 119 | * It is important to supply the unformatted names, i.e. "article" 120 | * rather than "ArticleController". The dispatcher will do the 121 | * appropriate formatting when the request is received. 122 | * 123 | * If only an action name is provided, forwards to that action in this 124 | * controller. 125 | * 126 | * If an action and controller are specified, forwards to that action and 127 | * controller in this module. 128 | * 129 | * Specifying an action, controller, and module is the most specific way to 130 | * forward. 131 | * 132 | * A fourth argument, $params, will be used to set the request parameters. 133 | * If either the controller or module are unnecessary for forwarding, 134 | * simply pass null values for them before specifying the parameters. 135 | * 136 | * @param string $action 137 | * @param string $controller 138 | * @param string $module 139 | * @param array $params 140 | * @return void 141 | */ 142 | final protected function _forward($action, $controller = null, $module = null, array $params = null) 143 | { 144 | if (!$controller) { 145 | $controller = $this->_request->getControllerName(); 146 | } 147 | if (!$module) { 148 | $module = $this->_request->getModuleName(); 149 | } 150 | 151 | $nameParser = $this->container->get('whitewashing.zfmvccompat.nameparser'); 152 | $controller = $nameParser->formatModule($module)."Bundle:".$nameParser->formatController($controller).":".$action; 153 | return $this->container->get('http_kernel')->forward($controller, array(), $params); 154 | } 155 | 156 | /** 157 | * Redirect to another URL 158 | * 159 | * Proxies to {@link Zend_Controller_Action_Helper_Redirector::gotoUrl()}. 160 | * 161 | * @param string $url 162 | * @param array $options Options to be used when redirecting 163 | * @return RedirectResponse The symfony redirect response 164 | */ 165 | protected function _redirect($url, array $options = array()) 166 | { 167 | return new RedirectResponse($this->container->get('request')->getUriForPath($url)); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /Resources/config/compat.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Whitewashing\ZFMvcCompatBundle\View\ZendViewEngine 9 | WhitewashingZFMvcCompatBundle::layout.html.phtml 10 | 11 | 12 | Whitewashing\ZFMvcCompatBundle\View\CoreViewListener 13 | Whitewashing\ZFMvcCompatBundle\Controller\CatchAllRequestListener 14 | Whitewashing\ZFMvcCompatBundle\View\View1 15 | Whitewashing\ZFMvcCompatBundle\Controller\RouteNameParser 16 | Whitewashing\ZFMvcCompatBundle\Controller\ZendRequest 17 | Whitewashing\ZFMvcCompatBundle\Controller\Helpers\ContextSwitch 18 | Whitewashing\ZFMvcCompatBundle\Controller\Helpers\FlashMessenger 19 | Whitewashing\ZFMvcCompatBundle\Controller\Helpers\UrlHelper 20 | Whitewashing\ZFMvcCompatBundle\Controller\Helpers\Redirector 21 | Whitewashing\ZFMvcCompatBundle\Controller\Helpers\Layout 22 | Whitewashing\ZFMvcCompatBundle\Controller\Helpers\ViewRenderer 23 | Whitewashing\ZFMvcCompatBundle\Router\Loader\ZFRouterLoader 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | %whitewashing.zfmvccompat.catchall_bundles% 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | %whitewashing.zfmvccompat.default_layout_resource% 80 | 81 | 82 | 83 | %whitewashing.zfmvccompat.default_layout_resource% 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Controller/Helpers/FlashMessenger.php: -------------------------------------------------------------------------------- 1 | get('session')->setFlash($namespace, $message) 9 | * 10 | * @author Richard Fullmer 11 | */ 12 | class FlashMessenger extends Helper 13 | { 14 | /** 15 | * $_messages - Messages from previous request 16 | * 17 | * @var array 18 | */ 19 | static protected $_messages = array(); 20 | 21 | /** 22 | * $_session - Zend_Session storage object 23 | * 24 | * @var Zend_Session 25 | */ 26 | static protected $_session = null; 27 | 28 | /** 29 | * $_messageAdded - Wether a message has been previously added 30 | * 31 | * @var boolean 32 | */ 33 | static protected $_messageAdded = false; 34 | 35 | /** 36 | * $_namespace - Instance namespace, default is 'default' 37 | * 38 | * @var string 39 | */ 40 | protected $_namespace = 'default'; 41 | 42 | /** 43 | * __construct() - Instance constructor, needed to get iterators, etc 44 | * 45 | * @param string $namespace 46 | * @return void 47 | */ 48 | public function __construct() 49 | { 50 | if (!self::$_session instanceof \Zend_Session_Namespace) { 51 | self::$_session = new \Zend_Session_Namespace($this->getName()); 52 | foreach (self::$_session as $namespace => $messages) { 53 | self::$_messages[$namespace] = $messages; 54 | unset(self::$_session->{$namespace}); 55 | } 56 | } 57 | } 58 | 59 | /** 60 | * setNamespace() - change the namespace messages are added to, useful for 61 | * per action controller messaging between requests 62 | * 63 | * @param string $namespace 64 | * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface 65 | */ 66 | public function setNamespace($namespace = 'default') 67 | { 68 | $this->_namespace = $namespace; 69 | return $this; 70 | } 71 | 72 | /** 73 | * resetNamespace() - reset the namespace to the default 74 | * 75 | * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface 76 | */ 77 | public function resetNamespace() 78 | { 79 | $this->setNamespace(); 80 | return $this; 81 | } 82 | 83 | /** 84 | * addMessage() - Add a message to flash message 85 | * 86 | * @param string $message 87 | * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface 88 | */ 89 | public function addMessage($message) 90 | { 91 | if (self::$_messageAdded === false) { 92 | self::$_session->setExpirationHops(1, null, true); 93 | } 94 | 95 | if (!is_array(self::$_session->{$this->_namespace})) { 96 | self::$_session->{$this->_namespace} = array(); 97 | } 98 | 99 | self::$_session->{$this->_namespace}[] = $message; 100 | 101 | return $this; 102 | } 103 | 104 | /** 105 | * hasMessages() - Wether a specific namespace has messages 106 | * 107 | * @return boolean 108 | */ 109 | public function hasMessages() 110 | { 111 | return isset(self::$_messages[$this->_namespace]); 112 | } 113 | 114 | /** 115 | * getMessages() - Get messages from a specific namespace 116 | * 117 | * @return array 118 | */ 119 | public function getMessages() 120 | { 121 | if ($this->hasMessages()) { 122 | return self::$_messages[$this->_namespace]; 123 | } 124 | 125 | return array(); 126 | } 127 | 128 | /** 129 | * Clear all messages from the previous request & current namespace 130 | * 131 | * @return boolean True if messages were cleared, false if none existed 132 | */ 133 | public function clearMessages() 134 | { 135 | if ($this->hasMessages()) { 136 | unset(self::$_messages[$this->_namespace]); 137 | return true; 138 | } 139 | 140 | return false; 141 | } 142 | 143 | /** 144 | * hasCurrentMessages() - check to see if messages have been added to current 145 | * namespace within this request 146 | * 147 | * @return boolean 148 | */ 149 | public function hasCurrentMessages() 150 | { 151 | return isset(self::$_session->{$this->_namespace}); 152 | } 153 | 154 | /** 155 | * getCurrentMessages() - get messages that have been added to the current 156 | * namespace within this request 157 | * 158 | * @return array 159 | */ 160 | public function getCurrentMessages() 161 | { 162 | if ($this->hasCurrentMessages()) { 163 | return self::$_session->{$this->_namespace}; 164 | } 165 | 166 | return array(); 167 | } 168 | 169 | /** 170 | * clear messages from the current request & current namespace 171 | * 172 | * @return boolean 173 | */ 174 | public function clearCurrentMessages() 175 | { 176 | if ($this->hasCurrentMessages()) { 177 | unset(self::$_session->{$this->_namespace}); 178 | return true; 179 | } 180 | 181 | return false; 182 | } 183 | 184 | /** 185 | * getIterator() - complete the IteratorAggregate interface, for iterating 186 | * 187 | * @return ArrayObject 188 | */ 189 | public function getIterator() 190 | { 191 | if ($this->hasMessages()) { 192 | return new \ArrayObject($this->getMessages()); 193 | } 194 | 195 | return new \ArrayObject(); 196 | } 197 | 198 | /** 199 | * count() - Complete the countable interface 200 | * 201 | * @return int 202 | */ 203 | public function count() 204 | { 205 | if ($this->hasMessages()) { 206 | return count($this->getMessages()); 207 | } 208 | 209 | return 0; 210 | } 211 | 212 | /** 213 | * Strategy pattern: proxy to addMessage() 214 | * 215 | * @param string $message 216 | */ 217 | public function direct($message) 218 | { 219 | return $this->addMessage($message); 220 | } 221 | 222 | /** 223 | * getName() 224 | * 225 | * @return string 226 | */ 227 | public function getName() 228 | { 229 | return 'flashmessenger'; 230 | } 231 | 232 | 233 | } 234 | -------------------------------------------------------------------------------- /Controller/ZendRequest.php: -------------------------------------------------------------------------------- 1 | request = $request; 48 | $this->parser = $parser; 49 | } 50 | 51 | private function parseRequest() 52 | { 53 | if ($this->actionName) { 54 | return; 55 | } 56 | 57 | $details = $this->parser->parse($this->request->attributes->get('_controller')); 58 | $this->actionName = $details['action']; 59 | $this->controllerName = $details['controller']; 60 | $this->moduleName = $details['module']; 61 | } 62 | 63 | public function __get($name) 64 | { 65 | if ($this->request->attributes->has($name)) { 66 | return $this->request->attributes->get($name); 67 | } else if ($this->request->query->has($name)) { 68 | return $this->request->query->get($name); 69 | } else if ($this->request->request->has($name)) { 70 | return $this->request->request->get($name); 71 | } else if ($this->request->cookies->has($name)) { 72 | return $this->request->cookies->get($name); 73 | } else if ($this->request->server->has($name)) { 74 | return $this->request->server->get($name); 75 | } else { 76 | return null; 77 | } 78 | } 79 | 80 | public function get($name) 81 | { 82 | return $this->__get($name); 83 | } 84 | 85 | public function set($name, $value) 86 | { 87 | throw new \BadMethodCallException("Cannot set value, please use setParam()"); 88 | } 89 | 90 | public function __set($name, $value) 91 | { 92 | $this->set($name, $value); 93 | } 94 | 95 | public function has($name) 96 | { 97 | if (isset($this->request->attributes[$name])) { 98 | return true; 99 | } else if (isset($this->request->query[$name])) { 100 | return true; 101 | } else if (isset($this->request->request[$name])) { 102 | return true; 103 | } else if (isset($this->request->cookies[$name])) { 104 | return true; 105 | } else if (isset($this->request->server[$name])) { 106 | return true; 107 | } else { 108 | return false; 109 | } 110 | } 111 | 112 | public function __isset($name) 113 | { 114 | return $this->has($name); 115 | } 116 | 117 | public function getQuery($name = null, $default = null) 118 | { 119 | if (null === $name) { 120 | return $this->request->query->all(); 121 | } 122 | 123 | return (isset($this->request->query[$name])) ? $this->request->query[$name] : $default; 124 | } 125 | 126 | public function getPost($name = null, $default = null) 127 | { 128 | if (null === $name) { 129 | return $this->request->request->all(); 130 | } 131 | 132 | return (isset($this->request->request[$name])) ? $this->request->request[$name] : $default; 133 | } 134 | 135 | public function getCookie($name = null, $default = null) 136 | { 137 | if (null === $name) { 138 | return $this->request->cookies->all(); 139 | } 140 | 141 | return (isset($this->request->cookies[$name])) ? $this->request->cookies[$name] : $default; 142 | } 143 | 144 | public function getServer($name = null, $default = null) 145 | { 146 | if (null === $name) { 147 | return $this->request->server->all(); 148 | } 149 | 150 | return (isset($this->request->server[$name])) ? $this->request->server[$name] : $default; 151 | } 152 | 153 | public function getEnv($key = null, $default = null) 154 | { 155 | if (null === $key) { 156 | return $_ENV; 157 | } 158 | 159 | return (isset($_ENV[$key])) ? $_ENV[$key] : $default; 160 | } 161 | 162 | public function getRequestUri() 163 | { 164 | return $this->request->getRequestUri(); 165 | } 166 | 167 | public function getBaseUrl() 168 | { 169 | return $this->request->getBaseUrl(); 170 | } 171 | 172 | public function getBasePath() 173 | { 174 | return $this->request->getBasePath(); 175 | } 176 | 177 | public function getPathInfo() 178 | { 179 | return $this->request->getPathInfo(); 180 | } 181 | 182 | /** 183 | * Set allowed parameter sources 184 | * 185 | * Can be empty array, or contain one or more of '_GET' or '_POST'. 186 | * 187 | * @param array $paramSoures 188 | * @return Zend_Controller_Request_Http 189 | */ 190 | public function setParamSources(array $paramSources = array()) 191 | { 192 | $this->paramSources = $paramSources; 193 | return $this; 194 | } 195 | 196 | /** 197 | * Get list of allowed parameter sources 198 | * 199 | * @return array 200 | */ 201 | public function getParamSources() 202 | { 203 | return $this->paramSources; 204 | } 205 | 206 | public function getParam($key, $default = null) 207 | { 208 | $paramSources = $this->getParamSources(); 209 | if (isset($this->_params[$key])) { 210 | return $this->_params[$key]; 211 | } else if ($this->request->attributes->has($key)) { 212 | return $this->request->attributes->get($key); 213 | } elseif (in_array('_GET', $paramSources) && $this->request->query->has($key)) { 214 | return $this->request->query->get($key); 215 | } elseif (in_array('_POST', $paramSources) && $this->request->request->has($key)) { 216 | return $this->request->request->get($key); 217 | } 218 | 219 | return $default; 220 | } 221 | 222 | public function getParams() 223 | { 224 | $return = $this->params; 225 | $paramSources = $this->getParamSources(); 226 | if (in_array('_GET', $paramSources)) { 227 | $return += $this->request->query->all(); 228 | } 229 | if (in_array('_POST', $paramSources)) { 230 | $return += $this->request->request->all(); 231 | } 232 | return $return; 233 | } 234 | 235 | public function setParams(array $params) 236 | { 237 | foreach ($params as $key => $value) { 238 | $this->setParam($key, $value); 239 | } 240 | return $this; 241 | } 242 | 243 | public function setParam($key, $value) 244 | { 245 | $this->params[$key] = $value; 246 | return $this; 247 | } 248 | 249 | public function getMethod() 250 | { 251 | return $this->request->getMethod(); 252 | } 253 | 254 | public function isPost() 255 | { 256 | return ($this->request->getMethod() == 'POST'); 257 | } 258 | 259 | public function isGet() 260 | { 261 | return ($this->request->getMethod() == 'GET'); 262 | } 263 | 264 | public function isPut() 265 | { 266 | return ($this->request->getMethod() == 'PUT'); 267 | } 268 | 269 | public function isDelete() 270 | { 271 | return ($this->request->getMethod() == 'DELETE'); 272 | } 273 | 274 | public function isOptions() 275 | { 276 | return ($this->request->getMethod() == 'OPTIONS'); 277 | } 278 | 279 | public function isHead() 280 | { 281 | return ($this->request->getMethod() == 'HEAD'); 282 | } 283 | 284 | public function isXmlHttpRequest() 285 | { 286 | return $this->request->isXmlHttpRequest(); 287 | } 288 | 289 | public function isFlashRequest() 290 | { 291 | $header = strtolower($this->request->headers->get('USER_AGENT')); 292 | return (strstr($header, ' flash')) ? true : false; 293 | } 294 | 295 | public function isSecure() 296 | { 297 | return $this->request->isSecure(); 298 | } 299 | 300 | public function getHeader($name) 301 | { 302 | return $this->request->headers->get($name); 303 | } 304 | 305 | public function getScheme() 306 | { 307 | return $this->request->getScheme(); 308 | } 309 | 310 | public function getHttpHost() 311 | { 312 | return $this->request->getHttpHost(); 313 | } 314 | 315 | public function getClientIp($proxy) 316 | { 317 | return $this->request->getClientIp($proxy); 318 | } 319 | 320 | public function getModuleName() 321 | { 322 | $this->parseRequest(); 323 | return $this->moduleName; 324 | } 325 | 326 | public function getControllerName() 327 | { 328 | $this->parseRequest(); 329 | return $this->controllerName; 330 | } 331 | 332 | public function getActionName() 333 | { 334 | $this->parseRequest(); 335 | return $this->actionName; 336 | } 337 | 338 | public function getUserParams() 339 | { 340 | return $this->params; 341 | } 342 | 343 | public function getUserParam($key, $default = null) 344 | { 345 | if (isset($this->params[$key])) { 346 | return $this->params[$key]; 347 | } 348 | return $default; 349 | } 350 | 351 | public function clearParams() 352 | { 353 | $this->params = array(); 354 | return $this; 355 | } 356 | } 357 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Symfony2 Zend MVC 1.x Compatibility Bundle 2 | 3 | Simplifies moving your Zend 1.x MVC apps to Symfony 2 if you follow the way I interpreted the Zend project guidelines closely enough :-) 4 | 5 | ## Overview 6 | 7 | ### What it can do: 8 | 9 | * Has a base controller that mimics Zend_Controller_Action functionality 10 | * Uses Zend_View as template engine and just replaces certain view helpers with the Symfony2 functionality. 11 | * Ports most of the common action helpers or implements proxies that implement Symfony2 functionality. 12 | * Adds a catch-all route mechanism for selected bundles. 13 | * Import ZF Routing format files 14 | 15 | ### What it cannot do yet (Waiting for your pull requests) 16 | 17 | * Support for custom Zend_View helpers (high priority) 18 | * Expose Symfony View Globals such as the User through Zend_View 19 | * Re-implement the Controller Plugin cycle (currently: use Symfony internals to port your plugins) 20 | * All the inflection madness with dashes, lowercase, uppercase whatnot routing to controller/action naming. Currently only simple inflection is used. 21 | * Context handling: The ContextSwitch and AjaxContext helpers are not ported yet. 22 | * Have a console task to import a module from a ZF Project and do some work of the steps Installation automatically. 23 | 24 | ### What it will never do 25 | 26 | * Make Zend Application code reusable (Use the dependency injection container) 27 | * Handle calls to Zend_Controller_FrontController, you have to get rid of them. 28 | * Make the ActionStack Helper work. This concept is flawed and should be replaced with calls to $this->action() in the view, which replaces it with Symfony internal functionality that is dispatching actions very fast. 29 | 30 | ### Example 31 | 32 | In the ZFMvcCompatBundle\Resources\examples folder is an example bundle that implements the Guestbook tutorial as 33 | a Symfony bundle using the compat layer. You can use it by adding "Application\ApplicationBundle()" as bundle to the Kernel, 34 | configure the autoloader to use "Application" as namespace and "Application_" as directory. You can configure 35 | the compat bundle with: 36 | 37 | whitewashing_zf_mvc_compat: 38 | default_layout_resource: "ApplicationBundle::layout.html.phtml" 39 | db_conn: 40 | adapter: pdo_mysql 41 | params: 42 | host: localhost 43 | username: root 44 | password: 45 | dbname: zfmvccompat 46 | 47 | The database schema is: 48 | 49 | CREATE TABLE `guestbook` ( 50 | `id` int(11) NOT NULL AUTO_INCREMENT, 51 | `email` varchar(32) NOT NULL DEFAULT 'noemail@test.com', 52 | `comment` text, 53 | `created` datetime NOT NULL, 54 | PRIMARY KEY (`id`) 55 | ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 56 | 57 | ## Installation 58 | 59 | 1. Add the bundle to your AppKernel::registerBundles() method: 60 | 61 | return array( 62 | //.. 63 | new Whitewashing\ZFMvcCompatBundle\WhitewashingZFMvcCompatBundle(), 64 | ); 65 | 66 | 2. Add the Whitewashing namespace to your autolod.php. 67 | 68 | 3. Register Zend_View as template engine in your config.yml: 69 | 70 | framework: 71 | templating: { engines: ["twig", "phtml"] } 72 | 73 | 4. Enable the Compat Bundle in config.yml: 74 | 75 | whitewashing_zf_mvc_compat: 76 | default_layout_resource: "MyBundle::layout.html.phtml" 77 | 78 | ## Usage 79 | 80 | It should be obvious that you won't be able to port your Zend Framework app to Symfony2 just by installing this bundle, manual labour will be necessary. 81 | Each Zend Framework module will need to be ported to a Symfony2 Bundle. 82 | 83 | 1. Create a bundle for your module. The Bundle Name should be "ModuleName" + "Bundle". So in the case of a "blog" module you need to call your Bundle class "BlogBundle". 84 | This can easily create clashes if you want to use a blog bundle built for Symfony in the future, but using this semantics you don't need to fix all your "_redirect", "_forward" 85 | and redirector helper calls. If you do want to use a another bundle name then make sure that whenever you specify $module in the Zend API you need that to be $module . "Bundle". 86 | 87 | 2. Move all controllers into the $BundleRoot."/Controller/" directory and namespace the classes according to PSR-0. src/Appliction/BlogBundle/Controller/PostController.php 88 | should become: 89 | 90 | namespace Application\BlogBundle\Controller; 91 | use Whitewashing\ZFMvcCompatBundle\Controller\ZendController; 92 | 93 | class PostController extends ZendController 94 | { 95 | } 96 | 97 | IMPORTANT: Since your Controllers are now inside a namespace you have to either "use" import all classes or prefix them with \. 98 | 99 | 3. Move all your views into $BundleRoot."/Resources/views" and rename the "default" context html views into "viewName.html.phtml" instead of "viewName.phtml" 100 | 101 | 4. Move your layout into $BundleRoot."/Resources/views/layout.html.phtml" 102 | 103 | Replace the call `$this->layout()->content` with `$this->content` 104 | 105 | Different layout blocks are NOT supported. Use `$this->action()` for that. 106 | 107 | 5. View Layer: Replace the scriptname in calls to $this->partial() and $this->partialLoop() with the symfony resources, for example: 108 | 109 | partial("HelloBundle:Test:partial.html.phtml", array("name" => "Someone else!")); ?> 110 | 111 | 6. Routing 112 | 113 | There is simple support for static and router routes in the compatibility layer through 114 | ``Whitewashing\ZFMvcCompatBundle\Router\Loader\ZFRouterLoader``. If you just use them you can 115 | use xml, ini or php Zend_Config inputs by defining for example the Guestbook example: 116 | 117 | guestbookzf: 118 | type: zfmvc 119 | resource: "@WhitewashingZFMvcCompatBundle/Resources/examples/Application/Resources/config/routing.ini" 120 | 121 | You should however convert all your Zend routes to Symfony routes, place them in a $BundleRoot."/Resources/routing.yml" and import 122 | them in your app/config/routing.yml. Additionally Symfony has no "catch-all" routes by default, so you have to make use 123 | of the catch all mechanism defined by the compat bundle: 124 | 125 | whitewashing_zf_mvc_compat: 126 | catchall_bundles: ["BlogBundle"] 127 | 128 | When this mechanism is enabled you can request: 129 | 130 | http://appuri/{module}/{controller}/{action} 131 | 132 | 7. Security and ACLs 133 | 134 | You probably implemented some kind of authentication, security and acl mechanism using controller plugins, Zend_Acl and 135 | Zend_Auth. You have to use Zend_Acl inside a kernel event, preferably after routing took place to reimplement that logic. 136 | 137 | ## Semantic differences 138 | 139 | ### FrontController 140 | 141 | Every code statically referencing the FrontController WILL fail. There is 142 | no such thing as a static/singleton front controller. Get the resources you 143 | need through the DIC. 144 | 145 | ### Request 146 | 147 | * Zend_Controller_Request_Http::__get does check for $_ENV and the PATH_INFO or REQUEST_URI keys. 148 | * Zend_Controller_Request_Http Aliases for params are not supported 149 | * Zend_Controller_Request_Http setters are not implemented 150 | 151 | ### Response 152 | 153 | * setHeader(), getHeader(), clearHeader() dont normalize the header key. 154 | * setRawHeader(), getRawHeader(), getRawHeaders() are not implemented 155 | * canSendHeaders(), sendHeaders() not implemented 156 | * Named body segments are not implemented. Symfony2 uses multiple response instances for that. 157 | All methods referencing a code will only reference the default segment or throw an exception 158 | (append(), prepend(), insert()). 159 | * All exception related code is not implemented. 160 | 161 | ### Zend_Controller_Action 162 | 163 | * IMPORTANT: Make sure $this->_redirect and $this->_forward are always called with a leading "return" statement. 164 | * $this->view only calls to a ParameterBag that temporarily holds all view parameters. Calling view helpers inside the controller won't work! 165 | 166 | ### Zend_Controller_Action_HelperBroker 167 | 168 | The HelperBroker in this compatibility layer only implements the necessary ZF functionality. 169 | You cannot extend it with your own helpers. Use the Dependency Injenction container in the Controller and request services to use: 170 | 171 | class MyController extends ZendController 172 | { 173 | public function indexAction() 174 | { 175 | $this->get('my.action.helper')->doAction(); 176 | } 177 | } 178 | 179 | If someone cares please implement the helper broker as extensionable object, its 180 | in `Whitewashing\Zend\Mvc1CompatBundle\Controller\Helpers\HelperBroker`. It should 181 | use DIC tags to register helpers through an interface that has a getName() method 182 | and the regular action helper stuff. 183 | 184 | ### List of ported Action Helpers 185 | 186 | * Url 187 | * Redirector 188 | * ViewRenderer 189 | * Layout 190 | * FlashMessenger 191 | 192 | #### Url Action Helper 193 | 194 | * $this->getHelper('url')->url($urlOptions, $name) will not allow to include 'controller', 'module' or 'action' parameters in $urlOptions as the original Zend router allows. 195 | * $this->_helper->url($action, $ctrl, $module, $params) is an expensive method, iterating over the collection of all routes. 196 | * The third parameter of the UrlHelper#url method is now $absolute = true/false, the original third and fourth parameter $reset/$encode have been dropped. 197 | 198 | #### Zend Layout 199 | 200 | Parts of the API of `Zend_Layout` and the respective action helper has been ported, though it changed semantically. 201 | 202 | In your config.yml when defining the `zendmvc1.compat:` section you have to specify a "default_layout_resource" parameter, 203 | that takes of the form "BundleName::layoutFile.phtml" and resides in Bundle/Resources/views/layoutFile.phtml respectively. 204 | The following very common API calls work: 205 | 206 | $this->_helper->layout()->disableLayout(); 207 | $this->_helper->layout()->enableLayout(); 208 | $this->_helper->layout()->setLayout("HelloBundle::layout.phtml", $enable) 209 | 210 | As you can see, `setLayout` also expects a bundle resource, not a path anymore. You have to change all occurances 211 | throughout your code, but I doubt that will be many. 212 | 213 | #### View Renderer 214 | 215 | Only the functions setNoRender() and setNeverRender() have been ported. --------------------------------------------------------------------------------