How I would do it:
interface CustomerValidationInterface
{
public function isValid(Customer $customer): bool;
}
class CustomerFooValidator implements CustomerValidationInterface
{
public function isValid(Customer $customer)
{
return $customer->foo === 'FOO';
}
}
class CustomerBarValidator implements CustomerValidationInterface
{
public function isValid(Customer $customer)
{
return $customer->bar === 'BAR';
}
}
class CustomerValidator
{
private $validators;
/**
* @param CustomerValidationInterface[] $validators
*/
public function __construct(array $validators)
{
$this->validators = $validators;
}
public function check(Customer $customer)
{
foreach ($this->validators as $validator) {
if ($validator->isValid($customer) === false) {
return 'error';
}
}
return 'success'
}
}
you can future proof your code, if you need more things to validate in the future, you just need to create a new class implementing your interface and pass to the main validator class.
Update customer status IMHO should do what it says, update the customer status, not check for validation. You should do validation 1 step before this.
I would suggest to refactor your code so that the updateCustomerStatus() method only contains business logic, i.e. checking the invariants on the customer before allowing to update it.
Currently you would call UI logic inside this method (even if the echo is happening in a separate method). I'd like to move the actual rendering of the UI out of updateCustomerStatus().
And I will even go a step further an also move the database access portion (findCustomerById()) out of the business logic method.
This way you can also test the business logic in isolation without needing to worry about the UI and the database.
So here is the direction in which I would move when refactoring your code:
So let's start top-down with some fictional public method that orchestrates the steps and calls your private methods:
public function doUpdateCustomerStatusStuff(string $customerId): void
{
$customer = $this->findCustomerById($customerId);
$operationResult = $this->updateCustomerStatus($customer);
if ($operationResult->failed()) {
$this->showMessage($operationResult->getMessage());
}
}
As you can see it first fetches the customer from the database so that your business logic can now operate on a customer object without having database dependencies.
In the next step we look into the refactored updateCustomerStatus() method:
private function updateCustomerStatus(Customer $customer): OperationResult
{
if ($this->firstCondition($customer)) {
return OperationResult::fail('first condition text');
}
if ($this->secondCondition($customer)) {
return OperationResult::fail('second condition text');
}
$this->updateCustomer($customer);
return OperationResult::succeed();
}
I now pass in the Customer object rather than the id so that the logic code can already do it's job.
Now to your original question:
Instead of calling the UI method (with the echo statement) I rather return some Result object that indicates if the operation succeeded or failed and which also provides an optional message. I added some static methods to the OperationResult class just for convenience.
Let's look at the class, it is not complex but does it's job:
class OperationResult
{
/**
* @var bool
*/
private $success;
/**
* @var string
*/
private $message;
private function __construct(bool $success)
{
$this->success = $success;
}
private function setMessage(string $message)
{
$this->message = $message;
}
public static function fail(string $message)
{
$result = new OperationResult(false);
$result->setMessage($message);
}
public static function succeed()
{
return new OperationResult(true);
}
public function failed()
{
return !$this->success;
}
public function succeeded()
{
return $this->success;
}
}
Now back to the fictional doUpdateCustomerStatusStuff() method:
public function doUpdateCustomerStatusStuff(string $customerId): void
{
$customer = $this->findCustomerById($customerId);
$operationResult = $this->updateCustomerStatus($customer);
if ($operationResult->failed()) {
$this->showMessage($operationResult->getMessage());
}
}
Now you can control when and how to output a message (if any) AFTER the business logic with all checking and updating rules has been performed.
You can even go a step further and move all business logic methods (such as updateCustomerStatus() into a separate class which only contains business logic).
Note: I just assumed that firstCondition() and secondCondition() would check for error conditions. But if that is not the case you can of course perform the output of the message also depending on if there is some message in the doUpdateCustomerStatusStuff() method.
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Find the answer in similar questions on our website.
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.
PHP (from the English Hypertext Preprocessor - hypertext preprocessor) is a scripting programming language for developing web applications. Supported by most hosting providers, it is one of the most popular tools for creating dynamic websites.
The PHP scripting language has gained wide popularity due to its processing speed, simplicity, cross-platform, functionality and distribution of source codes under its own license.
https://www.php.net/
Welcome to the Q&A site for web developers. Here you can ask a question about the problem you are facing and get answers from other experts. We have created a user-friendly interface so that you can quickly and free of charge ask a question about a web programming problem. We also invite other experts to join our community and help other members who ask questions. In addition, you can use our search for questions with a solution.
Ask about the real problem you are facing. Describe in detail what you are doing and what you want to achieve.
Our goal is to create a strong community in which everyone will support each other. If you find a question and know the answer to it, help others with your knowledge.