Localisation updates from https://translatewiki.net.
[mediawiki.git] / includes / jobqueue / JobFactory.php
blobe90f28d274908f7f82889cc31a69e5678bf858f2
1 <?php
3 namespace MediaWiki\JobQueue;
5 use Closure;
6 use GenericParameterJob;
7 use InvalidArgumentException;
8 use Job;
9 use MediaWiki\Page\PageReference;
10 use MediaWiki\Title\Title;
11 use Wikimedia\ObjectFactory\ObjectFactory;
13 /**
14 * @since 1.40
16 class JobFactory {
18 private ObjectFactory $objectFactory;
20 /** @var array<array|callable|string> Object specs, see ObjectFactory */
21 private array $jobObjectSpecs;
23 /**
24 * @param ObjectFactory $objectFactory
25 * @param array<array|callable|string> $jobObjectSpecs Object specs, see ObjectFactory
27 public function __construct( ObjectFactory $objectFactory, array $jobObjectSpecs ) {
28 $this->objectFactory = $objectFactory;
29 $this->jobObjectSpecs = $jobObjectSpecs;
32 /**
33 * Create the appropriate object to handle a specific job.
35 * @note For backwards compatibility with Job::factory,
36 * this method also supports an alternative signature:
37 * @code
38 * newJob(
39 * string $command,
40 * PageReference $page,
41 * array $params
42 * )
43 * @endcode
45 * @param string $command Job command
46 * @param array $params Job parameters
48 * @return Job
49 * @throws InvalidArgumentException
51 public function newJob( string $command, $params = [] ): Job {
52 if ( !isset( $this->jobObjectSpecs[ $command ] ) ) {
53 throw new InvalidArgumentException( "Invalid job command '{$command}'" );
56 $spec = $this->jobObjectSpecs[ $command ];
57 $needsTitle = $this->needsTitle( $command, $spec );
59 // TODO: revisit support for old method signature
60 if ( $params instanceof PageReference ) {
61 // Backwards compatibility for old signature ($command, $title, $params)
62 $title = Title::newFromPageReference( $params );
63 $params = func_num_args() >= 3 ? func_get_arg( 2 ) : [];
64 } elseif ( isset( $params['namespace'] ) && isset( $params['title'] ) ) {
65 // Handle job classes that take title as constructor parameter.
66 // If a newer classes like GenericParameterJob uses these parameters,
67 // then this happens in Job::__construct instead.
68 $title = Title::makeTitle(
69 $params['namespace'],
70 $params['title']
72 } else {
73 // Default title for job classes not implementing GenericParameterJob.
74 // This must be a valid title because it not directly passed to
75 // our Job constructor, but rather its subclasses which may expect
76 // to be able to use it.
77 $title = Title::makeTitle(
78 NS_SPECIAL,
79 'Blankpage'
83 if ( $needsTitle ) {
84 $args = [ $title, $params ];
85 } else {
86 $args = [ $params ];
89 /** @var Job $job */
90 $job = $this->objectFactory->createObject(
91 $spec,
93 'allowClassName' => true,
94 'allowCallable' => true,
95 'extraArgs' => $args,
96 'assertClass' => Job::class
100 // TODO: create a setter, marked @internal
101 $job->command = $command;
102 return $job;
106 * Determines whether the job class needs a Title to be passed
107 * as the first parameter to the constructor.
109 * @param string $command
110 * @param string|array|Closure $spec
112 * @return bool
114 private function needsTitle( string $command, $spec ): bool {
115 if ( is_callable( $spec ) ) {
116 $needsTitle = true;
117 } elseif ( is_array( $spec ) ) {
118 if ( isset( $spec['needsPage'] ) ) {
119 $needsTitle = $spec['needsPage'];
120 } elseif ( isset( $spec['class'] ) ) {
121 $needsTitle = !is_subclass_of( $spec['class'],
122 GenericParameterJob::class );
123 } elseif ( isset( $spec['factory'] ) ) {
124 $needsTitle = true;
125 } else {
126 throw new InvalidArgumentException(
127 "Invalid job specification for '{$command}': " .
128 "must contain the 'class' or 'factory' key."
131 } elseif ( is_string( $spec ) ) {
132 $needsTitle = !is_subclass_of( $spec,
133 GenericParameterJob::class );
134 } else {
135 throw new InvalidArgumentException(
136 "Invalid job specification for '{$command}': " .
137 "must be a callable, an object spec array, or a class name"
141 return $needsTitle;