-
Notifications
You must be signed in to change notification settings - Fork 16
Adapters, Requests and Data Providers
This article how the classes in \FACTFinder\Core\Server work together to provide the adapters (in \FACTFinder\Adapter) with data from the server.
The classes in the Adapter namespace form the main chunk of the library's public interface. All the classes you will use are really just dependencies of the adapters. Each adapter gives you high-level access to one FACT-Finder feature, such as the search itself, the tag cloud, product comparison or suggestions.
Among an adapter's dependencies there is only one for communication with the server: a Core\Server\Request object. Each adapter holds its own Request, which represents parameters and the target of the request and hides the details of the server connection.
A Request is more than just a data object containing parameters and a request target. It's actually a Facade which hides a Core\Server\ConnectionData object and a Core\Server\DataProvider. It only provides access to the relevant fields in the ConnectionData:
- It gives you read/write access to the parameters and HTTP header fields of the request.
- It gives lets you set the action to be requested on the server (e.g.
Search.ff). - It lets you configure timeouts for the request.
- It gives you access to the server's response.
This interface completely hides the actual execution of the request to the server. All it guarantees is that the server data is available when you call getResponse().
The DataProvider object hidden behind the Request determines how the data is actually obtained (from the server, or otherwise). Details on data providers follow below.
Because, we don't want users to wire up their requests manually, we provide request factories.
For each type of data provider, there is an implementation of Core\Server\RequestFactoryInterface. The factory takes care of setting up the right data provider and wiring up the Request objects for you. For instance, if you want your requests to be performed via cURL's multi-interface (parallel HTTP requests), all you need to do is:
$requestFactory = FF::getInstance('Core\Server\MultiCurlRequestFactory',
$loggerClass,
$configuration,
$requestParameters);
$request = $requestFactory->getRequest();
Of course, you need the last line for each adapter you want to create. Note that the request factory's third parameter is $requestParameters. This should be a Util\Parameters object representing the parameters from the request to the Client, so that requests to the Server can be pre-populated with these. (You can obtain such a Parameters object from Core\Client\RequestParser.)
These two classes, Request and RequestFactory, are the only ones you have to deal with to set up an adapter. The remaining classes are implementation details and therefore mostly of interest to contributors.
Implementations of AbstractDataProvider are responsible for the actual logic for turning a request into a response. There will usually be only one data provider per application (maintained by the single request factory in use) and it will handle all requests. When data for a request is obtained is at the discretion of the data provider, as long as a call to loadResponse() which actually provide the response.
The library comes with three data provider implementations:
-
FileSystemDataProviderturns the request parameters and target into a file name which it simply tries to load from the file system. This is very useful for unit testing (which is exactly where it is used): you can just save the server responses you want to test to individual files with the correct names in order to test adapters without ever connecting to the server. -
EasyCurlDataProviderestablishes the connection to the server via cURL (through PHP'scurl_*functions) using the "easy interface". That means that it sends each request sequentially at the time its response is requested. -
MultiCurlDataProvideralso uses cURL, but the "multi interface". That means this data provider can set up multiple connections in parallel, which greatly reduces the bottleneck that server requests cause. In order to utilize this, this data provider makes use of its freedom of when to send out requests: as soon as the first response is requested, all requests will be processed in parallel and the responses are stored until they are actually needed. Therefore, to make maximum use of this data provider, you should always configure all adapters (and therefore requests) before requesting the first response.
Other implementations are conceivable such a using sockets.