Как известно, чтобы передать в PHP-скрипт данные из HTML-формы в виде массива, нужно использовать ключи вида «field[key]», например:
[html]
<form id=myform>
Пользователь 15:<br>
<input type=hidden name="User[15][id]" value="15"><br>
Имя:<input type=text name="User[15][name]" value="Вася"><br>
Телефон:<input type=text name="User[15][phone]" value="+79991234567"><br>
Пользователь 16:<br>
<input type=hidden name="User[16][id]" value="16"><br>
Имя:<input type=text name="User[16][name]" value="Петя"><br>
Телефон<input type=text name="User[16][phone]" value="+79824445551"><br>
</form>
[/html]
Многие PHP-фреймворки при создании HTML-форм, дают имена их элементам подобным образом. Это и понятно, формировать их так — очень просто, при передаче такой формы в PHP-код она превратится в удобный массив вида:
array( "User" => array( 15 => array( "name" => "Вася", "phone" => "+79991234567" ), 16 => array( "name" => "Петя", "phone" => "+79824445551" ), ) ); |
Но если вы передаёте его не путём обычной отправки формы, а с помощью Ajax, тут вас и подстерегает проблема.
Допустим, что мы хотим сделать вот такой ajax-запрос:
//В переменной data хотелось бы иметь данные из заполненной формы $.post("/api/users", {"action":save, "users_data":data}, function(result) { alert("Ок"); }); |
А в PHP-коде мы сможем получить доступ к данным формы, обратившись к $_POST[‘users_data’]. Хотелось бы иметь возможность в PHP обращаться к полям формы таким образом: $name = $_POST[‘users_data’][‘User’][16][‘name’];
Как мы можем получить данные из формы? Даже с помощью jQuery существует как минимум несколько способов:
1. С помощью serialize:
data = $('#myform').serialize(); |
Эта функция вернёт нам такую строку:
User%5B15%5D%5Bid%5D=15&User%5B15%5D%5Bname%5D=%D0%92%D0%B0%D1%81%D1%8F&User%5B15%5D%5Bphone%5D=%2B79991234567&User%5B16%5D%5Bid%5D=16&User%5B16%5D%5Bname%5D=%D0%9F%D0%B5%D1%82%D1%8F&User%5B16%5D%5Bphone%5D=%2B79824445551
Если передать данные в таком формате, то PHP получит их в виде такой-же строки. (Конечно, распарсить её можно с помощью функции parse_str, однако, у такой строки и ещё один минус — невозможность манипулировать данными в JavaScript перед их отправкой на сервер.
2. С помощью serializeArray:
data = $('#myform').serializeArray(); |
Эта функция вернёт такой массив объектов:
Object { name="User[15][id]", value="15"}, Object { name="User[15][name]", value="Вася"}, Object { name="User[15][phone]", value="+79991234567"}, Object { name="User[16][id]", value="16"}, Object { name="User[16][name]", value="Петя"}, Object { name="User[16][phone]", value="+79824445551"}
Проблема этого массива в том, что, при передаче его в PHP в составе другого объекта, он не будет правильно разобран. К примеру, если передать эти данные вот таким образом:
$.post("/api/go", {"fields": $('#myform').serializeArray()}, function(result) {alert("ok");}); |
То в PHP коде окажется, что $_POST массив имеет следующую структуру:
array("fields" => array( "User[16" => "+79824445551", ) )
Чтобы сформировать вложенный объект как раз и создана данная функция:
/** * Convert html 'nested' field name, such as "field[key1][key2][key3]" * and it's value into nested object. * @param {String} field field name, like "field[key1][key2][key3]" * @param {String} value fields value, read from value attribute * @param {Object} append_to object, where to append resulting sub objects * (default {}) * @returns {Object} */ function htmlFieldToObject(field, value, append_to) { append_to = append_to || {}; var re_big = /^([^\[\]]+)((\[[^\]\[]+\])*)$/; var matches = field.match(re_big); var first = matches[1]; var keys_str = matches[2]; var keys = [first]; if (keys_str) { var re_small = new RegExp( "\\[(.+?)\\]", "gi" ); while(matches = re_small.exec(keys_str)) { keys.push(matches[1]); } } var obj = append_to; var cur = obj; var parent = null; var lastI = keys.length - 1; for (var i in keys) { var key = keys[i]; if (i != lastI) { if (cur[key] === undefined) { cur[key] = {}; } var newcur = cur[key]; cur = null; cur = newcur; } else { cur[key] = value; } } return obj; } |
Как ей пользоваться:
//Получаем с помощью serializeArray массив объектов {name: ... , value: ...}, //из которых возьмём имена полей и значения var values = $("#myform").serializeArray(); var obj = {}; for (var i in values) { var field = values[i]["name"]; var value = values[i]["value"]; obj = htmlFieldToObject(field, value, obj); } console.log(obj); |
В результате получим как раз то, чего хотели:
{ "User": { "15": { "name": "Вася", "phone": "+79991234567" }, "16": { "name": "Петя", "phone": "+79824445551" } } } |
Оставить комментарий