Reputation: 348
Is there a logic error/case that I'm not seeing?
I'm using PhpStorm 2017.1 with PHP language level 7.1 and CLI Interpreter PHP 7.1.8
I tried the following cases:
User
with carrinho(DB)
and with and without carrinho_id
on request
User
without carrinho(DB)
and with and without carrinho_id
on request
carrinho_id
on request
with no user
carrinho_id
with wrong user(not logged)
$user = Auth::guard('api')->user();
if(!(isset($user) && ($carrinho = $user->getCarrinho()) != null)){
if(!isset($data['carrinho_id']) || (($carrinho = Carrinho::find($data['carrinho_id'])) == null) || ($carrinho->usuario_id != null))
$carrinho = Carrinho::salvar([]);
if(isset($user))
$carrinho->setUsuario($user->id);
}
if($carrinho->addProduto($data)) //"$carrinho" Variable might have not been defined
return response()->json([
'carrinho_id' => $carrinho->id
]);
return response()->json(['msg' => "O produto já está no seu carrinho"],422);
Two possible cases
$user
exist
if(!(true && ($carrinho = $user->getCarrinho()) != null))
2 two possible path
1 - Has $carrinho
if(!(true && true)) -> !(true && true) -> !(true) -> false -> skip if and load the $carrinho from the user
2 - doesn't have $carrinho
if(!(true && false)) -> !(true && false) -> !(false) -> true -> Go inside the if and define the $carrinho
The code inside the first if
will allways have a $carrinho
The problem lies on the first if
. How do i know that?
Because if I do this, the warning goes off.
if(!(isset($user) && ($carrinho = $user->getCarrinho()) != null)){
if(!isset($data['carrinho_id']) || (($carrinho = Carrinho::find($data['carrinho_id'])) == null) || ($carrinho->usuario_id != null))
$carrinho = Carrinho::salvar([]);
if(isset($user))
$carrinho->setUsuario($user->id);
}else{
$carrinho = Carrinho::salvar([]);
}
Upvotes: 1
Views: 99
Reputation: 348
After some questioning and some reseach, I came to the conclusion that hard code does not help anyone, in tearms of team work and project growth. I decided to implement the code in the following way:
$user = Auth::guard('api')->user();
$hasUser = isset($user);
if($hasUser)
$carrinho = $user->getCarrinho();
if(!isset($carrinho)){
if(isset($data['carrinho_id']))
$carrinho = Carrinho::find($data['carrinho_id']);
if(!isset($carrinho) || $carrinho->usuario_id != null)
$carrinho = Carrinho::salvar([]);
if($hasUser)
$carrinho->setUsuario($user->id);
}
if($carrinho->addProduto($data))
return response()->json([
'carrinho_id' => $carrinho->id
]);
return response()->json(['msg' => "O produto já está no seu carrinho"],422);
I will not accept this anwser because I'm still not conviced that the code had errors because no one could find any. But I will leave this here to show that hard code does no help.
Upvotes: 0
Reputation: 97678
This code is extremely hard to read, because you've combined side effects (assignments) with complex conditions involving multiple boolean operators. Let's try to write it out as a set of discrete operations:
// First condition to be evaluated is isset($user)
$haveUser = isset($user);
// If that condition is false, the && will lazily skip the next part
if ( $haveUser ) {
// Now we conditionally assign $carrinho ...
$carrinho = $user->getCarrinho();
// ... and test its value
$haveCarrinho = ($carrinho != null);
}
// Having done all that, we combine the two conditions
$haveBoth = $haveUser && $haveCarrinho;
// Now we invert that condition for our if statement
if ( ! $haveBoth ) {
// We know here that $carrinho has either never been set (because $haveUser was false) ...
// ... or it was null (setting $haveCarrinho to false)
// Line 3 - another if statement to unpack
$haveIdInData = isset($data['carrinho_id']);
// If that condition is false, the || will shortcut
if ( ! $haveIdInData ) {
$carrinho = Carrinho::salvar([]);
}
// If we don't short-cut, the rest of line 3 runs
else {
// Try finding it by the ID in $data
$carrinho = Carrinho::find($data['carrinho_id']);
// If it's null, we short-cut at the next ||
if ($carrinho == null) {
$carrinho = Carrinho::salvar([]);
}
else {
// Else we make the next check
if ($carrinho->usuario_id != null) {
$carrinho = Carrinho::salvar([]);
}
}
}
// On to line 4! Reusing our condition from above, since the state of $user won't have changed
if ( $haveUser ) {
// This will give a horrible error if $carrinho is null
$carrinho->setUsuario($user->id);
}
}
// We've reached line 5, and expect $carrinho to be set, but we have no guarantee of that at all!
That's a lot of logic for 4 lines of code!
Tidying up a little bit, without making it as cryptic as the original, I think this is equivalent:
$carrinho = null;
if ( isset($user) ) {
// Now we conditionally assign $carrinho ...
$carrinho = $user->getCarrinho();
}
if ( $carrinho == null ) {
if ( isset($data['carrinho_id']) ) {
$carrinho = Carrinho::find($data['carrinho_id']);
if ($carrinho == null || $carrinho->usuario_id != null) {
$carrinho = Carrinho::salvar([]);
}
}
if(isset($user)) {
$carrinho->setUsuario($user->id);
}
}
Now we can see what was probably intended: the Carrinho::salvar
line should be the fallback for any other undefined state, rather than nested inside other conditions.
With a bit of effort, we can eliminate nested conditions altogether, giving something much more readable like this:
// Initialise variables to a known state
$carrinho = null;
$loadedFromUser = false;
// Try on user object
if ( isset($user) ) {
$carrinho = $user->getCarrinho();
$loadedFromUser = ($carrinho != null);
}
// Not found? Try looking up by input data
if ( $carrinho == null && isset($data['carrinho_id']) ) {
$carrinho = Carrinho::find($data['carrinho_id']);
}
// Discard if it already has a user ID, but wasn't loaded from user
if (!$loadedFromUser && $carrinho != null && $carrinho->usuario_id != null) {
$carrinho = null;
}
// Still not found? Create an empty one
if ($carrinho == null) {
$carrinho = Carrinho::salvar([]);
}
// Now we know we have an object some way or another, and can assign a user ID to it
if(isset($user) && !$loadedFromUser) {
$carrinho->setUsuario($user->id);
}
Some of these conditions might not be quite what was intended, but by splitting them out, we can now follow the logic much more easily and make changes as appropriate.
Upvotes: 1
Reputation: 6456
Your code may have a problem during execution and PHPStorm says about it. You won't have $carrinho
object for some cases, for example, if $user
variable exists
if(!(isset($user) && ($carrinho = $user->getCarrinho()) != null)){
if(!isset($data['carrinho_id']) || (($carrinho = Carrinho::find($data['carrinho_id'])) == null) || ($carrinho->usuario_id != null))
$carrinho = Carrinho::salvar([]);
if(isset($user))
$carrinho->setUsuario($user->id);
}
and code $carrinho->addProduto($data)
will fail.
You need to fix it. For example, you сan move your code into conditions block
if(!(isset($user) && ($carrinho = $user->getCarrinho()) != null)){
if(!isset($data['carrinho_id']) || (($carrinho = Carrinho::find($data['carrinho_id'])) == null) || ($carrinho->usuario_id != null)) {
$carrinho = Carrinho::salvar([]);
}
if(isset($user)) {
carrinho->setUsuario($user->id);
}
if($carrinho->addProduto($data)) {
return response()->json([
'carrinho_id' => $carrinho->id
]);
}
}
return response()->json(['msg' => "O produto já está no seu carrinho"],422);
Upvotes: 1