I have a question regarding the following situation. Let's say we have 2 domains with 2 aggregates. Domain A and domain B are different microservices.
Domain A - product aggregate
Domain B - shop aggregate
In our design we decide that domain A don't have knowledge about domain B. In domain B each shop aggregate have a reference to one or more products (sellable items).
If we want to remove a product then we can send a RemoveProductCommand to domain A - product aggregate.
How to handle the update of the shop's where the items have to be removed from the sellable item list? We want to do this in a kind of "transactional" why (only mark as removed if it is also removed from all the shops).
I already thought about it and I see 4 possible options:
Listen in the shop aggregates to ProductRemovedEvent and then remove the product reference from the shop. Accept that this theoretical can result in situation where the product can't be removed and will be still on the shop selling list.
Create a SAGA in domain A and first remove items from shops before mark the product as removed. If the Saga processing failed then all the shop statussen should be restored by sending some restore commands to the already modified shop aggregates. To know which shop references to the product we use a query request to fetch that information.
Same as bullet 2 but store also shop information (id's) in the product aggregate (productListedInShopList).
Other domain/aggregate definitions (merge them for example)
Any suggestions what's the best way to solve this?
I'm for option 2, but:
"A don't have knowledge about domain B": Option two promotes that B is upstream and A is downstream (A depends on B because A sends commands to B and A subscribes to events of B. This commands and events are part of the API of B), and not the other way around. But, this is fine! A and B are not mutually dependent.
Additionally, I would consider introducing the concept of Product in Domain B. For example, ShopProduct. This aggregate can be linked to your shops keeping the invariants safe (similar to your point number 3) within B domain model. This will decouple your bounded contexts: ShopProduct is how Shop bounded context understand this Product concept. This will enable you to run only domain model B as an independent application as well.
ProductRemovedEvent would put Product (domain A) in some PENDING state, for example, REMOVING, and this event will trigger Saga
Saga would communicate between Product (domain A) and ShopProduct (domain B):
ProductRemovedEvent received, and send Command to Shop model
ProductRemovedFromAllShopsSuccessfully received from Shop and we send a command to Product to update state to REMOVED
ProductRemovedFromAllShopsUnSuccessfully received from Shop and we send a command to Product to update state to some error state or initial state in order to compensate.
...
Related
Our client would like to be able to give out a preconfigued URL (URL with GET param, similar to affiliate partner URL) to their customers and for customers who visit the catalog through that URL to be able to see only a subset of products in that catalog.
I have noticed it is possible in ICM 7.10 to create affiliate partner and programs which generate specific URLs and it is also possible to define a catalog view which exclude certain products from the catalog for a targeted group of customers or customer segments but it is not possible to exclude products from the catalog for a partner.
Is there some other out-of-the-box platform functionality which would allow our client to assign a certain catalog view based on the URL which customer has used to visit the catalog or do we need to implement a fully customized solution to achieve this?
Yeah, this is not possible with affiliate links.
You'll need to write some custom code, but it might not be that difficult. The usergroups list (customer segments) that the user belongs to are kept in the session object (T_CurrentUserUserGroupKeys). See WebshopPGIDProvider it puts the user by default in the everyone group. You can write a pipeline that puts the customer in a segment by updating this list so that you can then use the segment for the catalog view. Just remember to do this before the pgid is generated.
I'm designing a small application using Symfony2, with a DDD domain conceived as a vendor. This allows me to abstract my domain by not making any assumptions on what uses it. Basically, this domain is a set of business entities and services which perform their internal stuff. The business operations are called from the outside (Symfony controllers) by simple facades that do not expose anything from the domain.
Now, I would like to test my domain to validate its business rules. Given that this domain can't work on its own as it needs concrete repositories implementations, I set up my tests to use mocks of these repositories. My question is : how can I validate all the domain actions which are performed internally ?
For instance, suppose my domain is made of two entities : Article and Category. I can traverse an article to get its category, but I can't traverse a category to get its articles as it doesn't make sense in the context of my domain. Now, I have a business rule that states that whenever a category is disabled, all the articles on this category should be disabled as well.
The entry point for this action would be a disable($category) method on a CategoryFacade service. This action would first disable the category, then fetch all the articles of this category and disable them.
If I call the disable() action from a test case, I can validate that my category was correctly disabled as it is the actual object on which I am performing the test. But what about the articles ? I don't have a getArticles() method on my category, and since my domain only uses mocks as repositories, it wouldn't make any sense to fetch manually the articles and asserting on them.
Edit
The answer proposed below reminded me of something critical. Indeed, in my example, a category is to be considered as an AR as it has an existence outside the scope of an article. But since an article is an AR as well, it should be entirely responsible for its own consistency. That means that the deactivation of all articles linked to a category should not be initiated by a category service, as this service shouldn't know anything about articles. My choice will be the one proposed below : dispatch en event whenever a category is disabled, and perform deactivation on articles in a service which is inside the boundaries of my article.
In first place it is best to not test repositories togheter with domain logic and since repositories should be used only in application layer, then you shoudln't test application services. If you have to, then just create some test repository (memory based).
You should test your business rules just on domain objects. In example if you want to test if user rating works fine then do:
rated_user = UserFactory(parameters)
assertEqual(rated_user.rating, Rating(0))
rating_user = UserFactory(parameters)
rating_value = 3
rating_user.rateUser(rated_user, rating)
assertEqual(rated_user.rating, Rating(3))
Testing of your case is difficult because ARs should be changed in different transactions (probably even not in the same request). From what you say it seems that Category should be an AR (aggregate root), because in order to disable category we have to fetch one category without using an article to do so.
Now when you disable category, you should send event that articles should get and disable itself then. You can test if articles are disabled just by calling EventListener callback, that would be better IMHO. Testing both ARs togheter would be actually an integration test, which requires more setup.
Anyway, to test if all articles of a given category are disabled, you have to fetch them, probably using something like "articlesRepository.getArticlesOfCategory(category)" and check one by one if it's disabled. There is no other way.
Our main product opinion aquisition channel are our mailings, that are sent after a purchase. Additionally, within Your Account panel, in past purchases there is an option to review a product a client bought.
I would like to compare how many percent of reviews does the functionality in Your Account provides. Adding a review is set as a goal, but I can't compare them as I would compare traffic channels, because Your Account page is not a channel. What would be the correct way to do that?
I have also done a sequence which includes users, step 1 is Page - Your Account, step 2 is Goal Completion per user more and equal 1. I'm not sure if I approached this problem correctly.
This is my current understanding of the events on pressing the Activate button:
If the user has replication permission, the content is sent to the dispatcher.
If the user does not have replicate, the Request for Activate workflow is run. Out of the Box this performs two steps which are both sent to the Administrators group.
If I change the OOB Request for Activation workflow to assign to another group then this group gets the message in their CQ Inbox instead.
My requirement is that I have multiple websites belonging to different divisions within the company, meaning that each has separate groups for users who can only author content and users who can Approve/Activate that content. In one case there is an additional requirement for the content in the careers section to be approved by the HR team only.
How can I alter the workflow to achieve these requirements?
I can think of two ways of doing this:
1) Change the OOB box workflow to use OR steps to switch to differnt groups based on the content path. This could get very complex when dealing with pages for both pages and assets, and the special conditions like the careers example.
2) Create a custom step that runs Java code that uses the AccessControlManager class to look for replicate permissions on the node, and if there aren't any then to traverse up the tree until it finds a node with permissions.
I've gone with option 1) for a similar problem.
If your main concern is having too many branches in your OR Split, maybe there's an opportunity to break down the workflow's decisions into multiple steps, instead of having one decision point where it branches out to many different paths.
For example, you might first split by what site the payload is on, and then split again based on user type, or section of the site. So, something like:
site 1
section 1
role 1
role 2
section 2
site 2
... and so on, where each level of indentation represents a separate OR Split.
If you use the Container Step to trigger a sub-workflow at each of these decision points, that may help keep your workflow more organised.
Because I didn't love the idea of changing the OOB Request for Activation workflow, I minimised that by making the first step an OR Split that does a generic check - basically:
Pseudo-code:
if (we're in one of the sites that's subject to my custom workflows) {
Container step that points to my main custom workflow;
} else {
Continue with the default Request for Activation workflow steps;
}
That way you make minimal changes to the OOB workflow, and leave yourself open to running the default workflow if you set up a new site on the same instance, and don't want it subject to your custom workflow.
We've created a custom property in each page, "page owner", which in fact is a pointer to a group (I wish we have made it inheritable through the tree since beginning). Then workflow was customized so that page owner group receives this in their inbox for approval.
Basically I have a site in which I want my clients to be owners of a group, and then anonymous users can add nodes through their group and my clients will receive notification if someone adds a node in their group.
Basically the service is a lead generation service so in effect the content type is a landing page and when anonymous users go to put their details in, dependent on which group they do it through, the client will receive the notification.
i.e. My clients group is www.example.com/group1 and they send out a link with their URL to generate some leads.
example.com/group1/node/add/landing-page
Once this node has been created, will it be possible to notify the group1 owner (I assume if I set the correct Rules)?
On top of this, I want the group1 owner to be able to login and see a Views display of all the nodes that have been created in their group.
I assume Organic Groups is the wway to go here, but I may be mistaken - any hep would be appreciated.
Unless this has dramatically changed in D7, I don't think you're going to be able to let anonymous users post into Groups. The whole concept and structure of OG relies on users being logged in and identifiable.
In other words, I think you have to be a member of a Group to post in it, and anonymous (user 0) can never belong to a Group.