Download the PHP package iperson1337/nct-client-bundle without Composer

On this page you can find all versions of the php package iperson1337/nct-client-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package nct-client-bundle

NCT Client Bundle

English · Қазақша

CI Latest Version PHP Version

Symfony client for the National Catalog of Goods of Kazakhstan (НКТ): the complete nationalcatalog.kz portal API (product requests and their lifecycle, files, duplicates, cards, attributes, dictionaries) and the public nct.gov.kz API (search, timestamp export). Ships with retries, Redis-backed rate limiting, typed exceptions and value objects for the protocol's data.

The bundle knows the portal protocol and nothing about your domain model: responses come back as decoded arrays (or small value objects), and what to do with them is up to the application.

Coverage: all 23 operations of the official portal specification (https://nationalcatalog.kz/gwp/docs) and all 5 requests of the public nct.gov.kz collection.

Features

Requirements

Installation

Without Symfony Flex, register the bundle:

Configuration

config/packages/iperson1337_nct_client.yaml:

All keys are optional; the values above are the defaults (except api_key, which is empty, and redis_dsn, which is null).

Key Meaning
portal.host, portal.api_key portal address and the applicant's API key; every request operation goes here regardless of lookup_source
portal.timeout, portal.connect_timeout default Guzzle timeouts for both hosts; overridable per call with $timeoutOverride
portal.retry_count how many times to retry after 429 / 422 TOO_MANY_REQUESTS; $maxAttempts = 1 on a call disables retries
*.retry_after_seconds sleep() before a retry, per host
*.rate_limit proactive limit checked before each request: a Redis sliding window with its own key per host, so the hosts never throttle each other
lookup_source where NctClient::fetchProductByGtin() looks: nctgov — public search, normalised to {gtin, ntin_code}; nationalcatalog — GET /products/{gtin} on the portal, raw response
redis_dsn Redis for the limiters; when Redis is unavailable the limit is skipped with a warning and the request proceeds

Registered services (autowire by class): NctClient, NctPortalClient, NctGovClient, NctHttpClient, RequestDetailsParser, NationalCatalogIdentifier.

Usage

Product by GTIN

A short timeout and a single attempt for a synchronous check in a UI action (don't wait the full timeout and don't sleep on 429):

GTIN is not unique on the portal — a GTIN may belong to several cards. To see all of them:

Product request lifecycle

The portal rejects an NTIN attribute in a create request. To edit a published card either pass ntin in the payload of submitProductRequest() or start from the card itself:

name_ru, name_kk, ntin and tnved cannot be changed on an edit request; extended cards (with a KZTIN) are not editable through the API.

ProductRequestPayload compares bodies regardless of key and attribute order — use it to decide whether a stored request actually changed before sending a PUT that would re-trigger moderation:

Request status and details

Base statuses (RequestStatus): new, onModeration, accepted, underRevision, cancelled, readyToPublish, existingProductSelected, completed, rejected. Extended-card statuses in gzStatus (ExtendedRequestStatus): acceptedGz, underRevisionGz, rejectedGz, publishingGz.

Duplicates

When moderation sends a request back for DUPLICATE_REVIEW:

Photos and documents

Files are uploaded to the request first (statuses new, underRevision, cancelled; 5 MB max), then referenced by filename in the payload:

An extended card (isGov: true) needs front and back photos, the brand attribute and at least five additional characteristics before it can go to moderation.

Attribute definitions and dictionaries

nct.gov.kz: search, card, export

Timestamp export needs an nct.gov.kz account (limit: 120 requests per minute):

After several failed logins the portal locks the account for 10 minutes (403, locked_seconds).

NTIN / XTIN format

Identifiers are strings: leading zeros matter.

Exceptions

Every exception extends \RuntimeException and implements NctExceptionInterface, so an existing catch (\RuntimeException) keeps working and catch (NctExceptionInterface) catches any NCT failure.

Exception When
NctProductNotFoundException no card for the GTIN (nct.gov.kz answered 404 "product … not found" or an empty list). The message is stable: Product with GTIN {gtin} not found in NCT (nct.gov.kz)
NctRateLimitExceededException 429 or 422 TOO_MANY_REQUESTS and no attempts left (or maxAttempts: 1)
NctRequestTimeoutException connection timeout (ConnectException) or response timeout (cURL 28)
NctTransportException 5xx, network failure, attempts exhausted
NctClientException any other 4xx: invalid request, forbidden, changed API path. The message carries HTTP {status} {body} — the full body (capped at 2000 characters, marked when cut), because the body is what explains which attribute was rejected
NctResponseException 2xx whose body is not valid JSON

A 404 with a {"Message": "product … not found"} body counts as "not found" only for requests that opted in (NctRequest::$notFoundAsEmpty): a 404 caused by a changed API path must not look like a missing product.

Rate limiting and retries

Two layers protect every request:

  1. Proactive limit — RateLimiterInterface::waitIfNeeded() before the request, one limiter per host (NctTarget::Portal / NctTarget::Gov). The Redis implementation keeps a sorted set of timestamps; an atomic Lua script counts requests in the window and, when full, returns the time until the oldest one leaves it. If Redis fails, the limit is skipped with a warning — a limiter must never stop the host process.
  2. Retry after 429 — up to retry_count retries with the host's retry_after_seconds pause; maxAttempts: 1 on a call turns retries off and surfaces NctRateLimitExceededException at once.

One Guzzle client serves both hosts. Portal requests carry Content-Type: application/json, Accept and X-API-KEY (multipart uploads let Guzzle set the boundary); nct.gov.kz requests carry Accept only, plus Authorization: JWT … for the export — the API key never leaves for the public host.

Endpoints

Method HTTP
NctPortalClient::submitProductRequest() POST /gwp/portal/api/v1/products/requests
NctPortalClient::createEditRequest() POST /gwp/portal/api/v1/products/requests/{ntin}/edit-product
NctPortalClient::updateProductRequest() PUT /gwp/portal/api/v1/products/requests/{id}
NctPortalClient::deleteProductRequest() DELETE /gwp/portal/api/v1/products/requests/{id}
NctPortalClient::submitToModeration() PUT /gwp/portal/api/v1/products/requests/{id}/moderation
NctPortalClient::cancelRequest() PUT /gwp/portal/api/v1/products/requests/{id}/cancel
NctPortalClient::publishRequest() PUT /gwp/portal/api/v1/products/requests/{id}/publish
NctPortalClient::fetchRequestStatus() GET /gwp/portal/api/v1/products/requests/{id}/status
NctPortalClient::fetchRequestDetails() GET /gwp/portal/api/v1/products/requests/{id}/details
NctPortalClient::fetchProductRequests() GET /gwp/portal/api/v1/products/requests?page=&size=[&status=]
NctPortalClient::fetchDuplicates() GET /gwp/portal/api/v1/products/requests/{id}/duplicates
NctPortalClient::decideDuplicates() POST /gwp/portal/api/v1/products/requests/{id}/duplicate-decision
NctPortalClient::uploadPhoto() POST /gwp/portal/api/v1/storage/{requestId}/upload?imageType=
NctPortalClient::uploadDocument() POST /gwp/portal/api/v1/storage/{requestId}/upload/document
NctPortalClient::deleteFile() DELETE /gwp/portal/api/v1/storage/{requestId}/{fileName}
NctPortalClient::fetchProductByGtin() GET /gwp/portal/api/v1/products/{tin}
NctPortalClient::fetchProductsByTin() GET /gwp/portal/api/v2/products/{tin}
NctPortalClient::fetchAttributes() GET /gwp/portal/api/v1/products/requests/attributes
NctPortalClient::fetchGovAttributes() GET /gwp/portal/api/v1/products/requests/categories/{oktru}/gov-attributes
NctPortalClient::fetchDictionaries() GET /gwp/portal/api/v1/dictionaries
NctPortalClient::fetchDictionaryRoots() GET /gwp/portal/api/v1/dictionaries/{code}/roots
NctPortalClient::fetchDictionaryChildren() GET /gwp/portal/api/v1/dictionaries/{code}/children/{parentId}
NctPortalClient::fetchDictionaryItems() GET /gwp/portal/api/v1/dictionaries/{code}/items?page=&size=
NctGovClient::searchByGtin(), searchByTins() GET /api/integration/ofd/search_ofd/?tin={codes}
NctGovClient::searchByName() GET /api/integration/ofd/search_ofd/?q={name}&limit=&offset=
NctGovClient::fetchProduct() GET /api/core/products/{id}
NctGovClient::login() POST /api/auth/login/
NctGovClient::exportProducts() GET /api/integration/ofd/ofd_product/?from=&limit=&offset= (JWT)
NctGovClient::countChangedProducts() GET /api/integration/ofd/ofd_product_count/?from= (JWT)

Testing

NctHttpClientTest is a snapshot test of the transport (31 scenarios: retries, 422, every kind of 404, timeouts, error bodies, headers per host); the baseline lives in tests/Http/__snapshots__/. To re-record it deliberately: UPDATE_SNAPSHOTS=1 vendor/bin/phpunit. NctPortalClientTest and NctGovClientTest pin method, path, query, body and headers of every operation against a Guzzle MockHandler.

NctClient, NctPortalClient and NctGovClient are not final, so they can be stubbed in the consumer's own tests.

Scope

The bundle implements the portal protocol. It deliberately does not store requests or their statuses, decide when an identifier may be written to a product, build request payloads from a domain model, or map attribute and dictionary rows into the consumer's own reference data. The value objects give those rows a predictable shape; the mapping stays in the application.

License

MIT — see LICENSE.


All versions of nct-client-bundle with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
guzzlehttp/guzzle Version ^7.0
psr/log Version ^3.0
symfony/cache Version ^7.4
symfony/config Version ^7.4
symfony/dependency-injection Version ^7.4
symfony/http-kernel Version ^7.4
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package iperson1337/nct-client-bundle contains the following files

Loading the files please wait ...