As usual I started implementation from domain. I implemented Menu Aggregate with all operations described in the task using DDD (Rich model) pattern and wrote some unit tests (not all) for this aggregate. And my 4 hours was gone:) The next step that I planned to implement is the Application layer. I planned to use the CQRS pattern because it is very easy to implement a global caching mechanism on Query Bus. And if we will have a lot of items in the menu and recording operations will be slow we can very easily make it asynchronous without changes in the Application level code using Command Bus. After that, I planned to connect my Domain and Application to Laravel infrastructure. I planned to use Tactician to implement Query and Command Bus or implement it himself because it's not complicated patterns. Then I planned to implement \Grifix\Demo\Test\Domain\Menu\MenuInfrastructureInterface::publishEvent using Laravel Event Bus. I planned to use Doctrine for the mapping aggregate to the database because it provides better opportunities for persistence ignorance than Eloquent. And as the second part, I planned to implement the UI layer using Laravel Router and Controllers.
Fork or Download this repository and implement the logic to manage a menu.
A Menu has a depth of N and maximum number of items per layer M. Consider N and M to be dynamic for bonus points.
It should be possible to manage the menu by sending API requests. Do not implement a frontend for this task.
Feel free to add comments or considerations when submitting the response at the end of the README
.
- Home
- Home sub1
- Home sub sub
- [N]
- Home sub sub
- Home sub2
- [M]
- Home sub1
- About
- [M]
Create a menu.
{
"field": "value"
}
{
"field": "value",
"max_depth": 5,
"max_children": 5
}
{
"field": "value"
}
{
"field": "value",
"max_depth": 5,
"max_children": 5
}
Get the menu.
{
"field": "value"
}
{
"field": "value",
"max_depth": 5,
"max_children": 5
}
Update the menu.
{
"field": "value"
}
{
"field": "value",
"max_depth": 5,
"max_children": 5
}
{
"field": "value"
}
{
"field": "value",
"max_depth": 5,
"max_children": 5
}
Delete the menu.
Create menu items.
[
{
"field": "value"
},
{
"field": "value"
}
]
[
{
"field": "value",
"children": [
{
"field": "value",
"children": []
},
{
"field": "value"
}
]
},
{
"field": "value"
}
]
[
{
"field": "value"
},
{
"field": "value"
}
]
[
{
"field": "value",
"children": [
{
"field": "value",
"children": []
},
{
"field": "value"
}
]
},
{
"field": "value"
}
]
Get all menu items.
[
{
"field": "value"
},
{
"field": "value"
}
]
[
{
"field": "value",
"children": [
{
"field": "value",
"children": []
},
{
"field": "value"
}
]
},
{
"field": "value"
}
]
Remove all menu items.
Create an item.
{
"field": "value"
}
{
"field": "value"
}
Get the item.
{
"field": "value"
}
Update the item.
{
"field": "value"
}
{
"field": "value"
}
Delete the item.
Create item's children.
[
{
"field": "value"
},
{
"field": "value"
}
]
[
{
"field": "value",
"children": [
{
"field": "value",
"children": []
},
{
"field": "value"
}
]
},
{
"field": "value"
}
]
[
{
"field": "value"
},
{
"field": "value"
}
]
[
{
"field": "value",
"children": [
{
"field": "value",
"children": []
},
{
"field": "value"
}
]
},
{
"field": "value"
}
]
Get all item's children.
[
{
"field": "value"
},
{
"field": "value"
}
]
[
{
"field": "value",
"children": [
{
"field": "value",
"children": []
},
{
"field": "value"
}
]
},
{
"field": "value"
}
]
Remove all children.
Get all menu items in a layer.
[
{
"field": "value"
},
{
"field": "value"
}
]
Remove a layer and relink layer + 1
with layer - 1
, to avoid dangling data.
Get depth of menu.
{
"depth": 5
}
- 10 vs 1.000.000 menu items - what would you do differently?
- Write documentation
- Use PhpCS | PhpCsFixer | PhpStan
- Use cache
- Use data structures
- Use docker