I have a 'sequence of tasks' to undertake on a zip file. It can be simplified into these steps:
- Validate that the file is a ZIP file and is valid
- Unzip the file
- Validate the contents are as expected
- Turn the contents into a product
I am currently using the Command pattern and it looks a little something like this
interface Command {
public function execute($data);
}
class ValidateFile implements Command {
public function execute($filePath) { //... }
}
class UnzipFile implements Command {
public function execute($filePath) { //... }
}
class ValidateContents implements Command {
public function execute($unzippedFilePath) { //... }
}
class ProductGenerator implements Command {
public function execute($unzippedFilePath) { //... }
}
Now, each of these execute commands returns a string that is in turn (by the command invoker) passed to the next command in the chain (defined by configuration).
I am having two problems here:
Each command requires its own dependencies, i.e. unzip needs access to ZipArchive, a class that handles the unzipping of zip files. How do I inject each command's depenencies? I am quite happy to get around this by instantiating all of the commands through a DIC and plugging them into an 'Invoker' that accepts instantiated objects of type Command, the runs them in sequence, however it doesn't feel right.
(More of an issue) How do I persist more than a string between commands? I have seen in places people passing a 'context' object from one command to another, however this feels a bit dirty as the command would be depending upon an untyped interface (they essentially wrap an associative array). It makes sense that it has to be untyped, as if you're to maintain an interface between commands, then the context can't implement any specific methods as that would deter from its abstraction.
I would appreciate any advice on how to deal with both of these issues.
Edit: Another issue I have is that each of these commands is actually coupled to the state of the file path that's passed to it, they're quite specific to the case at hand, but I doubt it's possible to work past that.