public function setInputFilter($inputFilter) { if (is_string($inputFilter)) { $inputFilters = $this->getFactory()->getInputFilterManager(); $inputFilter = $inputFilters->get($inputFilter); } return parent::setInputFilter($inputFilter); }
public function testEmptyCollectionIsNotValidIfRequired() { $data = array(); $this->filter->setInputFilter($this->getBaseInputFilter()); $this->filter->setData($data); $this->filter->setIsRequired(true); $this->assertFalse($this->filter->isValid()); }
/** * @group ZF2-5648 */ public function testCountZeroValidateInternalInputWithCollectionInputFilter() { $inputFilter = new InputFilter(); $inputFilter->add(new Input(), 'name'); $collection = new CollectionInputFilter(); $collection->setInputFilter($inputFilter); $collection->setCount(0); $this->filter->add($collection, 'people'); $data = array('people' => array(array('name' => 'Wanderson'))); $this->filter->setData($data); $this->assertTrue($this->filter->isvalid()); $this->assertSame($data, $this->filter->getValues()); }
private function setAllInputFilters() { $finalInputFilter = $this->createBaseInputFilter(); //set filters for entityProperties collection $propertyFieldset = new PropertyFieldset(); $propertiesFilter = new CollectionInputFilter(); $propertiesFilter->setInputFilter($propertyFieldset->getInputFilter()); $finalInputFilter->add($propertiesFilter, 'entityProperties'); //set filters for indexes collection $indexFieldset = new IndexFieldset(); $indexesFilter = new CollectionInputFilter(); $indexesFilter->setInputFilter($indexFieldset->getInputFilter()); $finalInputFilter->add($indexesFilter, 'indexes'); //set the completed input filter as the form's filter $this->setInputFilter($finalInputFilter); }
/** * @param Collection $collection */ protected function configureInputFilter(Collection $collection) { // Make it a collection input filter $inputFilter = new CollectionInputFilter(); $inputFilter->setIsRequired(false); // Add the input filter of the target document as the real input filter: $targetElement = $collection->getTargetElement(); if ($targetElement instanceof InputFilterProviderInterface) { $configuredFilter = $targetElement->getInputFilterSpecification(); $inputFilter->setInputFilter($configuredFilter); } // Replace the current input filter in the actual form: $collectionName = $collection->getName(); $formFilter = $this->form->getInputFilter(); $formFilter->remove($collectionName); $formFilter->add($inputFilter, $collectionName); }
/** * Attach defaults provided by the elements to the input filter * * @param InputFilterInterface $inputFilter * @param FieldsetInterface $fieldset Fieldset to traverse when looking for default inputs * @return void */ public function attachInputFilterDefaults(InputFilterInterface $inputFilter, FieldsetInterface $fieldset) { $formFactory = $this->getFormFactory(); $inputFactory = $formFactory->getInputFilterFactory(); if ($fieldset instanceof Collection && $fieldset->getTargetElement() instanceof FieldsetInterface) { $elements = $fieldset->getTargetElement()->getElements(); } else { $elements = $fieldset->getElements(); } if (!$fieldset instanceof Collection || !$fieldset->getTargetElement() instanceof FieldsetInterface || $inputFilter instanceof CollectionInputFilter) { foreach ($elements as $name => $element) { if ($this->preferFormInputFilter && $inputFilter->has($name)) { continue; } if (!$element instanceof InputProviderInterface) { if ($inputFilter->has($name)) { continue; } // Create a new empty default input for this element $spec = array('name' => $name, 'required' => false); $input = $inputFactory->createInput($spec); } else { // Create an input based on the specification returned from the element $spec = $element->getInputSpecification(); $input = $inputFactory->createInput($spec); if ($inputFilter->has($name) && $inputFilter instanceof ReplaceableInputInterface) { $input->merge($inputFilter->get($name)); $inputFilter->replace($input, $name); continue; } } // Add element input filter to CollectionInputFilter if ($inputFilter instanceof CollectionInputFilter && !$inputFilter->getInputFilter()->has($name)) { $inputFilter->getInputFilter()->add($input, $name); } else { $inputFilter->add($input, $name); } } if ($fieldset === $this && $fieldset instanceof InputFilterProviderInterface) { foreach ($fieldset->getInputFilterSpecification() as $name => $spec) { $input = $inputFactory->createInput($spec); $inputFilter->add($input, $name); } } } foreach ($fieldset->getFieldsets() as $name => $childFieldset) { if (!$childFieldset instanceof InputFilterProviderInterface) { if (!$inputFilter->has($name)) { // Add a new empty input filter if it does not exist (or the fieldset's object input filter), // so that elements of nested fieldsets can be recursively added if ($childFieldset->getObject() instanceof InputFilterAwareInterface) { $inputFilter->add($childFieldset->getObject()->getInputFilter(), $name); } else { // Add input filter for collections via getInputFilterSpecification() if ($childFieldset instanceof Collection && $childFieldset->getTargetElement() instanceof InputFilterProviderInterface && $childFieldset->getTargetElement()->getInputFilterSpecification()) { $collectionContainerFilter = new CollectionInputFilter(); $spec = $childFieldset->getTargetElement()->getInputFilterSpecification(); $filter = $inputFactory->createInputFilter($spec); $collectionContainerFilter->setInputFilter($filter); $inputFilter->add($collectionContainerFilter, $name); // We need to copy the inputs to the collection input filter if ($inputFilter instanceof CollectionInputFilter) { $inputFilter = $this->addInputsToCollectionInputFilter($inputFilter); } // Add child elements from target element $childFieldset = $childFieldset->getTargetElement(); } else { $inputFilter->add(new InputFilter(), $name); } } } $fieldsetFilter = $inputFilter->get($name); if (!$fieldsetFilter instanceof InputFilterInterface) { // Input attached for fieldset, not input filter; nothing more to do. continue; } // Traverse the elements of the fieldset, and attach any // defaults to the fieldset's input filter $this->attachInputFilterDefaults($fieldsetFilter, $childFieldset); continue; } if ($inputFilter->has($name)) { // if we already have an input/filter by this name, use it continue; } // Create an input filter based on the specification returned from the fieldset $spec = $childFieldset->getInputFilterSpecification(); $filter = $inputFactory->createInputFilter($spec); $inputFilter->add($filter, $name); // Recursively attach sub filters $this->attachInputFilterDefaults($filter, $childFieldset); // We need to copy the inputs to the collection input filter to ensure that all sub filters are added if ($inputFilter instanceof CollectionInputFilter) { $inputFilter = $this->addInputsToCollectionInputFilter($inputFilter); } } }
public function testNestedCollectionWithEmptyData() { $items_inputfilter = new BaseInputFilter(); $items_inputfilter->add(new Input(), 'id')->add(new Input(), 'type'); $items = new CollectionInputFilter(); $items->setInputFilter($items_inputfilter); $groups_inputfilter = new BaseInputFilter(); $groups_inputfilter->add(new Input(), 'group_class')->add($items, 'items'); $groups = new CollectionInputFilter(); $groups->setInputFilter($groups_inputfilter); $inputFilter = new BaseInputFilter(); $inputFilter->add($groups, 'groups'); $data = array('groups' => array(array('group_class' => 'bar', 'items' => array(array('id' => 100, 'type' => 'item-1'))), array('group_class' => 'biz', 'items' => array()), array('group_class' => 'bar', 'items' => array(array('id' => 200, 'type' => 'item-2'), array('id' => 300, 'type' => 'item-3'), array('id' => 400, 'type' => 'item-4'))))); $inputFilter->setData($data); $inputFilter->isValid(); $values = $inputFilter->getValues(); $this->assertEquals($data, $values); }
/** * Attempt to validate the incoming request * * If an input filter is associated with the matched controller service, * attempt to validate the incoming request, and inject the event with the * input filter, as the "ZF\ContentValidation\InputFilter" parameter. * * Uses the ContentNegotiation ParameterDataContainer to retrieve parameters * to validate, and returns an ApiProblemResponse when validation fails. * * Also returns an ApiProblemResponse in cases of: * * - Invalid input filter service name * - Missing ParameterDataContainer (i.e., ContentNegotiation is not registered) * * @param MvcEvent $e * @return null|ApiProblemResponse */ public function onRoute(MvcEvent $e) { $request = $e->getRequest(); if (! $request instanceof HttpRequest) { return; } $method = $request->getMethod(); if (in_array($method, $this->methodsWithoutBodies)) { return; } $routeMatches = $e->getRouteMatch(); if (! $routeMatches instanceof RouteMatch) { return; } $controllerService = $routeMatches->getParam('controller', false); if (! $controllerService) { return; } $inputFilterService = $this->getInputFilterService($controllerService, $method); if (! $inputFilterService) { return; } if (! $this->hasInputFilter($inputFilterService)) { return new ApiProblemResponse( new ApiProblem( 500, sprintf('Listed input filter "%s" does not exist; cannot validate request', $inputFilterService) ) ); } $dataContainer = $e->getParam('ZFContentNegotiationParameterData', false); if (! $dataContainer instanceof ParameterDataContainer) { return new ApiProblemResponse( new ApiProblem( 500, 'ZF\\ContentNegotiation module is not initialized; cannot validate request' ) ); } $data = $dataContainer->getBodyParams(); if (null === $data || '' === $data) { $data = array(); } $isCollection = $this->isCollection($controllerService, $data, $routeMatches, $request); $files = $request->getFiles(); if (! $isCollection && 0 < count($files)) { // File uploads are not validated for collections; impossible to // match file fields to discrete sets $data = array_merge_recursive($data, $files->toArray()); } $inputFilter = $this->getInputFilter($inputFilterService); if ($isCollection) { $collectionInputFilter = new CollectionInputFilter(); $collectionInputFilter->setInputFilter($inputFilter); $inputFilter = $collectionInputFilter; } $e->setParam('ZF\ContentValidation\InputFilter', $inputFilter); $events = $this->getEventManager(); $results = $events->trigger(self::EVENT_BEFORE_VALIDATE, $e, function ($result) { return ($result instanceof ApiProblem || $result instanceof ApiProblemResponse ); }); $last = $results->last(); if ($last instanceof ApiProblem) { $last = new ApiProblemResponse($last); } if ($last instanceof ApiProblemResponse) { return $last; } $inputFilter->setData($data); $status = ($request->isPatch()) ? $this->validatePatch($inputFilter, $data, $isCollection) : $inputFilter->isValid(); if ($status instanceof ApiProblemResponse) { return $status; } // Invalid? Return a 422 response. if (false === $status) { return new ApiProblemResponse( new ApiProblem(422, 'Failed Validation', null, null, array( 'validation_messages' => $inputFilter->getMessages(), )) ); } // Should we use the raw data vs. the filtered data? // - If no `use_raw_data` flag is present, always use the raw data, as // that was the default experience starting in 1.0. // - If the flag is present AND is boolean true, that is also // an indicator that the raw data should be present. if (! isset($this->config[$controllerService]['use_raw_data']) || (isset($this->config[$controllerService]['use_raw_data']) && $this->config[$controllerService]['use_raw_data'] === true) ) { $dataContainer->setBodyParams($data); return; } // If we don't have an instance of UnknownInputsCapableInterface, or no // unknown data is in the input filter, at this point we can just // set the input filter values directly into the data container. if (! $inputFilter instanceof UnknownInputsCapableInterface || ! $inputFilter->hasUnknown() ) { $dataContainer->setBodyParams($inputFilter->getValues()); return; } $bodyParams = $inputFilter->getValues(); $unknown = $inputFilter->getUnknown(); if ($this->allowsOnlyFieldsInFilter($controllerService)) { $fields = implode(', ', array_keys($unknown)); $detail = sprintf('Unrecognized fields: %s', $fields); $problem = new ApiProblem(Response::STATUS_CODE_422, $detail); return new ApiProblemResponse($problem); } $dataContainer->setBodyParams(array_merge($bodyParams, $unknown)); }
/** * Attempt to validate the incoming request * * If an input filter is associated with the matched controller service, * attempt to validate the incoming request, and inject the event with the * input filter, as the "ZF\ContentValidation\InputFilter" parameter. * * Uses the ContentNegotiation ParameterDataContainer to retrieve parameters * to validate, and returns an ApiProblemResponse when validation fails. * * Also returns an ApiProblemResponse in cases of: * * - Invalid input filter service name * - Missing ParameterDataContainer (i.e., ContentNegotiation is not registered) * * @param MvcEvent $e * @return null|ApiProblemResponse */ public function onRoute(MvcEvent $e) { $request = $e->getRequest(); if (!$request instanceof HttpRequest) { return; } $routeMatches = $e->getRouteMatch(); if (!($routeMatches instanceof RouteMatch || $routeMatches instanceof V2RouteMatch)) { return; } $controllerService = $routeMatches->getParam('controller', false); if (!$controllerService) { return; } $method = $request->getMethod(); $inputFilterService = $this->getInputFilterService($controllerService, $method); if (!$inputFilterService) { return; } if (!$this->hasInputFilter($inputFilterService)) { return new ApiProblemResponse(new ApiProblem(500, sprintf('Listed input filter "%s" does not exist; cannot validate request', $inputFilterService))); } $dataContainer = $e->getParam('ZFContentNegotiationParameterData', false); if (!$dataContainer instanceof ParameterDataContainer) { return new ApiProblemResponse(new ApiProblem(500, 'ZF\\ContentNegotiation module is not initialized; cannot validate request')); } $data = in_array($method, $this->methodsWithoutBodies) ? $dataContainer->getQueryParams() : $dataContainer->getBodyParams(); if (null === $data || '' === $data) { $data = []; } $isCollection = $this->isCollection($controllerService, $data, $routeMatches, $request); $files = $request->getFiles(); if (!$isCollection && 0 < count($files)) { // File uploads are not validated for collections; impossible to // match file fields to discrete sets $data = ArrayUtils::merge($data, $files->toArray(), true); } $inputFilter = $this->getInputFilter($inputFilterService); if ($isCollection && !in_array($method, $this->methodsWithoutBodies)) { $collectionInputFilter = new CollectionInputFilter(); $collectionInputFilter->setInputFilter($inputFilter); $inputFilter = $collectionInputFilter; } $e->setParam('ZF\\ContentValidation\\InputFilter', $inputFilter); $currentEventName = $e->getName(); $e->setName(self::EVENT_BEFORE_VALIDATE); $events = $this->getEventManager(); $results = $events->triggerEventUntil(function ($result) { return $result instanceof ApiProblem || $result instanceof ApiProblemResponse; }, $e); $e->setName($currentEventName); $last = $results->last(); if ($last instanceof ApiProblem) { $last = new ApiProblemResponse($last); } if ($last instanceof ApiProblemResponse) { return $last; } $inputFilter->setData($data); $status = $request->isPatch() ? $this->validatePatch($inputFilter, $data, $isCollection) : $inputFilter->isValid(); if ($status instanceof ApiProblemResponse) { return $status; } // Invalid? Return a 422 response. if (false === $status) { return new ApiProblemResponse(new ApiProblem(422, 'Failed Validation', null, null, ['validation_messages' => $inputFilter->getMessages()])); } // Should we use the raw data vs. the filtered data? // - If no `use_raw_data` flag is present, always use the raw data, as // that was the default experience starting in 1.0. // - If the flag is present AND is boolean true, that is also // an indicator that the raw data should be present. $useRawData = $this->useRawData($controllerService); if (!$useRawData) { $data = $inputFilter->getValues(); } // If we don't have an instance of UnknownInputsCapableInterface, or no // unknown data is in the input filter, at this point we can just // set the current data into the data container. if (!$inputFilter instanceof UnknownInputsCapableInterface || !$inputFilter->hasUnknown()) { $dataContainer->setBodyParams($data); return; } $unknown = $inputFilter->getUnknown(); if ($this->allowsOnlyFieldsInFilter($controllerService)) { if ($inputFilter instanceof CollectionInputFilter) { $unknownFields = []; foreach ($unknown as $key => $fields) { $unknownFields[] = '[' . $key . ': ' . implode(', ', array_keys($fields)) . ']'; } $fields = implode(', ', $unknownFields); } else { $fields = implode(', ', array_keys($unknown)); } $detail = sprintf('Unrecognized fields: %s', $fields); $problem = new ApiProblem(Response::STATUS_CODE_422, $detail); return new ApiProblemResponse($problem); } // The raw data already contains unknown inputs, so no need to merge // them with the data. if ($useRawData) { $dataContainer->setBodyParams($data); return; } // When not using raw data, we merge the unknown data with the // validated data to get the full set of input. $dataContainer->setBodyParams(array_merge($data, $unknown)); }