Source code for collective.multiworkflow.chain

"""The workflow chain adapter.

Registered for :class:`~collective.multiworkflow.interfaces.
IAdditionalWorkflows` and the workflow tool, making it more specific than
Plone's default chain adapter, which is registered for ``Interface``. It never
replaces the chain configured for a type — it only appends.
"""

from . import logger
from .declaration import collect_contributions
from .interfaces import IAdditionalWorkflows
from plone.base.interfaces import IWorkflowChain
from Products.CMFCore.interfaces import IWorkflowTool
from Products.CMFPlone.workflow import ToolWorkflowChain
from typing import Any
from zope.component import adapter
from zope.interface import implementer


# type-var: zope's stubs type @implementer for classes only, but declaring a
# *function* factory is the pattern Plone uses for ToolWorkflowChain itself.
[docs] @adapter(IAdditionalWorkflows, IWorkflowTool) # type: ignore[type-var] @implementer(IWorkflowChain) def additional_workflows_chain(context: Any, tool: Any) -> tuple[str, ...]: """Append contributed workflows to the chain configured for the type. The base chain is read by calling Plone's default adapter *function* directly. That function resolves the chain from the tool's own ``_chains_by_type`` mapping rather than through ``getChainFor``, so this call cannot re-enter adapter lookup and no recursion guard is needed. A contributed id that no workflow in the tool answers to is logged and skipped: a bad declaration must never break chain lookup, because a failure here would make the object unusable rather than merely misconfigured. :param context: the content object providing a participating marker. :param tool: the ``portal_workflow`` tool. :returns: the base chain followed by the contributed workflows, in order and deduplicated. """ chain: list[str] = list(ToolWorkflowChain(context, tool)) for workflow_id in collect_contributions(context): if workflow_id in chain: continue if tool.getWorkflowById(workflow_id) is None: logger.warning( "Workflow %r contributed to %r does not exist in " "portal_workflow; skipping it.", workflow_id, "/".join(context.getPhysicalPath()) if hasattr(context, "getPhysicalPath") else context, ) continue chain.append(workflow_id) return tuple(chain)