Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
WorkflowLoaderFactory
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 6
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 pageMoveInProgress
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createWorkflowLoader
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 loadWorkflowById
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
42
 uuidFromTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 uuidFromTitlePair
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace Flow;
4
5use Flow\Content\BoardContent;
6use Flow\Data\ManagerGroup;
7use Flow\Exception\CrossWikiException;
8use Flow\Exception\InvalidDataException;
9use Flow\Exception\InvalidInputException;
10use Flow\Exception\InvalidParameterException;
11use Flow\Exception\InvalidTopicUuidException;
12use Flow\Exception\UnknownWorkflowIdException;
13use Flow\Model\UUID;
14use Flow\Model\Workflow;
15use MediaWiki\MediaWikiServices;
16use MediaWiki\Title\Title;
17use MediaWiki\WikiMap\WikiMap;
18
19class WorkflowLoaderFactory {
20    /**
21     * @var ManagerGroup
22     */
23    protected $storage;
24
25    /**
26     * @var BlockFactory
27     */
28    protected $blockFactory;
29
30    /**
31     * @var SubmissionHandler
32     */
33    protected $submissionHandler;
34
35    /**
36     * @var bool
37     */
38    protected $pageMoveInProgress = false;
39
40    /**
41     * @param ManagerGroup $storage
42     * @param BlockFactory $blockFactory
43     * @param SubmissionHandler $submissionHandler
44     */
45    public function __construct(
46        ManagerGroup $storage,
47        BlockFactory $blockFactory,
48        SubmissionHandler $submissionHandler
49    ) {
50        $this->storage = $storage;
51        $this->blockFactory = $blockFactory;
52        $this->submissionHandler = $submissionHandler;
53    }
54
55    public function pageMoveInProgress() {
56        $this->pageMoveInProgress = true;
57    }
58
59    /**
60     * @param Title $pageTitle
61     * @param UUID|null $workflowId
62     * @return WorkflowLoader
63     * @throws InvalidInputException
64     * @throws CrossWikiException
65     */
66    public function createWorkflowLoader( Title $pageTitle, $workflowId = null ) {
67        if ( $pageTitle->isExternal() ) {
68            throw new CrossWikiException( 'Interwiki to ' . $pageTitle->getInterwiki() . ' not implemented ', 'default' );
69        }
70
71        if ( $pageTitle->getNamespace() < 0 ) {
72            throw new InvalidDataException( 'Can not load workflow for special (< 0) namespace', 'invalid-title' );
73        }
74
75        // @todo: ideally, workflowId is always set and this stuff is done in the places that call this
76        if ( $workflowId === null ) {
77            if ( $pageTitle->getNamespace() === NS_TOPIC ) {
78                // topic page: workflow UUID is page title
79                $workflowId = self::uuidFromTitle( $pageTitle );
80            } else {
81                // board page: workflow UUID is inside content model
82                $page = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $pageTitle );
83                $content = $page->getContent();
84                if ( $content instanceof BoardContent ) {
85                    $workflowId = $content->getWorkflowId();
86                }
87            }
88        }
89
90        if ( $workflowId === null ) {
91            // We failed to get a Flow content model for this title,
92            // so we'll want to clear LinkCache (we're likely be in
93            // the process of creating a new workflow, so we don't
94            // want lingering cache data)
95            // Workflow::create doesn't READ_LATEST to fetch the
96            // article id. Let's forcibly make it look like the title
97            // does not yet exist (in which case it will be
98            // READ_LATEST when we actually want to store it)
99            $title = clone $pageTitle;
100            $title->resetArticleID( 0 );
101
102            // no existing workflow found, create new one
103            $workflow = Workflow::create( 'discussion', $title );
104        } else {
105            $workflow = $this->loadWorkflowById( $pageTitle, $workflowId );
106        }
107
108        return new WorkflowLoader(
109            $workflow,
110            $this->blockFactory->createBlocks( $workflow ),
111            $this->submissionHandler
112        );
113    }
114
115    /**
116     * @param Title|false $title
117     * @param UUID $workflowId
118     * @return Workflow
119     * @throws InvalidDataException
120     * @throws UnknownWorkflowIdException
121     */
122    public function loadWorkflowById( /* Title or false */ $title, $workflowId ) {
123        /** @var Workflow $workflow */
124        $workflow = $this->storage->getStorage( 'Workflow' )->get( $workflowId );
125        if ( !$workflow ) {
126            throw new UnknownWorkflowIdException( 'Invalid workflow requested by id', 'invalid-input' );
127        }
128        if ( $workflow->getWiki() !== WikiMap::getCurrentWikiId() ) {
129            throw new UnknownWorkflowIdException( 'The requested workflow does not exist on this wiki.' );
130        }
131        if ( $title !== false && $this->pageMoveInProgress === false && !$workflow->matchesTitle( $title ) ) {
132            throw new InvalidDataException( 'Flow workflow is for different page', 'different-page' );
133        }
134
135        return $workflow;
136    }
137
138    /**
139     * Create a UUID for a Title object
140     *
141     * @param Title $title
142     * @return UUID
143     * @throws InvalidInputException When the Title does not represent a valid uuid
144     */
145    public static function uuidFromTitle( Title $title ) {
146        return self::uuidFromTitlePair( $title->getNamespace(), $title->getDBkey() );
147    }
148
149    /**
150     * Create a UUID for a ns/dbkey title pair
151     *
152     * @param int $ns
153     * @param string $dbKey
154     * @return UUID
155     * @throws InvalidInputException When the pair does not represent a valid uuid
156     */
157    public static function uuidFromTitlePair( $ns, $dbKey ) {
158        if ( $ns !== NS_TOPIC ) {
159            throw new InvalidParameterException( "Title is not from NS_TOPIC: $ns" );
160        }
161
162        try {
163            return UUID::create( strtolower( $dbKey ) );
164        } catch ( InvalidInputException $e ) {
165            throw new InvalidTopicUuidException( "$dbKey is not a valid UUID", 'invalid-input', $dbKey );
166        }
167    }
168}