Skip to content

Extending

Replacing pieces

Yii2 has no application-wide interface bindings, so the component builds the core graph itself and exposes the seams as properties (an instance, a config array, a class name or a component id):

Property Interface Use it for
transport IndexNowKit\Http\TransportInterface a recording transport in tests, a proxy
debounceStore IndexNowKit\Debounce\DebounceStoreInterface a shared store the cache component cannot express
dispatcher IndexNowKit\Dispatch\DispatcherInterface another queue, an outbox table
urlResolver IndexNowKit\Url\UrlResolverInterface replace the whole "object → URLs" step
logger PSR-3 anything but Yii's logger
clock PSR-20 Psr\Clock\ClockInterface one clock for the throttle, the debounce window and the submission timestamps (IndexNowKit\Testing\FrozenClock in tests)
checks list of IndexNowKit\Check\CheckInterface extra lines in indexnow/check (a CDN purge, a tenant table)

A value none of these can resolve (a component id that names nothing, a class that is not of the interface) is an IndexNowKit\Exception\ConfigurationException naming the value, as everywhere else in the family.

Underneath, Wiring describes the graph once with the core's Adapter\ServicesBuilder (the properties above are its overrides, resolved by References; the Yii pieces are closures) and services() returns the lazy Adapter\Services; nothing is built before it is used, and a request that collects nothing builds nothing. Everything built is also readable, as delegates: kit(), config(), submitter(), collector(), keys(), transport(), debounceStore(), routeResolver(), observer(), staging(), checker(), rules(), and sitemapConfig() / sitemapSource() with the optional indexnowkit/sitemap installed (sitemapInstalled(); without it they throw a LogicException naming the package).

Custom resolvers

#[IndexNow(resolver: ProductUrlResolver::class)]      // a class Yii::$container can build
#[IndexNow(resolver: 'productUrls')]                    // or an application component id

The class implements IndexNowKit\Url\UrlResolverInterface; constructor dependencies come from Yii::$container.

Rules at runtime

Yii::$app->indexnow->observe(Product::class, [new IndexNow(route: 'product/view', params: ['id' => 'self'])], new IndexNowDefaults(when: 'active'));
Yii::$app->indexnow->rules()->registerFor(Page::class, fn (Page $page): ?RuleSet => ...);   // decided per object

observe() hooks the class through class-level events (yii\base\Event::on), the same mechanism as the active_record.models list.

Manual submissions

submit(iterable $urls), submitRecord($record, Event $event), submitRecords(iterable $records) (one request for many), urlsFor(), explain() return Results; collect() parks URLs in the request collector, flush() sends them now. Listen to results the Yii way: Yii::$app->indexnow->on(IndexNowComponent::EVENT_RESULT, fn (ResultEvent $e) => ...) (Event\ResultEvent::$result is the Result; the submitter and the command submitters raise it for every result), or lower-level Yii::$app->indexnow->submitter()->addListener(fn (Result $r) => ...).

What is the core's

The observer keeps only what is Yii's (the change set from changedAttributes, the previous state, the verify-on-commit staging); guarding, logging and the URLs of a row about to be deleted are the core's Hook\ObserverHelper. SubmitUrlsJob is Retry\WorkerOutcome plus a delayed re-push of the rejected URLs (the delay of Retry\RetryPolicy from retry.*, Retry-After first; yii2-queue's canRetry() only concerns exceptions, see queue.md). The options of every indexnow/<action> come from Console\Definitions and Sitemap\Console\Definitions, names, shortcuts, descriptions and defaults (getActionOptionsHelp() reads them from the definitions, not from the property docblocks), so php yii help indexnow/submit-record matches the bundle and artisan.

Console

controllerMap['indexnow'] accepts loader (IndexNowKit\Console\SubjectLoaderInterface, tenant scoping or another id format), formatter (ResultFormatterInterface, your JSON envelope) and submitters (SubmitterFactoryInterface). The command bodies are the IndexNowKit\Console\*Runner of indexnowkit/console; a tenant loop over SubmitSubjectsRunner is a ten-line controller action.