вчера я начал свой первый проект laravel. но у меня проблема, которую я не могу понять.
Я пытаюсь создать корзину для покупок, и я отслеживаю использование объекта сеанса laravel с моей собственной оболочкой. код выглядит так:
class SessionController extends Controller
{
static function getSessionData($key = null, $data = null)
{
if ($data === null)
{
return Session::get($key);
}
else
{
return Session::get($key, $data);
}
}
static function allSessionData()
{
return Session::all();
}
static function putSessionData($key = null, $data)
{
if ($key === null)
{
Session::put($data);
}
else
{
Session::put($key, $data);
}
}
static function has($key)
{
return Session::has($key);
}
Теперь внутри моего класса ShoppingCart я создал поле $instance, в котором хранятся данные корзины покупок, или создается пустая корзина покупок, если она еще не в сеансе. код выглядит так:
class ShoppingCart extends Model
{
public $id;
public $session;
private $sessionName = 'shoppingcart';
private $instance;
public $cartItems;
protected $connection = 'mysql2';
protected $table = 'shoppingcart';
protected $primaryKey = 'Id';
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->cartItems = [];
}
private function getOrCreateSession()
{
if (SessionController::has($this->sessionName))
{
$this->instance = SessionController::getSessionData($this->sessionName);
}
else
{
SessionController::putSessionData($this->sessionName, $this);
$this->instance = SessionController::getSessionData($this->sessionName);
}
}
function addCartItem($productId, $qty = 1)
{
$this->getOrCreateSession();
$cartItem = $this->createCartitem($productId, $qty);
$content = $this->getContent();
if ($existingCartitem = $this->alreadyInCart($cartItem)) {
$existingCartitem->qty += $cartItem->qty;
} else {
array_push($content, $cartItem);
}
}
function createCartItem($productId, $qty)
{
$cartItem = CartItem::fromId($this->instance->id, $productId, $qty);
$cartItem->associate($this->instance->id);
return $cartItem;
}
private function alreadyInCart($cartItem)
{
$alreadyInCart = FALSE;
foreach ($this->instance->cartItems as $item) {
if ($item->productId == $cartItem->productId) {
return $item;
}
}
return $alreadyInCart;
}
//returns current shoppingcart contents.
private function getContent()
{
return $this->instance->cartItems;
}
}
Теперь внутри метода addCartItem я пытаюсь вставить новый элемент cartitem в массив, используя array_push(), но var_dump()-ing сеанса впоследствии показывает, что сеанс не содержит вновь добавленного элемента. Однако, если я var_dump(), $content до и после метода array_push, я вижу, что он добавлен.
Я думал, что PHP передаст сеанс по ссылке, но, похоже, мне что-то здесь не хватает.
Что я делаю не так?
Заранее спасибо.






Вам нужно будет вернуть сеанс по ссылке, т.е.
static function &getSessionData($key = null, $data = null)
и используйте его, получив ссылку, например:
$myVariable = &SessionController::getSessionData($this->sessionName);
Цитата из документы:
Returning by reference is useful when you want to use a function to find to which variable a reference should be bound. Do not use return-by-reference to increase performance. The engine will automatically optimize this on its own. Only return references when you have a valid technical reason to do so. To return references, use this syntax:
<?php
class foo {
public $value = 42;
public function &getValue() {
return $this->value;
}
}
$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue; // prints the new value of $obj->value, i.e. 2.
?>
@Mathijs, можете ли вы отредактировать свой вопрос и добавить способ, который вы пробовали?
Ваш ответ был правильным. Пришлось добавить и в getContent()-метод. Теперь это работает. Спасибо!
хотя мне все еще интересно, правильно ли это делать? Считается ли это хорошей практикой или нет?
@Mathijs, возвращающие ссылки сами по себе, не являются хорошей или плохой практикой, это возможности. Что делает эту практику хорошей или плохой, так это контекст. Если вы видите любую возможность того, что эти ссылки будут неправильно обработаны серверным кодом, то это плохая практика. Если вы не видите такой опасности, то это хорошая практика. Если вы не видите другой возможности, тогда это необходимая практика. В общем, не стоит возвращать ничего по ссылке без уважительной причины. В нашем случае я думаю, что вы можете достичь своей цели более элегантным способом.
@Mathijs Вы можете переместить все, что напрямую изменяет значения сеанса, в класс SessionController и обернуть их вокруг методов. Это защитит вас от решения одной и той же задачи несколько раз, а любую необходимость может решить класс.
На самом деле вы никогда не сохраняете (не сохраняете) данные в Session.
Попробуйте использовать фасад Session, выполнив что-нибудь вроде Session::put('new.item' , $cartItem).
Затем вы можете получить элемент в своем контроллере через: Session::get('new.item').
Спасибо за ответ, но не передавайте сеанс по ссылке, убедитесь, что добавление чего-либо к $instance, например array_push($instance, $cartItem), - это то же самое, что сказать Session::put('shoppingcart', $cartItem)?
К сожалению, в этом случае это работает не так, потому что вы используете диспетчер сеансов Laravel (это оболочка над глобалом $_SESSION), поэтому вы должны играть по их правилам, а не напрямую ссылаться на глобальный сеанс :)
Я только что построил простую корзину для покупок совсем недавно (хотя и на Lumen), возможно, это поможет вам: gist.github.com/MattWohler/1917e0d92b391536b6f2bbaff90923edBasket.php - это оболочка для сеанса. Итак, в моем случае моя тележка - это сеанс, а ваша - таблица в БД. Надеюсь, поможет.
Спасибо за ваш ответ, к сожалению, изменения все еще не сохранены после изменения моего кода так, как вы сказали, что я должен. Что-то не так с передачей определенного сеансового элемента по ссылке? (например, это плохая практика или ..?)