which URL pattern is better, action/id or id/action - url

I would like to know which of these 2 patterns would be better:
/photos/123/edit
or
/photos/edit/123
Currently I am using the first, which gives me a Whoops, looks like something went wrong. when I try /photos/123/editxx instead of a 404 not found.
routes:
I am unsure where to look for the mistake, these are the photos routes:
Route::get('photos/randpics','PhotosController#randpics');
Route::get('photos/{id}/edit','PhotosController#getEdit')->middleware(['auth']);
Route::post('photos/{id}/edit','PhotosController#postEdit')->middleware(['auth']);
Route::post('photos/{id}/retag', ['as' => 'photos.retag', 'uses' => 'PhotosController#retag'])->middleware(['auth']);
Route::post('photos/{id}/delete','PhotosController#delete')->middleware(['auth']);
Route::get('photos/{id}/albums', 'PhotosController#getAlbums')->middleware(['auth']);
Route::post('photos/{id}/albums', 'PhotosController#postAlbums')->middleware(['auth']);
Route::get('photos/{id}/detail','PhotosController#detail');
Route::get('photos/{id}','PhotosController#single');
Route::post('photos/like', 'PhotosController#postLike')->middleware(['auth']);
Route::post('photos/unlike', 'PhotosController#postUnlike')->middleware(['auth']);
Route::get('photos','PhotosController#index');
getEdit() and postEdit():
The same error, complaining about an undefined variable in the master layout template appears, when I enter /photos/123/a/a/a/ for example.
public function getEdit(Request $request, $id = null)
{
$pic = Pic::findOrFail($id);
if(Gate::denies('edit-pic',$pic)) {
abort(403);
}
$pic->text = htmlspecialchars($pic->text);
$years = array_combine(range(date("Y"), 1960), range(date("Y"), 1960));
$location = $pic->location;
$tags = $pic->tags;
$tagsarray = $pic->tagNames();
$albums = $pic->albums;
$locations = array();
$getlocations = Location::orderBy('city')->get();
foreach($getlocations as $gl)
{
$locations[$gl->id] = $gl->city.' ('.$gl->country.')';
}
$cats = Cat::lists('cat','cat')->all();
return view('photos.edit',compact('pic','location','tags','tagsarray','albums','locations','cats','years'));
}
public function postEdit(Request $request, $id = null)
{
$pic = Pic::findOrFail($id);
if(Gate::denies('edit-pic',$pic)) {
abort(403);
}
$this->validate($request, [
'title' => 'max:200',
'text' => 'max:3000',
'location' => 'required|exists:locations,id',
'cat' => 'required|exists:cats,cat',
'jahrprod' => 'date_format:Y'
]);
$pic->title = trim($request->input('title'));
$pic->text = trim($request->input('text'));
$pic->jahrprod = ($request->input('jahrprod')) ? $request->input('jahrprod') : null;
$pic->location_id = $request->input('location');
$pic->cat = $request->input('cat');
$pic->save();
#mail
$maildata = array(
'msg' => 'picture '.$id.' ( '.$request->input('title').' ) was edited by '.Auth::user()->username
);
Mail::send(['text' => 'emails.empty'], $maildata, function($message){
$message->to('xx#yy.de')->from('xx#yy.de')->subject('picture edited');
});
return back()->with('success','photo information updated');
}
Controller.php
It seems, with more than 2 URL segments, the Controller.php is not working properly. /domain.xy/1/2 shows the 8 but /domain.xy/1/2/3 throws the error Undefined variable: photos_online
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Auth;
use Cache;
use DB;
use App\Pic;
use App\Upload;
use Carbon\Carbon;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct()
{
dd(8);
//.......
}
}

If you follow laravel's resource controller guidelines
https://laravel.com/docs/5.2/controllers#restful-resource-controllers
You should go with the first one.
But to fix your problem show us your route and controller function handling it.
Update
open AppServiceProvider located in app/http/providers
and replace boot() function with this
public function boot()
{
//initilizw $photos_online
$photos_online = Cache::rememberForever('index_countpics', function()
{
return Pic::count();
});
#pics today
if (Cache::has('pics_today')){
$pics_today = Cache::get('pics_today');
}else{
$pics_today = Pic::whereRaw('DATE(created_at) = DATE(NOW())')->count();
Cache::put('pics_today', $pics_today, Carbon::tomorrow());
}
# count waiting uploads
$waiting_uploads = Cache::rememberForever('waiting_uploads', function()
{
return Upload::where('accepted',0)->where('infos',1)->count();
});
# user online
$client_ip = request()->ip();
$check = DB::table('useronline')->where('ip', $client_ip)->first();
$username = (Auth::guest()) ? null : Auth::user()->username;
$displayname = (Auth::guest()) ? null : Auth::user()->displayname;
if(is_null($check)){
DB::table('useronline')->insert(['ip' => $client_ip, 'datum' => DB::raw('NOW()'), 'username' => $username, 'displayname' => $displayname]);
}else{
DB::table('useronline')->where('ip', $client_ip)->update(['datum' => DB::raw('NOW()'), 'username' => $username, 'displayname' => $displayname]);
}
DB::delete('DELETE FROM useronline WHERE DATE_SUB(NOW(), INTERVAL 3 MINUTE) > datum');
$users_online = DB::table('useronline')->whereNotNull('username')->get();
$guests_online = DB::table('useronline')->count();
#unread messages
$unread_messages = 0;
if(Auth::check()){
$unread_messages = Auth::user()->newThreadsCount();
}
view()->share('photos_online',$photos_online);
view()->share('pics_today',$pics_today);
view()->share('waiting_uploads',$waiting_uploads);
view()->share('users_online',$users_online);
view()->share('guests_online',$guests_online);
view()->share('unread_messages',$unread_messages);
}

Related

Autocomplete with ajax in Symfony2

I'm using jQueryUI autocomplete to get a list of cities. I'm using a json array to display cities, but I just can't get the list to appear.
here is my Ajax function :
/**
* #Route("/ajax", name="ajax")
*/
public function ajaxAction(Request $request)
{
$value = $request->get('term');
$em = $this->getDoctrine()->getEntityManager();
$branches = $em->getRepository('AOFVHFlyBundle:City')
->findByName($value);
// Get branches by user if non-admin
$json = array();
foreach ($branches as $branch) {
$json[] = array(
'label' => sprintf('%s (%s)', $branch['name'], $branch['departement']),
'value' => $branch['id']
);
}
$response = new Response();
// better way to return json - via header?
$response->setContent(json_encode($json));
return $response;
}
and here is the form input :
->add('reqdeparture', 'genemu_jqueryautocompleter_entity', array(
'class' => 'AOFVH\FlyBundle\Entity\City',
'property' => 'name',
'route_name' => 'ajax',
'attr' => array(
'placeholder'=>'Départ',
'autocomplete' => 'on')
))
Whatever I type in the input, nothing appears.
Any idea why ? (at first I thought it was because collection was too big, but I barely have 50 cities)
You can use JsonResponse object. The Content-Type header will be 'application/json'. Symfony manage the chars to escape automatically and others conditions to return a JSON normalized correctly.
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* #Route("/ajax", name="ajax")
*/
public function ajaxAction(Request $request)
{
$value = $request->get('term');
$branches = $this->get("doctrine.orm.default_entity_manager")
->getRepository("NamespaceMyBundle:Entity")
->findByName($value);
$json = array();
foreach ($branches as $branch) {
$json[] = array(…);
}
return new JsonResponse($json);
}

How to hook tags to displayTopColumn in prestashop 1.6

Can somebody tell me how to display tags in TopColumn in prestashop 1.6?
I know that I must edit blogtags.php but I don't know how to do it - my PHP is too weak.
Of course I tried - now can I can hook tag in admin panel but not on website. What have I done?
.
.
.
function install()
{
$success = (parent::install() && $this->registerHook('header') && **$this->registerHook('displayTopColumn')** && Configuration::updateValue('BLOCKTAGS_NBR', 10));
if ($success)
.
.
.
public function hookdisplayTop($params)
{
return $this->hookdisplayTopColumn($params);
}
.
.
.
Full blogtags.php
if (!defined('_PS_VERSION_'))
exit;
define('BLOCKTAGS_MAX_LEVEL', 3);
class BlockTags extends Module
{
function __construct()
{
$this->name = 'blocktags';
$this->tab = 'front_office_features';
$this->version = '1.2.1';
$this->author = 'PrestaShop';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Tags block');
$this->description = $this->l('Adds a block containing your product tags.');
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
}
function install()
{
$success = (parent::install() && $this->registerHook('header') && $this->registerHook('displayTopColumn') && Configuration::updateValue('BLOCKTAGS_NBR', 10));
if ($success)
{
// Hook the module either on the left or right column
$theme = new Theme(Context::getContext()->shop->id_theme);
if ((!$theme->default_left_column || !$this->registerHook('leftColumn'))
&& (!$theme->default_right_column || !$this->registerHook('rightColumn'))
&& $this->registerHook('displayTopColumn'))
{
// If there are no colums implemented by the template, throw an error and uninstall the module
$this->_errors[] = $this->l('This module need to be hooked in a column and your theme does not implement one');
parent::uninstall();
return false;
}
}
return $success;
}
public function getContent()
{
$output = '';
if (Tools::isSubmit('submitBlockTags'))
{
if (!($tagsNbr = Tools::getValue('BLOCKTAGS_NBR')) || empty($tagsNbr))
$output .= $this->displayError($this->l('Please complete the "Displayed tags" field.'));
elseif ((int)($tagsNbr) == 0)
$output .= $this->displayError($this->l('Invalid number.'));
else
{
Configuration::updateValue('BLOCKTAGS_NBR', (int)$tagsNbr);
$output .= $this->displayConfirmation($this->l('Settings updated'));
}
}
return $output.$this->renderForm();
}
/**
* Returns module content for left column
*
* #param array $params Parameters
* #return string Content
*
*/
function hookLeftColumn($params)
{
$tags = Tag::getMainTags((int)($params['cookie']->id_lang), (int)(Configuration::get('BLOCKTAGS_NBR')));
$max = -1;
$min = -1;
foreach ($tags as $tag)
{
if ($tag['times'] > $max)
$max = $tag['times'];
if ($tag['times'] < $min || $min == -1)
$min = $tag['times'];
}
if ($min == $max)
$coef = $max;
else
{
$coef = (BLOCKTAGS_MAX_LEVEL - 1) / ($max - $min);
}
if (!sizeof($tags))
return false;
foreach ($tags AS &$tag)
$tag['class'] = 'tag_level'.(int)(($tag['times'] - $min) * $coef + 1);
$this->smarty->assign('tags', $tags);
return $this->display(__FILE__, 'blocktags.tpl');
}
function hookRightColumn($params)
{
return $this->hookLeftColumn($params);
}
function hookHeader($params)
{
$this->context->controller->addCSS(($this->_path).'blocktags.css', 'all');
}
public function hookdisplayTop($params)
{
return $this->hookdisplayTopColumn($params);
}
public function renderForm()
{
$fields_form = array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Displayed tags'),
'name' => 'BLOCKTAGS_NBR',
'class' => 'fixed-width-xs',
'desc' => $this->l('Set the number of tags you would like to see displayed in this block.')
),
),
'submit' => array(
'title' => $this->l('Save'),
)
),
);
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
$helper->default_form_language = $lang->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitBlockTags';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFieldsValues(),
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id
);
return $helper->generateForm(array($fields_form));
}
public function getConfigFieldsValues()
{
return array(
'BLOCKTAGS_NBR' => Tools::getValue('BLOCKTAGS_NBR', Configuration::get('BLOCKTAGS_NBR')),
);
}
}
Change this:
public function hookdisplayTop($params)
{
return $this->hookdisplayTopColumn($params);
}
To that:
public function hookdisplayTopColumn($params)
{
return $this->hookLeftColumn($params);
}

description isnt displaying for zf2 form element

I am trying to add a description to my form element. I am expecting to get my description in p tags.
<?php
namespace CsnCms\Form;
use Zend\Form\Form;
class ArticleForm extends Form
{
public function __construct($name = null)
{
parent::__construct('article');
$this->setAttribute('method', 'post');
$this->add(array(
'name' => 'currency',
'attributes' => array(
'type' => 'text',
'placeholder' =>'Currency',
),
'options' => array(
'label' => ' ',
'description' => 'Currency code: ie. USD',
),
));
}
}
unfortunately I am only getting this as an output
<label><span> </span><input name="currency" type="text" placeholder="Currency" value=""></label>
any advice?
Maybe this will work
$form = $this->form;
$element = $form->get("currency");
echo $this->formInput($element);
echo $element->getOption("description"); // <-------
?>
zf2 form elements don't have native description option u need to add it manually :
$this->add(array(
'name' => 'catMachineName',
'type' => 'Zend\Form\Element\Text',
'options' => array(
'label' => 'Category Machine Name',
'description' => 'Machine name can only contain English Alphabets and Numbers and _ and no space and no number at the beginning'
),
));
and render it in view like with something like this:
echo $form->get('catMachineName')->getOption('description);
Thanks I wrote my own view helper. I also added a class="error" in the error tags.
Thanks for the help guys.
<?php
namespace User\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Zend\Form\View\Helper\FormRow;
use Zend\Form\ElementInterface;
class FormRowWithDescription extends FormRow
{
/**
* Utility form helper that renders a label (if it exists), an element and errors
*
* #param ElementInterface $element
* #throws \Zend\Form\Exception\DomainException
* #return string
*/
public function render(ElementInterface $element)
{ $escapeHtmlHelper = $this->getEscapeHtmlHelper();
$labelHelper = $this->getLabelHelper();
$elementHelper = $this->getElementHelper();
$elementErrorsHelper = $this->getElementErrorsHelper();
$label = $element->getLabel();
$inputErrorClass = $this->getInputErrorClass();
if (isset($label) && '' !== $label) {
// Translate the label
if (null !== ($translator = $this->getTranslator())) {
$label = $translator->translate(
$label, $this->getTranslatorTextDomain()
);
}
}
// Does this element have errors ?
if (count($element->getMessages()) > 0 && !empty($inputErrorClass)) {
$classAttributes = ($element->hasAttribute('class') ? $element->getAttribute('class') . ' ' : '');
$classAttributes = $classAttributes . $inputErrorClass;
$element->setAttribute('class', $classAttributes);
}
if ($this->partial) {
$vars = array(
'element' => $element,
'label' => $label,
'labelAttributes' => $this->labelAttributes,
'labelPosition' => $this->labelPosition,
'renderErrors' => $this->renderErrors,
);
return $this->view->render($this->partial, $vars);
}
if ($this->renderErrors) {
$elementErrorsHelper
->setMessageOpenFormat('<ul%s><li class="error">')
->setMessageSeparatorString('</li><li class="error">');
$elementErrors = $elementErrorsHelper->render($element);
}
$elementString = $elementHelper->render($element);
$description = $element->getOption('description');
$elementString.="<p class='description'>".$description."</p>";
if (isset($label) && '' !== $label) {
$label = $escapeHtmlHelper($label);
$labelAttributes = $element->getLabelAttributes();
if (empty($labelAttributes)) {
$labelAttributes = $this->labelAttributes;
}
// Multicheckbox elements have to be handled differently as the HTML standard does not allow nested
// labels. The semantic way is to group them inside a fieldset
$type = $element->getAttribute('type');
if ($type === 'multi_checkbox' || $type === 'radio') {
$markup = sprintf(
'<fieldset><legend>%s</legend>%s</fieldset>',
$label,
$elementString);
} else {
if ($element->hasAttribute('id')) {
$labelOpen = '';
$labelClose = '';
$label = $labelHelper($element);
} else {
$labelOpen = $labelHelper->openTag($labelAttributes);
$labelClose = $labelHelper->closeTag();
}
if ($label !== '' && !$element->hasAttribute('id')) {
$label = '<span>' . $label . '</span>';
}
// Button element is a special case, because label is always rendered inside it
if ($element instanceof Button) {
$labelOpen = $labelClose = $label = '';
}
switch ($this->labelPosition) {
case self::LABEL_PREPEND:
$markup = $labelOpen . $label . $elementString . $labelClose;
break;
case self::LABEL_APPEND:
default:
$markup = $labelOpen . $elementString . $label . $labelClose;
break;
}
}
if ($this->renderErrors) {
$markup .= $elementErrors;
}
} else {
if ($this->renderErrors) {
$markup = $elementString . $elementErrors;
} else {
$markup = $elementString;
}
}
return $markup;
}
}

Zend/Session with ZfcUser

I'm using ZfcUser in my app and I need to control the timeout parameter. As it's not part of the configuration I would like to set my own Zend/Session object (with the remember_me_seconds param) to ZfcUser on bootstrap but I don't know how.
By chance, has anyone done this already?
The easiest way to set session params is as follows
config\autoload\global.php
return array(
'service_manager' => [
'factories' => [
// Configures the default SessionManager instance
'Zend\Session\ManagerInterface' => 'Zend\Session\Service\SessionManagerFactory',
// Provides session configuration to SessionManagerFactory
'Zend\Session\Config\ConfigInterface' => 'Zend\Session\Service\SessionConfigFactory',
],
],
'session_manager' => [
// SessionManager config: validators, etc
],
'session_config' => [
'cache_expire' => 86400,
'cookie_lifetime' => 86400,
'remember_me_seconds' => 86400,
'gc_probability' => 10,
'gc_divisor' => 1000,
'use_cookies' => true,
'cookie_httponly' => true,
'cookie_lifetime' => 0, // to reset lifetime to maximum at every click
'gc_maxlifetime' => 86400,
],
);
And add line to onBootstrap method at Module.php
public function onBootstrap(MvcEvent $e)
{
$manager = $e->getApplication()->getServiceManager()->get('Zend\Session\ManagerInterface');
}
This will affect session setting and phpinfo() shows it.
I found it in zfcuser github
I don't use zfcuser but try this
autoload/global.php
<?php
use Zend\Session\Config\SessionConfig;
use Zend\Session\SessionManager;
use Zend\Session\Container;
return array(
'service_manager' => array(
'factories' => array(
'SessionManager' => function($sm) {
$sessionConfig = new SessionConfig();
$sessionConfig->setOption('remember_me_seconds', 1440);
$sessionManager = new SessionManager($sessionConfig);
Container::setDefaultManager($sessionManager);
return $sessionManager;
},
),
),
);
Module.php
public function onBootstrap($event)
{
$serviceManager = $event->getApplication()->getServiceManager();
$serviceManager->get('SessionManager')->start();
}
Here is how I did it. I am not the worlds greatest coder but this seems to work. This is all in Module.php
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$sharedManager = $eventManager->getSharedManager();
$sm = $e->getApplication()->getServiceManager();
//This checks to see if the user is logged in.
$eventManager->attach(MvcEvent::EVENT_DISPATCH, array($this, 'checkLogin'), 100);
}
//This function is attached to a listener to see if the user is not currently logged in
//If they are not logged in they will be redirected to the login page. This check will happen through the
//application so there is no need to keep checking in other modules
public function checkLogin (MvcEvent $e)
{
$session = new Container('defaults');
$this->route = $e->getRouteMatch();
$this->matchedRouteName = explode('/', $this->route->getMatchedRouteName());
$this->route_root = $this->matchedRouteName[0];
$sm = $e->getApplication()->getServiceManager();
$zfcServiceEvents = $sm->get('ZfcUser\Authentication\Adapter\AdapterChain')->getEventManager();
$zfcServiceEvents->attach(
'authenticate',
function ($e) use ($session) {
$session->offsetSet('sessionstart', $_SERVER['REQUEST_TIME']);
}
);
$auth = $sm->get('zfcuser_auth_service');
if (!$auth->hasIdentity() && $this->route_root != 'zfcuser')
{
$response = new \Zend\Http\PhpEnvironment\Response();
$response->getHeaders()->addHeaderLine('Location', '/user/login');
$response->setStatusCode(302);
$response->sendHeaders();
$e->stopPropagation(true);
return $response;
}
else if ($auth->hasIdentity() && $session->offsetGet('sessionstart') < ($_SERVER['REQUEST_TIME'] - 10800) && $this->route_root != 'zfcuser')
{
$response = new \Zend\Http\PhpEnvironment\Response();
$response->getHeaders()->addHeaderLine('Location', '/user/logout');
$response->setStatusCode(302);
$response->sendHeaders();
$e->stopPropagation(true);
return $response;
}
else if ($auth->hasIdentity())
{
$session->offsetSet('sessionstart', $_SERVER['REQUEST_TIME']);
}
}

Functional test and sfWidgetFormChoice with multiple true

I want to test a user editing a form, and in that form there is a <select multiple="multiple">. How do I select or unselect <option>values from that form widget in the functional test?
Form setup:
'regions_list' => new sfWidgetFormDoctrineChoice(array(
'multiple' => true,
'model' => 'Region'
)),
Functional Test:
$browser->
getRoute('profile')->
//setField('profile[regions_list]', '[9][8]')-> // tried syntaxmany combinations
click('Save Profile', array(
'profile' => array(
// 'regions_list' => ???,
// I've tried many combinations even with setField and none made sense and where testable so far
)
))->
with('form')->begin()->
hasErrors(0)->
hasGlobalError(0)->
end()
;
I've never put the with('form') around the click() and this is working on my tests:
$browser->
getRoute('profile')->
click('Save Profile', array(
'profile' => array('regions_list' => array(8,9)
// with: <option value="8">something</option><option value="9">else</option>
// ... and other fields
)
))->
end()->
with('form')->begin()->
debug() -> // added this line so you can see what is happening
hasErrors(0)->
hasGlobalError(0)->
end()
;
Well, after digging in the click() process, I can't get the result I expect.
The solutions follows the problem:
in a <select multiple> tag, I expect that if I don't post any values, it's going to repost it as is, and if I do specify values, it will post only those and not try to control on/off by values.
The way it's reacting now is that the initial values and the chosen values are merged together and the initial values keys matching the chosen values keys are replaced which doesn't make sense to me because those keys or their order are irrelevant. I only care about the option values chosen.
The answer to my question is: You can't do what you expect with the current implementation.
The solution:
Override (or submit a patch if you have time) the doClickElement function in sfBrowserBase class which could look like this: ( look for the 3 comments // fix for select multiple and the last 2 methods to add )
public function doClickElement(DOMElement $item, $arguments = array(), $options = array())
{
$method = strtolower(isset($options['method']) ? $options['method'] : 'get');
if ('a' == $item->nodeName)
{
if (in_array($method, array('post', 'put', 'delete')))
{
if (isset($options['_with_csrf']) && $options['_with_csrf'])
{
$arguments['_with_csrf'] = true;
}
return array($item->getAttribute('href'), $method, $arguments);
}
else
{
return array($item->getAttribute('href'), 'get', $arguments);
}
}
else if ('button' == $item->nodeName || ('input' == $item->nodeName && in_array($item->getAttribute('type'), array('submit', 'button', 'image'))))
{
// add the item's value to the arguments
$this->parseArgumentAsArray($item->getAttribute('name'), $item->getAttribute('value'), $arguments);
// use the ancestor form element
do
{
if (null === $item = $item->parentNode)
{
throw new Exception('The clicked form element does not have a form ancestor.');
}
}
while ('form' != $item->nodeName);
}
// form attributes
$url = $item->getAttribute('action');
if (!$url || '#' == $url)
{
$url = $this->stack[$this->stackPosition]['uri'];
}
$method = strtolower(isset($options['method']) ? $options['method'] : ($item->getAttribute('method') ? $item->getAttribute('method') : 'get'));
// merge form default values and arguments
$defaults = array();
$arguments = sfToolkit::arrayDeepMerge($this->fields, $arguments);
// fix for select multiple
$select_multiple_to_check = array();
$xpath = $this->getResponseDomXpath();
foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $item) as $element)
{
if ($element->hasAttribute('disabled'))
{
continue;
}
$elementName = $element->getAttribute('name');
$nodeName = $element->nodeName;
$value = null;
if ($nodeName == 'input' && ($element->getAttribute('type') == 'checkbox' || $element->getAttribute('type') == 'radio'))
{
// fix for select multiple
if (substr($elementName, -2) == '[]')
{
$select_multiple_to_check[$elementName] = true;
}
if ($element->getAttribute('checked'))
{
$value = $element->hasAttribute('value') ? $element->getAttribute('value') : '1';
}
}
else if ($nodeName == 'input' && $element->getAttribute('type') == 'file')
{
$filename = array_key_exists($elementName, $arguments) ? $arguments[$elementName] : sfToolkit::getArrayValueForPath($arguments, $elementName, '');
if (is_readable($filename))
{
$fileError = UPLOAD_ERR_OK;
$fileSize = filesize($filename);
}
else
{
$fileError = UPLOAD_ERR_NO_FILE;
$fileSize = 0;
}
unset($arguments[$elementName]);
$this->parseArgumentAsArray($elementName, array('name' => basename($filename), 'type' => '', 'tmp_name' => $filename, 'error' => $fileError, 'size' => $fileSize), $this->files);
}
else if ('input' == $nodeName && !in_array($element->getAttribute('type'), array('submit', 'button', 'image')))
{
$value = $element->getAttribute('value');
}
else if ($nodeName == 'textarea')
{
$value = '';
foreach ($element->childNodes as $el)
{
$value .= $this->getResponseDom()->saveXML($el);
}
}
else if ($nodeName == 'select')
{
if ($multiple = $element->hasAttribute('multiple'))
{
// fix for select multiple
$select_multiple_to_check[$elementName] = true;
$elementName = str_replace('[]', '', $elementName);
$value = array();
}
else
{
$value = null;
}
$found = false;
foreach ($xpath->query('descendant::option', $element) as $option)
{
if ($option->getAttribute('selected'))
{
$found = true;
if ($multiple)
{
$value[] = $option->getAttribute('value');
}
else
{
$value = $option->getAttribute('value');
}
}
}
$option = $xpath->query('descendant::option', $element)->item(0);
if (!$found && !$multiple && $option instanceof DOMElement)
{
$value = $option->getAttribute('value');
}
}
if (null !== $value)
{
$this->parseArgumentAsArray($elementName, $value, $defaults);
}
}
// fix for select multiple
foreach($select_multiple_to_check as $elementName => $uselessbool)
{
$path = array_filter(preg_split('/(\[ | \[\] | \])/x', $elementName), create_function('$s', 'return $s !== "";'));
if ($this->findInArrayByArrayPath($arguments, $path) !== false)
{
$this->unsetInArrayByArrayPath($defaults, $path);
}
}
$arguments = sfToolkit::arrayDeepMerge($defaults, $arguments);
if (in_array($method, array('post', 'put', 'delete')))
{
return array($url, $method, $arguments);
}
else
{
$queryString = http_build_query($arguments, null, '&');
$sep = false === strpos($url, '?') ? '?' : '&';
return array($url.($queryString ? $sep.$queryString : ''), 'get', array());
}
}
// fix for select multiple
// taken from http://stackoverflow.com/questions/3145068/set-multi-dimensional-array-by-key-path-from-array-values/3145199#3145199
public function findInArrayByArrayPath(&$array, &$path, $_i=0) {
// sanity check
if ( !(is_array($array) && is_array($path)) ) return false;
$c = count($path); if ($_i >= $c) return false;
if ($_i==0) {$path = array_values($path);} // to make sure we don't get skipped numeric keys which does happens in the preg_split above
$k = $path[$_i];
if (array_key_exists($k, $array))
return ($_i == $c-1) ? $array[$k] : $this->findInArrayByArrayPath($array[$k], $path, $_i+1);
else
return false;
}
// fix for select multiple
public function unsetInArrayByArrayPath(&$array, &$path, $_i=0) {
// sanity check
if ( !(is_array($array) && is_array($path)) ) return false;
$c = count($path); if ($_i >= $c) return false;
if ($_i==0) {$path = array_values($path);} // to make sure we don't get skipped numeric keys which does happens in the preg_split above
$k = $path[$_i];
if (array_key_exists($k, $array))
if ($_i == $c-1) {
unset($array[$k]);
return true;
} else {
return $this->unsetInArrayByArrayPath($array[$k], $path, $_i+1);
}
else
return false;
}
And Now:
'profile' => array('regions_list' => array(8,9)) works for me.

Resources