/** * This method passes through an HTTP request to another webserver. * This proxy is used to avoid any cross domain issues. The proxy * uses a white-list of domains to minimize security risks. * * @param SS_HTTPRequest $data array of parameters * * $data['u']: URL (complete request string) * $data['no_header']: set to '1' to avoid sending header information * directly. * @return the CURL response */ public function dorequest($data) { $headers = array(); $vars = $data->requestVars(); $no_header = false; if (!isset($vars['u'])) { return "Invalid request: unknown proxy destination."; } $url = $vars['u']; if (isset($vars['no_header']) && $vars['no_header'] == '1') { $no_header = true; } $checkUrl = explode("/", $url); if (!in_array($checkUrl[2], self::get_allowed_host())) { return "Access denied to ({$url})."; } // Open the Curl session $session = curl_init($url); // If it's a POST, put the POST data in the body $isPost = $data->isPOST(); if ($isPost) { $postvars = ''; $vars = $data->getBody(); if ($vars) { $postvars = "body=" . $vars; } else { $vars = $data->postVars(); if ($vars) { foreach ($vars as $k => $v) { $postvars .= $k . '=' . $v . '&'; } } } $headers[] = 'Content-type: text/xml'; curl_setopt($session, CURLOPT_HTTPHEADER, $headers); curl_setopt($session, CURLOPT_POST, true); curl_setopt($session, CURLOPT_POSTFIELDS, $postvars); } // Don't return HTTP headers. Do return the contents of the call curl_setopt($session, CURLOPT_HEADER, false); curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Make the call $xml = curl_exec($session); // The web service returns XML. Set the Content-Type appropriately if ($no_header == false) { header("Content-Type: text/xml"); } curl_close($session); return $xml; }
/** * @param SS_HTTPRequest $req * @return string */ public function search_suggest(SS_HTTPRequest $req) { /** @var SS_HTTPResponse $response */ $response = $this->owner->getResponse(); $callback = $req->requestVar('callback'); // convert the search results into usable json for search-as-you-type if (ShopSearch::config()->search_as_you_type_enabled) { $searchVars = $req->requestVars(); $searchVars[ShopSearch::config()->qs_query] = $searchVars['term']; unset($searchVars['term']); $results = ShopSearch::inst()->suggestWithResults($searchVars); } else { $results = array('suggestions' => ShopSearch::inst()->suggest($req->requestVar('term'))); } if ($callback) { $response->addHeader('Content-type', 'application/javascript'); $response->setBody($callback . '(' . json_encode($results) . ');'); } else { $response->addHeader('Content-type', 'application/json'); $response->setBody(json_encode($results)); } return $response; }
public function testRequestVars() { $getVars = array('first' => 'a', 'second' => 'b'); $postVars = array('third' => 'c', 'fourth' => 'd'); $requestVars = array('first' => 'a', 'second' => 'b', 'third' => 'c', 'fourth' => 'd'); $request = new SS_HTTPRequest('POST', 'admin/crm', $getVars, $postVars); $this->assertEquals($requestVars, $request->requestVars(), 'GET parameters should supplement POST parameters'); $getVars = array('first' => 'a', 'second' => 'b'); $postVars = array('first' => 'c', 'third' => 'd'); $requestVars = array('first' => 'c', 'second' => 'b', 'third' => 'd'); $request = new SS_HTTPRequest('POST', 'admin/crm', $getVars, $postVars); $this->assertEquals($requestVars, $request->requestVars(), 'POST parameters should override GET parameters'); $getVars = array('first' => array('first' => 'a'), 'second' => array('second' => 'b')); $postVars = array('first' => array('first' => 'c'), 'third' => array('third' => 'd')); $requestVars = array('first' => array('first' => 'c'), 'second' => array('second' => 'b'), 'third' => array('third' => 'd')); $request = new SS_HTTPRequest('POST', 'admin/crm', $getVars, $postVars); $this->assertEquals($requestVars, $request->requestVars(), 'Nested POST parameters should override GET parameters'); $getVars = array('first' => array('first' => 'a'), 'second' => array('second' => 'b')); $postVars = array('first' => array('second' => 'c'), 'third' => array('third' => 'd')); $requestVars = array('first' => array('first' => 'a', 'second' => 'c'), 'second' => array('second' => 'b'), 'third' => array('third' => 'd')); $request = new SS_HTTPRequest('POST', 'admin/crm', $getVars, $postVars); $this->assertEquals($requestVars, $request->requestVars(), 'Nested GET parameters should supplement POST parameters'); }
/** * @param SS_HTTPRequest $request * * @return string */ public function deploySummary(SS_HTTPRequest $request) { // Performs canView permission check by limiting visible projects $project = $this->getCurrentProject(); if (!$project) { return $this->project404Response(); } // Performs canView permission check by limiting visible projects $environment = $this->getCurrentEnvironment($project); if (!$environment) { return $this->environment404Response(); } // Plan the deployment. $strategy = $environment->Backend()->planDeploy($environment, $request->requestVars()); $data = $strategy->toArray(); // Add in a URL for comparing from->to code changes. Ensure that we have // two proper 40 character SHAs, otherwise we can't show the compare link. $interface = $project->getRepositoryInterface(); if (!empty($interface) && !empty($interface->URL) && !empty($data['changes']['Code version']['from']) && strlen($data['changes']['Code version']['from']) == '40' && !empty($data['changes']['Code version']['to']) && strlen($data['changes']['Code version']['to']) == '40') { $compareurl = sprintf('%s/compare/%s...%s', $interface->URL, $data['changes']['Code version']['from'], $data['changes']['Code version']['to']); $data['changes']['Code version']['compareUrl'] = $compareurl; } // Append json to response $token = SecurityToken::inst(); $data['SecurityID'] = $token->getValue(); return json_encode($data); }
/** * This is the action that gets executed when a GridField_AlterAction gets clicked. * * @param array $data * @param Form $form * @param SS_HTTPRequest $request * * @return string */ public function gridFieldAlterAction($data, $form, SS_HTTPRequest $request) { $data = $request->requestVars(); $name = $this->getName(); $fieldData = null; if (isset($data[$name])) { $fieldData = $data[$name]; } $state = $this->getState(false); if (isset($fieldData['GridState'])) { $state->setValue($fieldData['GridState']); } foreach ($data as $dataKey => $dataValue) { if (preg_match('/^action_gridFieldAlterAction\\?StateID=(.*)/', $dataKey, $matches)) { $stateChange = Session::get($matches[1]); $actionName = $stateChange['actionName']; $arguments = array(); if (isset($stateChange['args'])) { $arguments = $stateChange['args']; } $html = $this->handleAlterAction($actionName, $arguments, $data); if ($html) { return $html; } } } if ($request->getHeader('X-Pjax') === 'CurrentField') { return $this->FieldHolder(); } return $form->forTemplate(); }
/** * This is the action that gets executed when a GridField_AlterAction gets clicked. * * @param array $data * @return string */ public function gridFieldAlterAction($data, $form, SS_HTTPRequest $request) { $html = ''; $data = $request->requestVars(); $fieldData = @$data[$this->getName()]; // Update state from client $state = $this->getState(false); if(isset($fieldData['GridState'])) $state->setValue($fieldData['GridState']); // Try to execute alter action foreach($data as $k => $v) { if(preg_match('/^action_gridFieldAlterAction\?StateID=(.*)/', $k, $matches)) { $id = $matches[1]; $stateChange = Session::get($id); $actionName = $stateChange['actionName']; $args = isset($stateChange['args']) ? $stateChange['args'] : array(); $html = $this->handleAction($actionName, $args, $data); // A field can optionally return its own HTML if($html) return $html; } } switch($request->getHeader('X-Pjax')) { case 'CurrentField': return $this->FieldHolder(); break; case 'CurrentForm': return $form->forTemplate(); break; default: return $form->forTemplate(); break; } }
/** * Handle a form submission. GET and POST requests behave identically. * Populates the form with {@link loadDataFrom()}, calls {@link validate()}, * and only triggers the requested form action/method * if the form is valid. * * @param SS_HTTPRequest $request * @throws SS_HTTPResponse_Exception */ public function httpSubmission($request) { // Strict method check if ($this->strictFormMethodCheck) { // Throws an error if the method is bad... if ($this->formMethod != $request->httpMethod()) { $response = Controller::curr()->getResponse(); $response->addHeader('Allow', $this->formMethod); $this->httpError(405, _t("Form.BAD_METHOD", "This form requires a " . $this->formMethod . " submission")); } // ...and only uses the variables corresponding to that method type $vars = $this->formMethod == 'GET' ? $request->getVars() : $request->postVars(); } else { $vars = $request->requestVars(); } // Populate the form $this->loadDataFrom($vars, true); // Protection against CSRF attacks $token = $this->getSecurityToken(); if (!$token->checkRequest($request)) { $securityID = $token->getName(); if (empty($vars[$securityID])) { $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", "There seems to have been a technical problem. Please click the back button, " . "refresh your browser, and try again.")); } else { // Clear invalid token on refresh $data = $this->getData(); unset($data[$securityID]); Session::set("FormInfo.{$this->FormName()}.data", $data); Session::set("FormInfo.{$this->FormName()}.errors", array()); $this->sessionMessage(_t("Form.CSRF_EXPIRED_MESSAGE", "Your session has expired. Please re-submit the form."), "warning"); return $this->controller->redirectBack(); } } // Determine the action button clicked $funcName = null; foreach ($vars as $paramName => $paramVal) { if (substr($paramName, 0, 7) == 'action_') { // Break off querystring arguments included in the action if (strpos($paramName, '?') !== false) { list($paramName, $paramVars) = explode('?', $paramName, 2); $newRequestParams = array(); parse_str($paramVars, $newRequestParams); $vars = array_merge((array) $vars, (array) $newRequestParams); } // Cleanup action_, _x and _y from image fields $funcName = preg_replace(array('/^action_/', '/_x$|_y$/'), '', $paramName); break; } } // If the action wasn't set, choose the default on the form. if (!isset($funcName) && ($defaultAction = $this->defaultAction())) { $funcName = $defaultAction->actionName(); } if (isset($funcName)) { Form::set_current_action($funcName); $this->setButtonClicked($funcName); } // Permission checks (first on controller, then falling back to form) if ($this->controller->hasMethod($funcName) && !$this->controller->checkAccessAction($funcName) && !$this->actions->dataFieldByName('action_' . $funcName)) { return $this->httpError(403, sprintf('Action "%s" not allowed on controller (Class: %s)', $funcName, get_class($this->controller))); } elseif ($this->hasMethod($funcName) && !$this->checkAccessAction($funcName)) { return $this->httpError(403, sprintf('Action "%s" not allowed on form (Name: "%s")', $funcName, $this->name)); } // TODO : Once we switch to a stricter policy regarding allowed_actions (meaning actions must be set // explicitly in allowed_actions in order to run) // Uncomment the following for checking security against running actions on form fields /* else { // Try to find a field that has the action, and allows it $fieldsHaveMethod = false; foreach ($this->Fields() as $field){ if ($field->hasMethod($funcName) && $field->checkAccessAction($funcName)) { $fieldsHaveMethod = true; } } if (!$fieldsHaveMethod) { return $this->httpError( 403, sprintf('Action "%s" not allowed on any fields of form (Name: "%s")', $funcName, $this->Name()) ); } }*/ // Validate the form if (!$this->validate()) { return $this->getValidationErrorResponse(); } // First, try a handler method on the controller (has been checked for allowed_actions above already) if ($this->controller->hasMethod($funcName)) { return $this->controller->{$funcName}($vars, $this, $request); // Otherwise, try a handler method on the form object. } elseif ($this->hasMethod($funcName)) { return $this->{$funcName}($vars, $this, $request); } elseif ($field = $this->checkFieldsForAction($this->Fields(), $funcName)) { return $field->{$funcName}($vars, $this, $request); } return $this->httpError(404); }
/** * Handles all contexts * !TODO - handle more than one model in one request * * @param SS_HTTPRequest $req * @return SS_HTTPResponse * @throws Exception */ public function index(SS_HTTPRequest $req) { $model = $req->requestVar('model'); if (!$model) { return $this->fail(400); } // allow different date formats for different clients (eg. android) if ($df = $req->requestVar('date_format')) { self::$date_format = $df; } // this just makes the crossdomain ajax stuff simpler and // keeps anything weird from happening there. if (self::$allow_crossdomain && $_SERVER['REQUEST_METHOD'] === 'OPTIONS') { // $response = $this->getResponse(); // $response->addHeader("Access-Control-Allow-Origin", "*"); // $response->addHeader("Access-Control-Allow-Headers", "X-Requested-With"); // return $response; header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Headers: X-Requested-With"); exit; } //Debug::log(print_r($req->requestVars(),true)); // find the configuration $context = SyncContext::current(); if (!$context) { return $this->fail(400); } $cfg = $context->getConfig($model); // is syncing this model allowed? if (!$cfg || !is_array($cfg) || !isset($cfg['type']) || $cfg['type'] == SYNC_NONE) { return $this->fail(403, 'Access denied'); } $fields = isset($cfg['fields']) ? explode(',', $cfg['fields']) : array_keys(singleton($model)->db()); if (count($fields) == 0) { return $this->fail(403, 'Access denied'); } $fieldFilters = SyncFilterHelper::process_fields($fields); $fieldFilters['ID'] = false; $fieldFilters['LastEdited'] = false; $fields = array_keys($fieldFilters); // do we need to swap out for a parent table or anything? if (isset($cfg['model'])) { $model = $cfg['model']; } // build up the rest of the config with defaults if (!isset($cfg['filter'])) { $cfg['filter'] = array(); } if (!isset($cfg['join'])) { $cfg['join'] = array(); } if (!isset($cfg['sort'])) { $cfg['sort'] = ''; } if (!isset($cfg['limit'])) { $cfg['limit'] = ''; } // check authentication if (!$context->checkAuth($req->requestVars())) { return $this->fail(403, 'Incorrect or invalid authentication'); } // there are a few magic values that can be used in the filters: // :future // :last X days $cfg['filter'] = SyncFilterHelper::process_filters($cfg['filter']); // fill in any blanks in the filters based on the request input $replacements = $context->getFilterVariables($req->requestVars()); $cfg['filter'] = str_replace(array_keys($replacements), array_values($replacements), $cfg['filter']); // input arrays $insert = $req->requestVar('insert') ? json_decode($req->requestVar('insert'), true) : array(); $check = $req->requestVar('check') ? json_decode($req->requestVar('check'), true) : array(); $update = $req->requestVar('update') ? json_decode($req->requestVar('update'), true) : array(); // output arrays $clientSend = array(); $clientInsert = array(); $clientUpdate = array(); $clientDelete = array(); // check modification times on any existing records // NOTE: if update is set we assume this is the second request (#3 above) if (count($update) == 0) { if ($cfg['type'] == SYNC_DOWN || $cfg['type'] == SYNC_FULL) { $list = DataObject::get($model); if ($cfg['filter']) { $list = $list->filter($cfg['filter']); } if ($cfg['sort']) { $list = $list->sort($cfg['sort']); } if ($cfg['limit']) { $list = $list->limit($cfg['limit']); } if ($cfg['join'] && count($cfg['join']) > 0) { if (!is_array($cfg['join'])) { throw new Exception('Invalid join syntax'); } $fn = count($cfg['join']) > 2 ? $cfg['join'] . 'Join' : 'innerJoin'; $list = $list->{$fn}($cfg['join'][0], $cfg['join'][1]); } //$map = $list->map('ID', 'LastEdited'); $map = array(); $objMap = array(); foreach ($list as $rec) { $map[$rec->ID] = strtotime($rec->LastEdited); $objMap[$rec->ID] = $rec; } // take out the id's that are up-to-date form the map // also add any inserts and deletes at this point if (is_array($check)) { foreach ($check as $rec) { if (isset($map[$rec['ID']])) { $serverTS = $map[$rec['ID']]; $clientTS = max($rec['TS'], 0); if ($serverTS > $clientTS) { // the server is newer than the client // mark it to be sent back as a clientUpdate $clientUpdate[] = self::to_array($objMap[$rec['ID']], $fields, $fieldFilters); } elseif ($clientTS > $serverTS) { // the version on the client is newer than the server // add it to the clientSend list (i.e. request the data back from the client) $clientSend[] = $rec['ID']; } else { // the versions are the same, leave well enough alone } // $objMap is now our insert list, so we remove this id from it unset($objMap[$rec['ID']]); } else { // if it's present on the client WITH an ID but not present // on the server, it means we've deleted it and need to notify // the client $clientDelete[] = $rec['ID']; } } } // anything left on the $map right now needs to be inserted if (count($objMap) > 0) { foreach ($objMap as $id => $obj) { $clientInsert[] = self::to_array($obj, $fields, $fieldFilters); } } } // insert any new records if (($cfg['type'] == SYNC_FULL || $cfg['type'] == SYNC_UP) && is_array($insert)) { foreach ($insert as $rec) { unset($rec['ID']); unset($rec['LocalID']); $obj = new $model(); $obj->castedUpdate(self::filter_fields($rec, $fields)); $obj->write(); // send the object back so it gets an id, etc if ($cfg['type'] == SYNC_FULL) { $clientInsert[] = self::to_array($obj, $fields, $fieldFilters); } } } // NOTE: for SYNC_UP, if there do happen to be any records left // on the client, we want to tell it to delete them. that probably // means the model has changed from sync_full to sync_up OR // there was a bug at some point. Best to clean up the mess. if ($cfg['type'] == SYNC_UP && is_array($check) && count($check) > 0) { foreach ($check as $rec) { $clientDelete[] = $rec['ID']; } } } else { if (($cfg['type'] == SYNC_FULL || $cfg['type'] == SYNC_UP) && is_array($update)) { // update records foreach ($update as $rec) { $obj = DataObject::get_by_id($model, $rec['ID']); unset($rec['ID']); unset($rec['LocalID']); unset($rec['ClassName']); $obj->castedUpdate(self::filter_fields($rec, $fields)); $obj->write(); } } } // respond return $this->respond(array('ok' => 1, 'send' => $clientSend, 'update' => $clientUpdate, 'insert' => $clientInsert, 'del' => $clientDelete)); }
/** * This is the action that gets executed when a GridField_AlterAction gets clicked. * * @param array $data * @param Form $form * @param SS_HTTPRequest $request * * @return string */ public function gridFieldAlterAction($data, $form, SS_HTTPRequest $request) { $data = $request->requestVars(); // Protection against CSRF attacks $token = $this->getForm()->getSecurityToken(); if (!$token->checkRequest($request)) { $this->httpError(400, _t("Form.CSRF_FAILED_MESSAGE", "There seems to have been a technical problem. Please click the back button, " . "refresh your browser, and try again.")); } $name = $this->getName(); $fieldData = null; if (isset($data[$name])) { $fieldData = $data[$name]; } $state = $this->getState(false); if (isset($fieldData['GridState'])) { $state->setValue($fieldData['GridState']); } foreach ($data as $dataKey => $dataValue) { if (preg_match('/^action_gridFieldAlterAction\\?StateID=(.*)/', $dataKey, $matches)) { $stateChange = Session::get($matches[1]); $actionName = $stateChange['actionName']; $arguments = array(); if (isset($stateChange['args'])) { $arguments = $stateChange['args']; } $html = $this->handleAlterAction($actionName, $arguments, $data); if ($html) { return $html; } } } if ($request->getHeader('X-Pjax') === 'CurrentField') { return $this->FieldHolder(); } return $form->forTemplate(); }
/** * Handles requests to reorder a set of IDs in a specific order. * * @param GridField $grid * @param SS_HTTPRequest $request * @return SS_HTTPResponse */ public function handleReorder($grid, $request) { $list = $grid->getList(); $modelClass = $grid->getModelClass(); if ($list instanceof ManyManyList && !singleton($modelClass)->canView()) { $this->httpError(403); } else { if (!$list instanceof ManyManyList && !singleton($modelClass)->canEdit()) { $this->httpError(403); } } $ids = $request->postVar('order'); $field = $this->getSortField(); if (!is_array($ids)) { $this->httpError(400); } $sortterm = ''; if ($this->extraSortFields) { if (is_array($this->extraSortFields)) { foreach ($this->extraSortFields as $col => $dir) { $sortterm .= "{$col} {$dir}, "; } } else { $sortterm = $this->extraSortFields . ', '; } } $sortterm .= '"' . $this->getSortTable($list) . '"."' . $field . '"'; $items = $list->filter('ID', $ids)->sort($sortterm); // Ensure that each provided ID corresponded to an actual object. if (count($items) != count($ids)) { $this->httpError(404); } // Save any un-comitted changes to the gridfield if (($form = $grid->getForm()) && ($record = $form->getRecord())) { $form->loadDataFrom($request->requestVars(), true); $grid->saveInto($record); } // Populate each object we are sorting with a sort value. $this->populateSortValues($items); // Generate the current sort values. if ($items instanceof ManyManyList) { $current = array(); foreach ($items->toArray() as $record) { // NOTE: _SortColumn0 is the first ->sort() field // used by SS when functions are detected in a SELECT // or CASE WHEN. if (isset($record->_SortColumn0)) { $current[$record->ID] = $record->_SortColumn0; } else { $current[$record->ID] = $record->{$field}; } } } else { $current = $items->map('ID', $field)->toArray(); } // Perform the actual re-ordering. $this->reorderItems($list, $current, $ids); return $grid->FieldHolder(); }
/** * Method to determine what to do with the request and returns what will be processed * by the output processor * @param \SS_HTTPRequest $request * @return array */ public function process(\SS_HTTPRequest $request) { $data = $request->requestVars(); $shippingFields = $this->shippingHandler->getDynamicMethods(); // populate defaults foreach ($data as $key => $value) { if (in_array($key, $shippingFields)) { if ($key === 'Country') { $this->shippingHandler->setCountry(new Identifier($value)); } else { $this->shippingHandler->{$key} = $value; } } } // errors $errors = []; if (!isset($data['BillingFirstName']) || !$data['BillingFirstName']) { $errors['BillingFirstName_Error'] = ['Error' => 'Please enter a first name.']; } if (!isset($data['BillingSurname']) || !$data['BillingSurname']) { $errors['BillingSurname_Error'] = ['Error' => 'Please enter a surname.']; } if (!isset($data['BillingEmail']) || !filter_var($data['BillingEmail'], FILTER_VALIDATE_EMAIL)) { $errors['BillingEmail_Error'] = ['Error' => 'Please enter an email address.']; } if (!isset($data['BillingAddressLine1']) || !$data['BillingAddressLine1']) { $errors['BillingAddressLine1_Error'] = ['Error' => 'Please enter an address.']; } if (!isset($data['BillingCity']) || !$data['BillingAddressLine1']) { $errors['BillingCity_Error'] = ['Error' => 'Please enter a city.']; } if (!isset($data['BillingPostcode']) || !$data['BillingPostcode']) { $errors['BillingPostcode_Error'] = ['Error' => 'Please enter a postcode.']; } if (!isset($data['BillingCountry']) || !$data['BillingCountry']) { $errors['BillingCountry_Error'] = ['Error' => 'Please select a country.']; } // if the delivery is billing, populate those fields that we can if ($data['delivery'] == 'billing') { $this->shippingHandler->BillingAsShipping = true; $this->shippingHandler->FirstName = $data['BillingFirstName']; $this->shippingHandler->Surname = $data['BillingSurname']; $this->shippingHandler->Email = $data['BillingEmail']; $this->shippingHandler->AddressLine1 = $data['BillingAddressLine1']; $this->shippingHandler->AddressLine2 = $data['BillingAddressLine2']; $this->shippingHandler->City = $data['BillingCity']; $this->shippingHandler->Postcode = $data['BillingPostcode']; $this->shippingHandler->Country = $data['BillingCountry']; } else { if (!isset($data['FirstName']) || !$data['FirstName']) { $errors['FirstName_Error'] = ['Error' => 'Please enter a first name.']; } if (!isset($data['Surname']) || !$data['Surname']) { $errors['Surname_Error'] = ['Error' => 'Please enter a surname.']; } if (!isset($data['Email']) || !filter_var($data['Email'], FILTER_VALIDATE_EMAIL)) { $errors['Email_Error'] = ['Error' => 'Please enter an email address.']; } if (!isset($data['AddressLine1']) || !$data['AddressLine1']) { $errors['AddressLine1_Error'] = ['Error' => 'Please enter an address.']; } if (!isset($data['City']) || !$data['City']) { $errors['City_Error'] = ['Error' => 'Please enter a city.']; } if (!isset($data['Postcode']) || !$data['Postcode']) { $errors['Postcode_Error'] = ['Error' => 'Please enter a postcode.']; } if (!isset($data['Country']) || !$data['Country']) { $errors['Country_Error'] = ['Error' => 'Please select a country.']; } $this->shippingHandler->BillingAsShipping = false; $this->shippingHandler->FirstName = $data['BillingFirstName']; $this->shippingHandler->Surname = $data['BillingSurname']; $this->shippingHandler->Email = $data['BillingEmail']; } if (count($errors)) { return array_merge(['success' => false, 'Errors' => $errors], $data); } $this->shippingHandler->saveState(); return ['success' => true]; }
/** * Controller's default action handler. It will call the method named in "$Action", if that method * exists. If "$Action" isn't given, it will use "index" as a default. * * @param SS_HTTPRequest $request * @param string $action * * @return DBHTMLText|SS_HTTPResponse */ protected function handleAction($request, $action) { foreach ($request->latestParams() as $k => $v) { if ($v || !isset($this->urlParams[$k])) { $this->urlParams[$k] = $v; } } $this->action = $action; $this->requestParams = $request->requestVars(); if ($this->hasMethod($action)) { $result = parent::handleAction($request, $action); // If the action returns an array, customise with it before rendering the template. if (is_array($result)) { return $this->getViewer($action)->process($this->customise($result)); } else { return $result; } } // Fall back to index action with before/after handlers $beforeResult = $this->extend('beforeCallActionHandler', $request, $action); if ($beforeResult) { return reset($beforeResult); } $result = $this->getViewer($action)->process($this); $afterResult = $this->extend('afterCallActionHandler', $request, $action, $result); if ($afterResult) { return reset($afterResult); } return $result; }
/** * @param array $data * @param Form $form * @param SS_HTTPRequest $request * @return HTML|HTMLText|mixed */ public function gridFieldAlterAction($data, $form, SS_HTTPRequest $request) { $data = $request->requestVars(); $stateHash = $this->getStateHash(); // Check if we have encountered a reset action. We need to clear the state here before // the other components start accessing it. foreach ($data as $dataKey => $dataValue) { if (preg_match('/^action_gridFieldAlterAction\\?StateID=(.*)/', $dataKey, $matches)) { $stateChange = Session::get($matches[1]); $actionName = $stateChange['actionName']; if ($actionName === 'ResetState') { Session::set($stateHash, null); $this->state = new GridState($this); } } } foreach ($data as $dataKey => $dataValue) { if (preg_match('/^action_gridFieldAlterAction\\?StateID=(.*)/', $dataKey, $matches)) { $stateChange = Session::get($matches[1]); $actionName = $stateChange['actionName']; $arguments = array(); if (isset($stateChange['args'])) { $arguments = $stateChange['args']; } $html = $this->handleAlterAction($actionName, $arguments, $data); if ($html) { return $html; } } } // The state is stored in the session so that we can access it on the next page load $this->setStateHash($this->state->Value()); if ($request->getHeader('X-Pjax') === 'CurrentField') { return $this->FieldHolder(); } return $form->forTemplate(); }
/** * Handles requests to reorder a set of IDs in a specific order. * * @param GridField $grid * @param SS_HTTPRequest $request * @return SS_HTTPResponse */ public function handleReorder($grid, $request) { if (!$this->immediateUpdate) { $this->httpError(400); } $list = $grid->getList(); $modelClass = $grid->getModelClass(); if ($list instanceof ManyManyList && !singleton($modelClass)->canView()) { $this->httpError(403); } else { if (!$list instanceof ManyManyList && !singleton($modelClass)->canEdit()) { $this->httpError(403); } } // Save any un-committed changes to the gridfield if (($form = $grid->getForm()) && ($record = $form->getRecord())) { $form->loadDataFrom($request->requestVars(), true); $grid->saveInto($record); } // Get records from the `GridFieldEditableColumns` column $data = $request->postVar($grid->getName()); $sortedIDs = $this->getSortedIDs($data); if (!$this->executeReorder($grid, $sortedIDs)) { $this->httpError(400); } Controller::curr()->getResponse()->addHeader('X-Status', rawurlencode('Records reordered.')); return $grid->FieldHolder(); }
/** * @param SS_HTTPRequest $request * * @return DeploymentStrategy */ public function getDeployStrategy(\SS_HTTPRequest $request) { return $this->Backend()->planDeploy($this, $request->requestVars()); }