DDD: where to generate url slug of an entity? - entity

how do you deal with url slug generation in DDD?
Inside constructor? But entity relying on other service is not good.
Pass as constructor argument? I think slugs shouldnt be there because they are not business requirements. are they?
or just having a setter?

It seems like the URL slug IS part of your domain model, even though it seems like an infrastructure concern at first.
If you are modeling it as a property of your entity, I see no problem in passing it in the constructor arguments. It is certainly better then having it as a property with a public setter, open to be modified by anyone at anytime.
Create an ISlugGenerator interface and inject it into the appropriate layer (ApplicationService or DomainService, see here for more info), to generate the URL string and pass it in the constructor to the entity.
Implement the ISlugGenerator in the Presentation Layer, the one that actually holds the page/route that is going the be accessed via the URL.
You could argue that the URL really has no place in the domain model, because it is just some info that is related to the entity, but is not used in any decision making process.
Well, then think about Product Description or Product Image in an e-commerce application. It is the same thing. You most certainly have validation logic for these properties and this validation should be part of the Domain, but you probably don't make any other decisions based on them.
So, shouldn't you remove Description and Image from the Product entity? Actually, no. Even though the image is probably a URL just like the slug from your question.
The product will receive the imageUrl as a string parameter in its constructor, or be set via a method in the entity. But the imageUrl will be generated by some ImageUploadService, whose interface will be defined in the Application Layer and implemented in some Infrastructure Layer.

Related

Where to put web scrape logic in MVC

I'm building a .NET Core MVC application. It has a single endpoint that retrieves an imdb id of a movie by scraping the imdb site. So my question is, where do I put the logic to get the id? My original project structure is shown below.
+--Controller
+--Entry point api call
+--Logic
+--Class that retrieves imdbId
+--Models
+--Models
+--Context
So I was originally going to put the logic where it retrieves the id in the "Logic" folder and call it from the Controller. I was also going to instantiate the model and store it in the DB here. I also do request validation in the controller and make sure the given movie title and release year are correct format.
I'm starting to think this is incorrect though? Should I put request validation and id retrieval in the model layer? Any help on how to approach this would be appreciated.
So I was originally going to put the logic where it retrieves the id in the "Logic" folder and call it from the Controller.
This is what I would do too. ID retrieval is not a concern of the controller (the presentation layer does not care how you retrieve the ID) so it should be placed in a separate layer.
Should I put request validation and id retrieval in the model layer?
No, because this does not pertain to the models. The model layer should just contain the classes for your models. I would put request validation in the controller (presentation layer).
My suggestion is that your original project structure works fine. Within the logic layer, I would further separate concerns among different services, so that the ID retrieval functionality would reside in a separate service from the DB storage functionality (DB management could also be a separate layer on its own).
I would suggest you put it in the Logic class, so you can unit test the logic outside of the model. Your models should be super simple, just properties, and if there is some other internal logic they need.
The http call you will need to make I would put in your logic and ensure you are using some interface for your http client so you can create moqs for easier unit testing.

Accessing AppSettings.json value from a model class

I have a calculated field in a class used for photos which prepends a url to the filename, I want to be able to add a base url for the photos (which is to an azure storage account) which will come from the appsettings file.
Initially I created a strongly typed class to access the settings, and I can inject it just fine to say a service class, but how can I access this in a model class? Am I completely going in the wrong direction with this?
Thanks for any help!
When instantiating the model, you could inject your strongly typed settings class, as long as the model already has a dependency on that. Alternatively, you'd need to move the calculation of that field out of the model, or simply provide the base URL to the model from your service classes.

MVC - Is It Wrong To Redirect From Model

I would like to ask whether it's a good approach to redirect from within a model instead of a controller.
The reason I want to do that is because it is easier to unit test redirection from a model (I just pass a mock redirector object to the model in my tests) as opposed to controller which is more difficult to unit test. It also keeps controller thinner as all I do in the controller is create an instance of the model and pass it parameters from the request object. There is not a single if/else in the controller this way.
Is it a bad practise?
Most often in webapplications - MVC or not - redirects are implemented on a high-level layer. In non OOP code this often is a high level global function that knows a lot about the global static state and what represents a request and a response therein.
In more OOP driven sites, you find this often as a method with the "response" object (compare Symfony2 and HTTP Fundamentals; note that Symfony2 is not MVC), however, it often then has also some similar methods (e.g. see Difference between $this->render and $this->redirect Symfony2).
As most often those "response" objects are central in the web-application this qualifies as well as a high-level layer in my eyes.
From a testing standpoint - especially with integration testing - you normally do not need to test for redirects specifically. You should test that generally your redirect-functionality works on the HTTP layer so that parts of your application that make use of it can rely on it. Common problems are to not really follow the suggestions given in the HTTP/1.1 specs like providing a response body with redirects. A well working webapplication should honor that. Same for using fully qualified URIs.
So how does all fit this into MVC here? In a HTTP context this could be simplified as the following:
The response is to tell the user to go somewhere else.
If the user would not be important, the application could forward directly - that is executing a different command, the client would not be used for that, the redirect not necessary (sub-command).
The response is to say: Done. And then: See next here this command (in form of an URI).
This pretty much sounds like that the actual redirect is just some output you send to the client on the protocol level in client communication. It belongs into the interface of that protocol you want to support. So not into the model but into the client-interface and the boundary of the client interface inside an MVC application is the controller AFAIK.
So the redirect probably is a view-value-object with a special meaning. To get that working in a HTTP MVC you need a full URL abstraction which most PHP frameworks and libraries make a big round around because it's not well known how that works. So in the end I'd say: Do as Symfony2 has done, place it in a high level layer component, drop MVC and live with the deficiencies.
Everything else is hard to achieve, if you try otherwise, there is high risk to not stop with abstracting anymore.
Neither controller nor model should be redirecting anything anywhere. HTTP Location header is form of a response, which strictly in purview of views.
Model layer deals with business logic, it should be completely oblivious even to the existence of presentation layer.
Basically, it goes down to this: controllers handle input, views handle output. HTTP headers are part of output.
Note: when dealing with Rails clones, it is common to see redirects performed in "controller". It is because what they call "controller" is actually a merger of view and a controller responsibilities. This is a side-effect of opting to replace real views with simple templates as the 3rd side of triad.
I would say yes, it is wrong. As far as I understood, while models manage data and views manage layouts (i.e. how data should be displayed), controllers are only and exclusively in charge of the HTTP requests/responses management (in the case of a web app), and redirections typically belong to that tier in my opinion.
Examples in common frameworks
Symfony:
return $this->redirect($this->generateUrl('homepage'));
Spring MVC:
return "redirect:/appointments";
I think that you could have a model for your applications work flow or navigation (in your model layer) and then have your controller translate the different concepts in your work flow/navigation model into what views are to be displayed.
Your work flow class/module could know about the different activities/phases/steps that are available to the user, and it model your application kind of like a state machine. So your controller would make calls to this module to update the state and would recieve a response telling the controller which activity/phase/step it should go to.
That way your work flow model is easy to test but it still doesn't know about your view technology.
Many mentioned in comments these thoughts, so here is a summary:
The logic to figure out whether you need a redirect and what your redirect should be belongs into the controller. The model simply takes the data a view needs. This happens AFTER you decided which view to render. Think of the redirect as an instruction to perform a different controller action.
I use ASP.NET MVC and the controllers generate a RedirectResult for this purpose, which are completely unit testable. I don't know what is supported in your framework, but this is what MVC would do:
public class MyController : Controller {
public ActionResult ShowInfo(string id) {
if( id == null ) {
return new RedirectResult("searchpage");
} else {
return new ViewResult("displayInfo");
}
}
}
In your unit tests, you instantiate MyController and check the type of the result and optionally, the url or view name.
Whether your redirect is actually performed is not a unit test issue - that's essentially making sure your framework is working right. What you need to test is that you are giving the correct instruction (i.e. the redirect) and the correct url.

Spine.js have updateAttributes include new attributes

It seems that Spine's Model.updateAttributes only updates attributes, and does not create new ones in case you supply any.
In my usecase, I have a controller that creates part of the attributes. Then through an Ajax request the server responds with the full object, and I want to update the model instance living in Spine with the additional variables.
For example, I have a model with attributes: name, date_created. Through the controller a user instantiates an object providing only the name. An Ajax request notifies the server which in turn responds with a name and a date_created. This date_created should then be added to the user's model.
Model.updateAttributes doesn't work, and I wouldn't be too fond of deleting the object and creating a new one - that just seems as too much overhead. I could provide default values for variables that are not set upon creation, but that also has a negative side. I guess what I'm looking for is a method that could be called Model.createOrUpdateAttributes. Can anybody recommend a way to achieve this? Thanks!
I might haven't fully understood your usecase, but I'll try to answer.
You need to declare whatever attributes a type of a model has with the configure class method. This declaration helps various model function to do their job later.
After you declare all the attributes you need, you can create model instances with any of the previously declared attributes.
You don't have to provide values for all the declared attributes.
After the ajax call returns, the date_created will be set on your model instance. Until this happens it will be just undefined.
If this solution still can't work for you, please describe why, and I'll gladly try to help.

OOP Value Objects and Entities in the same class

I am refactoring an old procedural PHP website into a tasty OOP application with a light sprinkling of Domain Driven Design for added flavour.
I keep stumbling upon cases where I have a need for classes that can have subclasses which are either entities or value objects.
An url object, for example. There are a zillion urls out there and so they all cannot really be entities. But some are very special urls, like my home page. That is an entity.
Another example is, say, a 'configuration object'. I'd like some configurations to have identities so i can create 'presets' and administer them via an online control panel. For those a finder/repository is needed to find them and ORM is needed to manage their lifetimes. But, for others 'not-presets' (of the same class hierarchy) I'd like to be able to load them up with data that has been customised on the fly and does not need to be persisted.
I am envisaging a lot of :
class factory {
reconstitute($rawdata) {
if (raw data has identity)
load up and return entity version of the class
else
load up and return anonymous/value object version of the class
It all seems a bit odd.
Is there any pattern out there that discusses the best way to handle this issue?
I'm not sure I totally understand your scenerio but... does that really matter?
In my experience with EFs/ORMs the best way (that I can think of) to do what you are wanting to do is to let your entity class decide whether or not to load/persist itself from/to a database based on business rules defined in the class.
$url = new URLClass('KEY_DATA') // returns loaded object url if key if found in database
$url = new URLClass() // returns new url object
$url = new URLClass('', '110011000110010001000011101010010100') // returns new url with data loaded from raw data
Not sure if that really helps you out or if it even applies.