Repository navigation
Add the hook contract and the hook pipeline - #2734
Merged
Merged
Conversation
… copy the entry for after hooks, narrow Get conversions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2694
Adds the hook contract to the SDK (
IBeforeValidateHook<T>and the Before/After pairs for Create, Update, Delete, Publish, Unpublish and Restore,HookContext<T>,HookOrderAttribute,HookRejectedException,ContentDocument) and the pipeline inFluentCMS.Corethat resolves hooks for a content class and forContentDocument, orders them by[HookOrder], runs them, and throwsHookRejectedExceptionat the first cancellation.ContentChanges.Betweencomputes the changed field paths in the dotted form validation uses; the pipeline recomputes them before each before hook, so a hook sees the changes of the hooks before it. After hooks work on a deep copy of the entry, because only before hooks may change it. The content service (#2693) will call the pipeline inside its transaction; the tests in this PR play that part against a SQLiteCmsDbContext. The validation pipeline already ran in the order the issue lists (#2685), includingRequired/RequiredWhenon publish, so it is unchanged; a test now pins that one result lists every failing field across declarative rules, field validators and entry validators.Dependencies
None.
Acceptance
OperationContextand change set availableBeyond the spec
HookContextinFluentCMS.Hooks, so they are there, together withHookOrderAttributeandHookRejectedException, which the spec does not place.ContentDocumentis inFluentCMS.Content.IAfterValidateHook. The spec listsIBeforeValidateHook<T>only, so there are 13 hook interfaces.HookContext<T>; one method per interface (BeforeCreateAsync, ...) so a class can implement a Before/After pair.Cancelrecords the cancellation and the pipeline throws after the hook returns; a hook can also throwHookRejectedExceptionitself. An after hook can cancel too, which rolls the write back.ContentDocumentand for the content class (and its base classes, such asContentItem) form one sequence ordered by[HookOrder], then by tiebreak rank. If they still tie, all-types hooks run first, then base classes, then the content class, each in registration order.IHookTiebreaker.Rank(Type)is an optional service for the plugin host's dependency order. Without it, registration order decides.IHookEntryMapper.ContentDocumentis the canonical entry, so hooks for a content class go through this seam (ToEntry,CopyTo), which the content service (IContentService and IContentService<T> with optimistic concurrency #2693) provides. A typed before hook's changes are copied back into the document. Without a mapper, a registered typed hook throwsInvalidOperationException.ContentChanges.Between(previous, entry). An operation that changes no field, such as publish, passes the stored state asprevious.ContentDocument.Get<T>. Converts only between numeric types, and only when the value fits; anything else throwsInvalidCastException.