Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Mvc / Controller / Plugin / FilePostRedirectGet.php
blobb88950506bbf533f463a65ddce1e5574118db1c4
1 <?php
3 /**
4 * Zend Framework (http://framework.zend.com/)
6 * @link http://github.com/zendframework/zf2 for the canonical source repository
7 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
8 * @license http://framework.zend.com/license/new-bsd New BSD License
9 */
11 namespace Zend\Mvc\Controller\Plugin;
13 use Zend\Filter\FilterChain;
14 use Zend\Form\FormInterface;
15 use Zend\Http\Response;
16 use Zend\InputFilter\FileInput;
17 use Zend\InputFilter\InputFilterInterface;
18 use Zend\Mvc\Exception\RuntimeException;
19 use Zend\Session\Container;
20 use Zend\Validator\ValidatorChain;
22 /**
23 * Plugin to help facilitate Post/Redirect/Get for file upload forms
24 * (http://en.wikipedia.org/wiki/Post/Redirect/Get)
26 * Requires that the Form's File inputs contain a 'fileRenameUpload' filter
27 * with the target option set: 'target' => /valid/target/path'.
28 * This is so the files are moved to a new location between requests.
29 * If this filter is not added, the temporary upload files will disappear
30 * between requests.
32 class FilePostRedirectGet extends AbstractPlugin
34 /**
35 * @var Container
37 protected $sessionContainer;
39 /**
40 * @param FormInterface $form
41 * @param string $redirect Route or URL string (default: current route)
42 * @param bool $redirectToUrl Use $redirect as a URL string (default: false)
43 * @return bool|array|Response
45 public function __invoke(FormInterface $form, $redirect = null, $redirectToUrl = false)
47 $request = $this->getController()->getRequest();
48 if ($request->isPost()) {
49 return $this->handlePostRequest($form, $redirect, $redirectToUrl);
50 } else {
51 return $this->handleGetRequest($form);
55 /**
56 * @param FormInterface $form
57 * @param string $redirect Route or URL string (default: current route)
58 * @param bool $redirectToUrl Use $redirect as a URL string (default: false)
59 * @return Response
61 protected function handlePostRequest(FormInterface $form, $redirect, $redirectToUrl)
63 $container = $this->getSessionContainer();
64 $request = $this->getController()->getRequest();
66 // Change required flag to false for any previously uploaded files
67 $inputFilter = $form->getInputFilter();
68 $previousFiles = ($container->files) ?: array();
69 $this->traverseInputs(
70 $inputFilter,
71 $previousFiles,
72 function ($input, $value) {
73 if ($input instanceof FileInput) {
74 $input->setRequired(false);
76 return $value;
80 // Run the form validations/filters and retrieve any errors
81 $postFiles = $request->getFiles()->toArray();
82 $postOther = $request->getPost()->toArray();
83 $post = array_merge_recursive($postOther, $postFiles);
85 // Validate form, and capture data and errors
86 $form->setData($post);
87 $isValid = $form->isValid();
88 $data = $form->getData(FormInterface::VALUES_AS_ARRAY);
89 $errors = (!$isValid) ? $form->getMessages() : null;
91 // Merge and replace previous files with new valid files
92 $prevFileData = $this->getEmptyUploadData($inputFilter, $previousFiles);
93 $newFileData = $this->getNonEmptyUploadData($inputFilter, $data);
94 $postFiles = array_merge_recursive(
95 $prevFileData ?: array(),
96 $newFileData ?: array()
98 $post = array_merge_recursive($postOther, $postFiles);
100 // Save form data in session
101 $container->setExpirationHops(1, array('post', 'errors', 'isValid'));
102 $container->post = $post;
103 $container->errors = $errors;
104 $container->isValid = $isValid;
105 $container->files = $postFiles;
107 return $this->redirect($redirect, $redirectToUrl);
111 * @param FormInterface $form
112 * @return bool|array
114 protected function handleGetRequest(FormInterface $form)
116 $container = $this->getSessionContainer();
117 if (null === $container->post) {
118 // No previous post, bail early
119 unset($container->files);
120 return false;
123 // Collect data from session
124 $post = $container->post;
125 $errors = $container->errors;
126 $isValid = $container->isValid;
127 $previousFiles = ($container->files) ?: array();
128 unset($container->post);
129 unset($container->errors);
130 unset($container->isValid);
132 // Remove File Input validators and filters on previously uploaded files
133 // in case $form->isValid() or $form->bindValues() is run
134 $inputFilter = $form->getInputFilter();
135 $this->traverseInputs(
136 $inputFilter,
137 $post,
138 function ($input, $value) {
139 if ($input instanceof FileInput) {
140 $input->setAutoPrependUploadValidator(false)
141 ->setValidatorChain(new ValidatorChain())
142 ->setFilterChain(new FilterChain);
144 return $value;
148 // Fill form with previous info and state
149 $form->setData($post);
150 $form->isValid(); // re-validate to bind values
151 if (null !== $errors) {
152 $form->setMessages($errors); // overwrite messages
154 $this->setProtectedFormProperty($form, 'isValid', $isValid); // force previous state
156 // Clear previous files from session data if form was valid
157 if ($isValid) {
158 unset($container->files);
161 return $post;
165 * @return Container
167 public function getSessionContainer()
169 if (!isset($this->sessionContainer)) {
170 $this->sessionContainer = new Container('file_prg_post1');
172 return $this->sessionContainer;
176 * @param Container $container
177 * @return FilePostRedirectGet
179 public function setSessionContainer(Container $container)
181 $this->sessionContainer = $container;
182 return $this;
186 * @param FormInterface $form
187 * @param string $property
188 * @param mixed $value
189 * @return FilePostRedirectGet
191 protected function setProtectedFormProperty(FormInterface $form, $property, $value)
193 $formClass = new \ReflectionClass($form);
194 $property = $formClass->getProperty($property);
195 $property->setAccessible(true);
196 $property->setValue($form, $value);
197 return $this;
201 * Traverse the InputFilter and run a callback against each Input and associated value
203 * @param InputFilterInterface $inputFilter
204 * @param array $values
205 * @param callable $callback
206 * @return array|null
208 protected function traverseInputs(InputFilterInterface $inputFilter, $values, $callback)
210 $returnValues = null;
211 foreach ($values as $name => $value) {
212 if (!$inputFilter->has($name)) {
213 continue;
216 $input = $inputFilter->get($name);
217 if ($input instanceof InputFilterInterface && is_array($value)) {
218 $retVal = $this->traverseInputs($input, $value, $callback);
219 if (null !== $retVal) {
220 $returnValues[$name] = $retVal;
222 continue;
225 $retVal = $callback($input, $value);
226 if (null !== $retVal) {
227 $returnValues[$name] = $retVal;
230 return $returnValues;
234 * Traverse the InputFilter and only return the data of FileInputs that have an upload
236 * @param InputFilterInterface $inputFilter
237 * @param array $data
238 * @return array
240 protected function getNonEmptyUploadData(InputFilterInterface $inputFilter, $data)
242 return $this->traverseInputs(
243 $inputFilter,
244 $data,
245 function ($input, $value) {
246 $messages = $input->getMessages();
247 if (is_array($value) && $input instanceof FileInput && empty($messages)) {
248 $rawValue = $input->getRawValue();
249 if (
250 (isset($rawValue['error']) && $rawValue['error'] !== UPLOAD_ERR_NO_FILE)
251 || (isset($rawValue[0]['error']) && $rawValue[0]['error'] !== UPLOAD_ERR_NO_FILE)
253 return $value;
256 return null;
262 * Traverse the InputFilter and only return the data of FileInputs that are empty
264 * @param InputFilterInterface $inputFilter
265 * @param array $data
266 * @return array
268 protected function getEmptyUploadData(InputFilterInterface $inputFilter, $data)
270 return $this->traverseInputs(
271 $inputFilter,
272 $data,
273 function ($input, $value) {
274 $messages = $input->getMessages();
275 if (is_array($value) && $input instanceof FileInput && empty($messages)) {
276 $rawValue = $input->getRawValue();
277 if ( (isset($rawValue['error']) && $rawValue['error'] === UPLOAD_ERR_NO_FILE)
278 || (isset($rawValue[0]['error']) && $rawValue[0]['error'] === UPLOAD_ERR_NO_FILE)
280 return $value;
283 return null;
289 * TODO: Good candidate for traits method in PHP 5.4 with PostRedirectGet plugin
291 * @param string $redirect
292 * @param bool $redirectToUrl
293 * @return Response
294 * @throws \Zend\Mvc\Exception\RuntimeException
296 protected function redirect($redirect, $redirectToUrl)
298 $controller = $this->getController();
299 $params = array();
300 $options = array();
301 $reuseMatchedParams = false;
303 if (null === $redirect) {
304 $routeMatch = $controller->getEvent()->getRouteMatch();
306 $redirect = $routeMatch->getMatchedRouteName();
307 //null indicates to redirect for self.
308 $reuseMatchedParams = true;
311 if (method_exists($controller, 'getPluginManager')) {
312 // get the redirect plugin from the plugin manager
313 $redirector = $controller->getPluginManager()->get('Redirect');
314 } else {
316 * If the user wants to redirect to a route, the redirector has to come
317 * from the plugin manager -- otherwise no router will be injected
319 if ($redirectToUrl === false) {
320 throw new RuntimeException('Could not redirect to a route without a router');
323 $redirector = new Redirect();
326 if ($redirectToUrl === false) {
327 $response = $redirector->toRoute($redirect, $params, $options, $reuseMatchedParams);
328 $response->setStatusCode(303);
329 return $response;
332 $response = $redirector->toUrl($redirect);
333 $response->setStatusCode(303);
335 return $response;