Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Application description

I have an application of the following structure, simplified:

    Http request
         ↓ 
+-----------------+
|  RequestParser |
+-----------------+
         ↓
Business layer request object

Problem code

The request parser layer accepts the input parameters, validates them and builds the business-layer request object. The code looks like that:

public function processMyRequest()
{
    validationForm =
        Form::create()
            .addIntegerValidator('order_id')
            .addStringValidator('external_id')
    ;

    if (validationForm.hasErrors()) {
        throw new Exception();
    }

    return
        BusinessRulessObject::create()
            .setOrderId(validationForm.getParameter('order_id'))
            .setExternalId(validationForm.getParameter('external_id'))
    ;
}

Some prerequisites

The form can be huge, so does the business layer object. Unfortunately, the Form class belongs to framework and it is final, so I can not inherit the concrete form from the base one where I could specify all the validators. The agreed solutions was to create this forms via Factory classes (this is not the Factory template though as it is not needed here: no mocks in tests, no polymorphism in client code). The RequestParser class can handle several requests.

Better version

So now the code looks like this:

public function processMyRequest()
{
    validationForm = FormFactory.createSomeForm();

    if (validationForm.hasErrors()) {
        throw new Exception();
    }

    return
        BusinessRulessObject::create()
            .setOrderId(validationForm.getParameter('order_id'))
            .setExternalId(validationForm.getParameter('external_id'))
    ;
}

How can I make it better? Version 1

But how should I create my object? Should I have some factory that creates it from form? I.e.,

public function processMyRequest()
{
    ...
    return BusinessRulessObjectFactory::createMyConcreteObject(form);
}

Version 2

Or should BusinessRulessObject class have some method like createFromForm(), i.e.

public function processMyRequest()
{
    ...
    return BusinessRulessObject::createMyConcreteObject(form);
}

Version 3

Or RequestParser's method createFromForm() would be enough, i.e.

public function processMyRequest()
{
    ...
    return createMyConcreteObject(form);
}

private function createMyConcreteObject(Form validationForm)
{
    return
        BusinessRulessObject::create()
            .setOrderId(validationForm.getParameter('order_id'))
            .setExternalId(validationForm.getParameter('external_id'))
    ;
}

So?...

I guess I should choose between the first and the second option, but what aspects should I take into consideration when choosing the way object should be created? And, actually, what way is preferable in my case?

share|improve this question
add comment

closed as primarily opinion-based by Ozz, Bart van Ingen Schenau, Kilian Foth, DougM, Dynamic Jan 29 at 23:43

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise.If this question can be reworded to fit the rules in the help center, please edit the question.

2 Answers

I've been extracting the HTTP / web stuff out of my controllers for a while now, and couldn't look back. Essentially it leaves you with:

Use Case|Interactor|Controller - Function that, using your application's services, converts a business request into a business response. The key thing to note here is that you are dealing with single in/out message objects.

public function execute(RegistrationRequest $request)
{
    // some basic interactions between $request and your app
    // $request->getCredentials(), $request->getProfile(), etc.

    return new RegistrationResponse($accountInfo);
}

HTTP|CLI|etc. Translators - Function that builds the business request from the HTTP request, and converts the business response to a HTTP response. These wrap the use case or interactors to translate to the given communication channel. Again, single input object (HTTP request), single output object (HTTP response).

/**
 * Executes the usecase or controller in a web context
 * @param Http\Request $request
 * @return Http\Response
 */
public function handle(Http\Request $request)
{
    return $this->convertResponse($this->useCase->execute($this->convertRequest($request)));
}

/**
 * Converts a HTTP request into a RegistrationRequest
 * @param Http\Request $request
 * @return RegistrationRequest
 */
protected function convertRequest(Http\Request $request)
{
    return new RegistrationRequest(
        new UserCredentials(
            'username' => $request->post->get('username'),
            'password' => $request->post->get('password')
        ),
        new UserProfile(
            'name' => $request->post->get('name'),
            'gender' => $request->post->get('gender')
        )
    );
}

/**
 * Converts a RegistrationResponse into a Http\Response
 * @param RegistrationResponse $response
 * @return Http\Response
 */
protected function convertResponse(RegistrationResponse $response)
{
    return new Http\RedirectResponse($this->routing->generateUrl('/account'));
    // or 
    return new Http\Response($this->templating->render([
        'user' => $response->getUser()
    ]);
}

This way, you can ecapsulate some of your validation in your business objects rather than as form validation. You'd want to have a strategy on how you map various exception types into HTTP status codes, or into command line exit codes, etc.

This may be overkill based on your project, but I work with CLI and HTTP quite often so the added extraction is very handy. It also makes your HTTP code much simpler and less tied to any specific tools or frameworks.

Examples are in PHP, sorry if that is confusing at all. These should somewhat mimick the Entity Boundary Interactor or other similar architectural patterns.

share|improve this answer
add comment

I would rule out version 2 as it leads to cluttering the business object with form details. This is exactly why you have the request layer: to keep form and business object separated.

Versions 1 and 3 are pretty similar, except that 1 also requires the business logic to know about forms, even if only in a factory. So, unless you already have a business object factory that could help you here, I'd go for version 3.

(This all only makes limited sense as the amount of code is unknown etc.)

Btw, your "better version" is not necessarily better. In your first code sample you had the form fields spelled out twice. I'd put them in constants or something and use them. The second version hides those field names in the factory making it worse to understand where the business object input arguments a few lines down actually came from

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.