File Manager
Editing: Reference.php
<?php declare(strict_types=1); namespace Kreait\Firebase\Database; use Kreait\Firebase\Exception\DatabaseException; use Kreait\Firebase\Exception\InvalidArgumentException; use Kreait\Firebase\Exception\OutOfRangeException; use Psr\Http\Message\UriInterface; use Stringable; use function array_fill_keys; use function array_keys; use function array_map; use function basename; use function dirname; use function is_array; use function ltrim; use function sprintf; use function trim; /** * A Reference represents a specific location in your database and can be used * for reading or writing data to that database location. */ class Reference implements Stringable { /** * @internal */ public function __construct( private readonly UriInterface $uri, private readonly ApiClient $apiClient, ) { } /** * Returns the absolute URL for this location. * * @see getUri() */ public function __toString(): string { return (string) $this->getUri(); } /** * The last part of the current path. * * For example, "ada" is the key for https://sample-app.firebaseio.example.com/users/ada. * * The key of the root Reference is null. */ public function getKey(): ?string { $key = basename($this->getPath()); return $key !== '' ? $key : null; } /** * Returns the full path to a reference. */ public function getPath(): string { return trim($this->uri->getPath(), '/'); } /** * The parent location of a Reference. * * @throws OutOfRangeException if requested for the root Reference */ public function getParent(): self { $parentPath = dirname($this->getPath()); if ($parentPath === '.') { throw new OutOfRangeException('Cannot get parent of root reference'); } return new self($this->uri->withPath('/'.ltrim($parentPath, '/')), $this->apiClient); } /** * The root location of a Reference. */ public function getRoot(): self { return new self($this->uri->withPath('/'), $this->apiClient); } /** * Gets a Reference for the location at the specified relative path. * * The relative path can either be a simple child name (for example, "ada") * or a deeper slash-separated path (for example, "ada/name/first"). * * @throws InvalidArgumentException if the path is invalid */ public function getChild(string $path): self { $childPath = sprintf('/%s/%s', trim($this->uri->getPath(), '/'), trim($path, '/')); try { return new self($this->uri->withPath($childPath), $this->apiClient); } catch (\InvalidArgumentException $e) { throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); } } /** * Generates a new Query object ordered by the specified child key. * * @see Query::orderByChild() */ public function orderByChild(string $path): Query { return $this->query()->orderByChild($path); } /** * Generates a new Query object ordered by key. * * @see Query::orderByKey() */ public function orderByKey(): Query { return $this->query()->orderByKey(); } /** * Generates a new Query object ordered by child values. * * @see Query::orderByValue() */ public function orderByValue(): Query { return $this->query()->orderByValue(); } /** * Generates a new Query limited to the first specific number of children. * * @see Query::limitToFirst() */ public function limitToFirst(int $limit): Query { return $this->query()->limitToFirst($limit); } /** * Generates a new Query object limited to the last specific number of children. * * @see Query::limitToLast() */ public function limitToLast(int $limit): Query { return $this->query()->limitToLast($limit); } /** * Creates a Query with the specified starting point (inclusive). * * @see Query::startAt() */ public function startAt(bool|string|int|float $value): Query { return $this->query()->startAt($value); } /** * Creates a Query with the specified starting point (exclusive). * * @see Query::startAfter() */ public function startAfter(bool|string|int|float $value): Query { return $this->query()->startAfter($value); } /** * Creates a Query with the specified ending point (inclusive). * * @see Query::endAt() */ public function endAt(bool|string|int|float $value): Query { return $this->query()->endAt($value); } /** * Creates a Query with the specified ending point (exclusive). * * @see Query::endBefore() */ public function endBefore(bool|string|int|float $value): Query { return $this->query()->endBefore($value); } /** * Creates a Query which includes children which match the specified value. * * @see Query::equalTo() */ public function equalTo(bool|string|int|float $value): Query { return $this->query()->equalTo($value); } /** * Creates a Query with shallow results. * * @see Query::shallow() */ public function shallow(): Query { return $this->query()->shallow(); } /** * Returns the keys of a reference's children. * * @throws DatabaseException if the API reported an error * @throws OutOfRangeException if the reference has no children with keys * * @return string[] */ public function getChildKeys(): array { $snapshot = $this->shallow()->getSnapshot(); if (is_array($value = $snapshot->getValue())) { return array_map('strval', array_keys($value)); } throw new OutOfRangeException(sprintf('%s has no children with keys', $this)); } /** * Convenience method for {@see getSnapshot()}->getValue(). * * @throws DatabaseException if the API reported an error */ public function getValue(): mixed { return $this->getSnapshot()->getValue(); } /** * Write data to this database location. * * This will overwrite any data at this location and all child locations. * * Passing null for the new value is equivalent to calling {@see remove()}: * all data at this location or any child location will be deleted. * * @throws DatabaseException if the API reported an error */ public function set(mixed $value): self { if ($value === null) { $this->apiClient->remove($this->uri->getPath()); } else { $this->apiClient->set($this->uri->getPath(), $value); } return $this; } /** * Returns a data snapshot of the current location. * * @throws DatabaseException if the API reported an error */ public function getSnapshot(): Snapshot { $value = $this->apiClient->get($this->uri->getPath()); return new Snapshot($this, $value); } /** * Generates a new child location using a unique key and returns its reference. * * This is the most common pattern for adding data to a collection of items. * * If you provide a value to push(), the value will be written to the generated location. * If you don't pass a value, nothing will be written to the database and the child * will remain empty (but you can use the reference elsewhere). * * The unique key generated by push() are ordered by the current time, so the resulting * list of items will be chronologically sorted. The keys are also designed to be * unguessable (they contain 72 random bits of entropy). * * @param mixed|null $value * * @throws DatabaseException if the API reported an error */ public function push($value = null): self { $value ??= []; $newKey = $this->apiClient->push($this->uri->getPath(), $value); $newPath = sprintf('%s/%s', $this->uri->getPath(), $newKey); return new self($this->uri->withPath($newPath), $this->apiClient); } /** * Remove the data at this database location. * * Any data at child locations will also be deleted. * * @throws DatabaseException if the API reported an error */ public function remove(): self { $this->apiClient->remove($this->uri->getPath()); return $this; } /** * Remove the data at the given locations. * * Each location can either be a simple property (for example, "name"), or a relative path * (for example, "name/first") from the current location to the data to remove. * * Any data at child locations will also be deleted. * * @param string[] $keys Locations to remove * * @throws DatabaseException */ public function removeChildren(array $keys): self { $this->update( array_fill_keys($keys, null), ); return $this; } /** * Writes multiple values to the database at once. * * The values argument contains multiple property/value pairs that will be written to the database together. * Each child property can either be a simple property (for example, "name"), or a relative path * (for example, "name/first") from the current location to the data to update. * * As opposed to the {@see set()} method, update() can be use to selectively update only the referenced properties * at the current location (instead of replacing all the child properties at the current location). * * Passing null to {see update()} will remove the data at this location. * * @param array<mixed> $values * * @throws DatabaseException if the API reported an error */ public function update(array $values): self { $this->apiClient->update($this->uri->getPath(), $values); return $this; } /** * Returns the absolute URL for this location. * * This method returns a URL that is ready to be put into a browser, curl command, or a * {@see Database::getReferenceFromUrl()} call. Since all of those expect the URL * to be url-encoded, toString() returns an encoded URL. * * Append '.json' to the URL when typed into a browser to download JSON formatted data. * If the location is secured (not publicly readable), * you will get a permission-denied error. */ public function getUri(): UriInterface { return $this->uri; } /** * Returns a new query for the current reference. */ private function query(): Query { return new Query($this, $this->apiClient); } }
💾 Save
⬅ Back