В symfony3 я пытаюсь сохранить cookie. Но когда cookie создается в первый раз, он возвращает ошибку 500.
Это код для создания файла cookie:
protected function checkForCartId(Request $request)
{
if (!empty($this->uniqueCartId)) {
return $this->uniqueCartId;
}
$response = new Response();
if (!$request->cookies->has('uniqueCartId')) {
$this->uniqueCartId = uniqid();
$response->headers->setCookie(new Cookie('uniqueCartId', $this->uniqueCartId));
$response->send();
return $this->uniqueCartId;
}
return $request->cookies->get('uniqueCartId');
}
Когда я удаляю строку $response->send(), ошибка исчезает, но файл cookie не сохраняется.
Любые идеи?
=========== РЕДАКТИРОВАТЬ =============
Файл журнала (после повторного получения ошибки)
[2018-04-22 14:47:26] request.INFO: Matched route "homepage". {"route":"homepage","route_parameters":{"_controller":"AppBundle\\Controller\\DefaultController::indexAction","_route":"homepage"},"request_uri":"http://127.0.0.1:8000/","method":"GET"} []
[2018-04-22 14:47:26] security.DEBUG: Checking for guard authentication credentials. {"firewall_key":"main","authenticators":1} []
[2018-04-22 14:47:26] security.DEBUG: Calling getCredentials() on guard configurator. {"firewall_key":"main","authenticator":"AppBundle\\Security\\LoginFormAuthenticator"} []
[2018-04-22 14:47:26] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2018-04-22 14:47:26] doctrine.DEBUG: SELECT t0.id AS id_1, t0.url AS url_2, t0.title AS title_3, t0.content AS content_4, t0.seo_title AS seo_title_5, t0.seo_description AS seo_description_6, t0.published AS published_7 FROM pages t0 WHERE t0.url = ? LIMIT 1 ["/"] []
[2018-04-22 14:47:26] doctrine.DEBUG: SELECT p0_.id AS id_0, p0_.slug AS slug_1, p0_.name AS name_2, p0_.is_published AS is_published_3, p0_.description AS description_4, p0_.price AS price_5, p0_.discount_price AS discount_price_6, p0_.page_title AS page_title_7, p0_.seo_title AS seo_title_8, p0_.seo_description AS seo_description_9 FROM product p0_ WHERE p0_.discount_price > 0 AND p0_.is_published = ? [1] []
[2018-04-22 14:47:26] doctrine.DEBUG: SELECT h0_.id AS id_0, h0_.title AS title_1, h0_.subtitle AS subtitle_2, h0_.image AS image_3, h0_.button_text AS button_text_4, h0_.button_link AS button_link_5, h0_.active AS active_6 FROM homepage_banner h0_ WHERE h0_.active = ? [1] []
[2018-04-22 14:47:26] doctrine.DEBUG: SELECT c0_.id AS id_0, c0_.name AS name_1, c0_.slug AS slug_2, c0_.page_title AS page_title_3, c0_.description AS description_4, c0_.parent_id AS parent_id_5, c0_.created_by AS created_by_6 FROM category c0_ WHERE c0_.parent_id IS NULL [] []
[2018-04-22 14:47:26] doctrine.DEBUG: SELECT t0.id AS id_1, t0.name AS name_2, t0.slug AS slug_3, t0.page_title AS page_title_4, t0.description AS description_5, t0.parent_id AS parent_id_6, t0.created_by AS created_by_7 FROM category t0 WHERE t0.parent_id = ? [1] []
[2018-04-22 14:47:26] doctrine.DEBUG: SELECT t0.id AS id_1, t0.name AS name_2, t0.slug AS slug_3, t0.page_title AS page_title_4, t0.description AS description_5, t0.parent_id AS parent_id_6, t0.created_by AS created_by_7 FROM category t0 WHERE t0.parent_id = ? [2] []
[2018-04-22 14:47:26] doctrine.DEBUG: SELECT s0_.id AS id_0, s0_.cart_id AS cart_id_1, s0_.quantity AS quantity_2, s0_.price AS price_3, s0_.discount_price AS discount_price_4, s0_.ordered AS ordered_5, s0_.created_at AS created_at_6, s0_.product_id AS product_id_7, s0_.user_id AS user_id_8 FROM shopping_cart s0_ WHERE s0_.cart_id = ? ["5adc845e728a9"] []
[2018-04-22 14:47:26] request.CRITICAL: Uncaught PHP Exception UnexpectedValueException: "The Response content must be a string or object implementing __toString(), "boolean" given." at H:\Websites\CMS\vendor\symfony\symfony\src\Symfony\Component\HttpFoundation\Response.php line 406 {"exception":"[object] (UnexpectedValueException(code: 0): The Response content must be a string or object implementing __toString(), \"boolean\" given. at H:\\Websites\\CMS\\vendor\\symfony\\symfony\\src\\Symfony\\Component\\HttpFoundation\\Response.php:406)"} []
[2018-04-22 14:47:27] request.INFO: Matched route "_wdt". {"route":"_wdt","route_parameters":{"_controller":"web_profiler.controller.profiler:toolbarAction","token":"49bddb","_route":"_wdt"},"request_uri":"http://127.0.0.1:8000/_wdt/49bddb","method":"GET"} []
================= РЕДАКТИРОВАТЬ =============== Действие контроллера:
public function getCartItems(Request $request)
{
$shoppingCartRepository = $this->em->getRepository(ShoppingCart::class);
return $this->render('checkout/cart.html.twig', [
'cartItems' => $shoppingCartRepository->findAllProductsInCart($this->getUser(), $this->checkForCartId($request))
]);
}
================= РЕДАКТИРОВАТЬ ===============
Моя новая функция getCartItems:
public function getCartItems(Request $request)
{
$shoppingCartRepository = $this->em->getRepository(ShoppingCart::class);
if (!$request->cookies->has('uniqueCartId')) {
$this->checkForCartId($request);
}
$response = $this->render('checkout/cart.html.twig', [
'cartItems' => $shoppingCartRepository->findAllProductsInCart($this->getUser(), $this->checkForCartId($request))
]);
$response->headers->setCookie(new Cookie('uniqueCartId', $this->checkForCartId($request)));
return $response;
}
============= РЕШЕНИЕ =============
public function getCartItems(Request $request)
{
$shoppingCartRepository = $this->em->getRepository(ShoppingCart::class);
$response = new Response();
if (!$request->cookies->has('uniqueCartId')) {
$response->headers->setCookie(new Cookie('uniqueCartId', $this->checkForCartId($request)));
$response->sendHeaders();
}
return $this->render('checkout/cart.html.twig', [
'cartItems' => $shoppingCartRepository->findAllProductsInCart($this->getUser(), $this->checkForCartId($request))
], $response);
}
@DanielAlexandrov Я вставил файл журнала.
Попробуй найти ошибку, поставив блок try...catch ...
Вы отправляете логическое значение в качестве полезной нагрузки ответа где-то (строка перед последней в вашем журнале). Я не могу вычесть поток вашего приложения только из этого метода, но вы не должны отправлять ответ из этой функции, потому что я предполагаю, что позже вы будете делать это снова. Как правило, если вы ожидаете результата от метода / функции, избегайте в нем побочных эффектов (например, отправки запроса в вашем случае), потому что это часто приводит к таким ошибкам.
@DanielAlexandrov Когда я удаляю строку $ response-> send (), она не вызывает ошибку. Я просто хочу знать, как сохранить файл cookie без этой ошибки. Не знаю, как по другому настроить. Я могу попробовать это в javascript, но это опасно?
Откуда вы вызываете этот метод? Что происходит после проверки? Если вы можете вернуть значение cookie и установить его в существующем запросе позже, он будет работать нормально. Однако, не видя кода вашего контроллера, будет сложно дать вам более конкретную информацию.
Обновите свой вопрос кодом контроллера. Поскольку контроллер Symfony требует возврата объекта ответа и неявно вызывает метод send возвращаемого объекта ответа, вам следует избегать этого в службе, поскольку заголовки уже были бы отправлены им, когда Symfony попытается это сделать.
@fyrye обновлен кодом контроллера
@DanielAlexandrov Я вызываю этот метод из контроллера (см. Обновленный пост). А getCartItems() я вызываю прямо в моем шаблоне веточки.






Вам необходимо установить cookie для объекта Response, который в вашем случае является визуализированным шаблоном веточки. После небольшого рефакторинга ваш код может выглядеть так:
protected function getCardId(Request $request)
{
if (!$request->cookies->has('uniqueCartId')) {
$this->uniqueCartId = uniqid();
return ['is_new' => true, 'unique_id' => $this->uniqueCartId];
}
$this->uniqueId = $request->cookies->get('uniqueCartId');
return ['is_new' => false, 'unique_id' => $request->cookies->get('uniqueCartId')];
}
...
public function getCartItems(Request $request)
{
$shoppingCartRepository = $this->em->getRepository(ShoppingCart::class);
$cartId = $this->getCardId($request);
$response = $this->render('checkout/cart.html.twig', [
'cartItems' => $shoppingCartRepository->findAllProductsInCart($this->getUser(), $cartId['uniqueId'])
]);
if ($cartId['is_new']) {
$response->headers->setCookie(new Cookie('uniqueCartId', $this->uniqueCartId));
}
return $response;
}
Важно отметить, что ответ возвращается только один раз, вы не можете вернуть два ответа на один запрос.
Привет, Даниэль, спасибо за ответ. Я уже пробовал это, но при этом cookie не создается.
Уверены ли вы? Вы удалили $ response-> send (); из вашего метода checkForCartId? Можете ли вы попробовать код из моего примера, включая измененный checkForCartId / getCardId?
Я использовал ваш код, и это дамп с app.request.cookiesParameterBag {#71 ▼ #parameters: array:1 [▼ "PHPSESSID" => "nljafbnff634j9vl69cvd07bm3" ] }. Как видите, cookie не установлен. Ошибка исчезла.
Ой, подождите, я вижу uniqueCartId в Google Chrome, но не в режиме инкогнито Google Chrome. Есть ли способ установить файлы cookie в режиме инкогнито?
@Refilon chrome в основном устанавливает кеш во временный каталог, который очищается при закрытии браузера и отключает файлы cookie и файлы cookie Flash. Таким образом, вы не можете сохранять данные cookie в режиме инкогнито. См .: Что именно делает режим инкогнито в Chrome? и en.wikipedia.org/wiki/Privacy_mode
@fyrye Это не совсем так. Потому что, когда я использую метод $response->send(), он устанавливает cookie в режиме инкогнито. В режиме инкогнито используются файлы cookie, и они также помещаются во временную папку. Поэтому, когда вы закрываете браузер, он также удаляет файлы cookie из временной папки.
@Refilon Пожалуйста, прочтите статьи, на которые я ссылался, которые объясняют то, что я упомянул. «Сохранение» данных cookie, в отличие от использования данных cookie, заставляет их функционировать так же, как сеанс.
@fyrye Да, это должно быть так. Но когда я пробую этот метод, он не сохраняет cookie во временную папку. Когда я использую $response->send(), он сохраняет cookie во временной папке. Так что мне интересно, почему он это делает?
@Refilon Покажите нам код, который вы используете сейчас, чтобы мы могли воспроизвести проблему. На моем сервере apache dev состояние cookie для приведенного выше ответа работает нормально в режиме инкогнито, протестировано путем комментирования вызова setCookie и многократного обновления страницы в Symfony 3.4.8.
@fyrye Я только что добавил новую функцию. Это не работает и не устанавливает cookie. Ни в обычном Google Chrome, ни в Google Chrome инкогнито
@Refilon в отношении вашего решения, имейте в виду, что ваш ответ ветки НЕ сможет отправлять свои собственные заголовки, так как заголовки уже были отправлены вашим ответом cookie. См .: github.com/symfony/http-foundation/blob/v3.4.8/…. Вы можете проверить это, изменив свой render на redirectToRoute, хотя обычно он также добавляет мета-тег обновления.
@fyrye Спасибо. Я думаю, он отправляет заголовки? Потому что он сохраняет файл cookie. Но теперь все работает
В вашем файле журнала в var / log / должна быть дополнительная информация, можете ли вы добавить ее к вопросу? Я подозреваю, что где-то вы увидите сообщение «Невозможно изменить информацию заголовка - заголовки уже отправлены».