3 namespace MediaWiki\JobQueue
;
6 use GenericParameterJob
;
7 use InvalidArgumentException
;
9 use MediaWiki\Page\PageReference
;
10 use MediaWiki\Title\Title
;
11 use Wikimedia\ObjectFactory\ObjectFactory
;
18 private ObjectFactory
$objectFactory;
20 /** @var array<array|callable|string> Object specs, see ObjectFactory */
21 private array $jobObjectSpecs;
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;
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:
40 * PageReference $page,
45 * @param string $command Job command
46 * @param array $params Job parameters
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(
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(
84 $args = [ $title, $params ];
90 $job = $this->objectFactory
->createObject(
93 'allowClassName' => true,
94 'allowCallable' => true,
96 'assertClass' => Job
::class
100 // TODO: create a setter, marked @internal
101 $job->command
= $command;
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
114 private function needsTitle( string $command, $spec ): bool {
115 if ( is_callable( $spec ) ) {
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'] ) ) {
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 );
135 throw new InvalidArgumentException(
136 "Invalid job specification for '{$command}': " .
137 "must be a callable, an object spec array, or a class name"