diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..824c5d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# +# vendor-dir (see composer.json). +# +/lib/ diff --git a/BitfinexStreamerPlugin.php b/BitfinexStreamerPlugin.php new file mode 100644 index 0000000..41066e9 --- /dev/null +++ b/BitfinexStreamerPlugin.php @@ -0,0 +1,58 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +require_once dirname(__FILE__) . '/lib/autoload.php'; + +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Streamer\osTicket\Factories\UseCaseFactory; +use Bitfinex\Data\Streamer\osTicket\Configuration\BitfinexStreamerPluginConfig; + +/** + * Entry point class to bfx-ost-streamer plugin. + */ +class BitfinexStreamerPlugin extends \Plugin { + + /** + * {@inheritDoc} + */ + public $config_class = BitfinexStreamerPluginConfig::class; + + /** + * The plugin directory path. + * + * @var string + */ + const PLUGIN_DIR = __DIR__; + + /** + * {@inheritDoc} + */ + public function bootstrap() { + $factory = new UseCaseFactory(); + + foreach ($factory->formats() as $name => $label) { + if (Helper::isUseCaseEnabled($name)) { + $factory->create($name); + } + } + } + +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9b3248c --- /dev/null +++ b/README.md @@ -0,0 +1,356 @@ +# Bitfinex osTicket Streamer + +[![License](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://opensource.org/licenses/Apache-2.0) +![GitHub Release](https://img.shields.io/github/release/bitfinexcom/bfx-ost-streamer/all.svg) +![GitHub Release Date](https://img.shields.io/github/release-date/bitfinexcom/bfx-ost-streamer.svg) +![GitHub Last Commit](https://img.shields.io/github/last-commit/bitfinexcom/bfx-ost-streamer.svg) +![GitHub Pull Requests](https://img.shields.io/github/issues-pr/bitfinexcom/bfx-ost-streamer.svg) +![stability-stable](https://img.shields.io/badge/stability-stable-green.svg) +[![Works on osTicket v1.10](https://img.shields.io/badge/osTicket-v1.10-green)](https://github.com/osTicket/osTicket/tree/v1.10.7) +[![Works on osTicket v1.11](https://img.shields.io/badge/osTicket-v1.11-green)](https://github.com/osTicket/osTicket/tree/v1.11) +[![Works on osTicket v1.12](https://img.shields.io/badge/osTicket-v1.12-green)](https://github.com/osTicket/osTicket/tree/v1.12.6) +[![Works on osTicket v1.14](https://img.shields.io/badge/osTicket-v1.14-green)](https://github.com/osTicket/osTicket/tree/v1.14.8) +[![Works on osTicket v1.15](https://img.shields.io/badge/osTicket-v1.15-green)](https://github.com/osTicket/osTicket/tree/v1.15.6) +[![Works on osTicket v1.16](https://img.shields.io/badge/osTicket-v1.16-green)](https://github.com/osTicket/osTicket/tree/v1.16.1) + + + +- [Introduction](#introduction) +- [Copying](#copying) +- [Prerequisites](#prerequisites) +- [Install](#install) +- [Options](#options) + - [General Options](#general-options) + - [Stream Options](#stream-options) + - [Beanstalk Stream Options](#beanstalk-stream-options) + - [Use Cases Options](#use-cases-options) + - [Tickets Creation Use Cases Options](#tickets-creation-use-cases-options) + - [Record Options](#record-options) + - [Amazon Kinesis Record Options](#amazon-kinesis-record-options) + - [Serializer Options](#serializer-options) + - [CSV Serializer Options](#csv-serializer-options) + - [JSON Serializer Options](#json-serializer-options) + - [NDJSON Serializer Options](#ndjson-serializer-options) + - [Encoder Options](#encoder-options) + - [UTF-8 Encoder Options](#utf-8-encoder-options) + - [Base16 Encoder Options](#base16-encoder-options) + - [Base64 Encoder Options](#base64-encoder-options) +- [Signals](#signals) + - [Format Signals](#format-signals) + - [Option Signals](#option-signals) + - [Use Case Signals](#use-case-signals) +- [Examples](#examples) + - [Signal Examples](#signal-examples) + - [Format Signal Examples](#format-signal-examples) + - [Use Case Signal Examples](#use-case-signal-examples) +- [Maintainers](#maintainers) + + +## Introduction + +The [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) is an [osTicket](https://osticket.com/) plugin that allows the creation of data streams to any third-party system. + + +## Copying + +The [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) is free software. See the files whose names start with *LICENSE* (case-insensitive) for copying permission. The manuals, and some of the runtime libraries, are under different terms; see the individual source files for details. + +Copyright years on [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) source files may be listed using range notation, e.g., 2017-2022, indicating that every year in the range, inclusive, is a copyrightable year that could otherwise be listed individually. + + +## Prerequisites + +The [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) is a plugin for [osTicket](https://osticket.com/), it is therefore necessary to have it installed in order to use this plugin; here you can find the [system requirements](https://docs.osticket.com/en/latest/Getting%20Started/Installation.html#prerequisites). However, note that this plugin can also be used with previous versions of [osTicket](https://osticket.com/) (versions *greater than* or *equal to* *v1.10*), provided a [PHP](https://www.php.net/) version *greater than* or *equal to* *7.0* is used. In addition, the following [PHP](https://www.php.net/) extensions are also required: + +- [Data Filtering](https://www.php.net/manual/en/book.filter.php) +- [Multibyte String](https://www.php.net/manual/en/book.mbstring.php) +- [JavaScript Object Notation](https://www.php.net/manual/en/book.json.php) + +However, these extensions are default extensions of [PHP](https://www.php.net/) or requested by [osTicket](https://osticket.com/) itself so, most likely, none of these have to be installed. + + +## Install + +The [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) is a standard [osTicket](https://osticket.com/) plugin, so it can be installed and configured following the standard procedure; see the [official osTicket guide](https://docs.osticket.com/en/latest/Admin/Manage/Plugins.html) to manage the plugins. Note that before activating the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin, it is required to run [composer](https://getcomposer.org/) within this plugin directory to install external libraries and verify that the environment meets all the requirements. + + +## Options + +The intended audience of this section are end users, who will have to configure the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin via the [administration panel](https://docs.osticket.com/en/latest/Admin%20Panel.html). + +The [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) requires several configurations in order to be run properly. There are various sections that have to be configured; below is a brief introduction to the main ones. + +### General Options + +In this section there are some general settings such as, for example, the *helpdesk code*. This is an optional configuration that can be used to identify a specific instance; this code must start with an alphabetic character followed by alphabetic characters, hyphens or underscores, for a maximum total length of *8* characters. + +### Stream Options + +In this section you can choose the stream type where to submit the [records](#record-options) and configure different general settings of it. Options that appear in this section, after the type of stream has been chosen, depend on the stream itself; see the following sections for more information. Basically, a stream represents the set of all the events of the same type that occurred over time. + +![The stream options](doc/stream.gif "The stream options") + +Note that third-party plugins can add more streams to those provided by default, see the [Format Signals](#format-signals) section for more information. + +#### Beanstalk Stream Options + +[Beanstalk](https://beanstalkd.github.io/) is a simple, fast work queue. Its interface is generic, but was originally designed for reducing the latency of page views in high-volume web applications by running time-consuming tasks asynchronously. Although it is not really a stream according to the formal definition, it can improve the reliability of the system by switching from a "*fire and forget*" paradigm to an improved management of jobs with a strategy to retry in case of an error. See the [protocol specifications](https://raw.githubusercontent.com/beanstalkd/beanstalkd/master/doc/protocol.txt) for an overview and constraints on some options. + +Note that when using the [Beanstalk](https://beanstalkd.github.io/) as a stream, [osTicket](https://osticket.com/) will act as a *producer*, therefore an external program that acts as a *consumer* is necessary in order to forward the records to the real stream. + +### Use Cases Options + +A use case represents a type of event that occurs on the [osTicket](https://osticket.com/) instance; here follows a list of use cases supported by the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin, one for each event, which can be configured independently. Note that third-party plugins can add more use cases to those provided by default, see the [Use Case Signals](#use-case-signals) section for more information. + +Basically, for each use case, the following main options should be configured: + +- whether to enable the streaming of this use case +- how data should be serialized; this determines the type of [stream](#stream-options) that will be created. See the [Serializer Options](#serializer-options) section for a list of all available serializer types +- record type; this is normally bound to the [stream](#stream-options) type but, in the case of an agnostic stream (eg [Beanstalk](#beanstalk-options)), it may also not be. See the [Record Options](#record-options) section for a list of all available record types + +![A use case options](doc/use-case.gif "A use case options") + +Other settings may be available, depending on the various selected options; for example, if the [stream](#stream-options) supports several queues, this can be chosen in this section so that each use case can be sent to its own queue. + +#### Tickets Creation Use Cases Options + +The ticket creation use case describes the event that occurs whenever a new ticket is created; by default only a few information is sent to the [stream](#stream-options), here's the list: + +- `helpdesk_code` as explained in the [General Options](#general-options) section +- `datetime_complete` is the date and time of the instant in which the new ticket has been created +- `department_id` is the identifier of the department under which the ticket has been created +- `department_name` is the name of the department under which the ticket has been created +- `helptopic_id` is the identifier of the help topic that has been assigned to the newly created ticket +- `helptopic_label` is the name of the help topic that has been assigned to the newly created ticket + +However, third-party plugins can add more information to those streamed by default, see the [Use Case Signals](#use-case-signals) section for more information. + +### Record Options + +In this section the record type that will be sent to the [stream](#stream-options) can be chosen and several settings can be configured. Options that appear in this section, after the type of record has been chosen, depend on the record itself; see the following sections for more information. Basically, a record represents a single event in the [Stream](#stream-options). + +![A record options](doc/record.gif "A record options") + +Note that third-party plugins can add more records to those provided by default, see the [Format Signals](#format-signals) section for more information. + +#### Amazon Kinesis Record Options + +This type of record is suitable for use with [Amazon Kinesis Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/what-is-this-service.html), a fully managed service for delivering real-time [streaming data](http://aws.amazon.com/streaming-data/) to destinations such as Amazon Simple Storage Service (Amazon S3), Amazon Redshift, Amazon OpenSearch Service, Splunk, and any custom HTTP endpoint or HTTP endpoints owned by supported third-party service providers, including Datadog, Dynatrace, LogicMonitor, MongoDB, New Relic, and Sumo Logic. [Kinesis Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/what-is-this-service.html) is part of the [Kinesis](https://aws.amazon.com/kinesis/) streaming data platform. See the [API Reference](https://docs.aws.amazon.com/kinesis/latest/APIReference/Welcome.html) for a thorough overview of the service. + +This type of record makes use of an [encoder](#encoder-options), to manage any binary data, and a [serializer](#serializer-options) if the record itself have to be submitted to a [stream](#stream-options) that serialize the records; see relevant sections for more information. + +### Serializer Options + +In this section the serializer type that will be used when the different entities have to be converted into a stream of bytes can be chosen and several settings can be configured. Options that appear in this section, after the type of serializer has been chosen, depend on the serializer itself; see the following sections for more information. + +Note that third-party plugins can add more serializers to those provided by default, see the [Format Signals](#format-signals) section for more information. + +#### CSV Serializer Options + +This serializer, best suited as a data serializer, converts an array into a string of *comma-separated values*; see [RFC 4180](https://www.rfc-editor.org/info/rfc4180) for a formal description of this format. Note that the order of the columns will be the same order as the array when serialization occurs; however, since an array, in [PHP](https://www.php.net/), is actually an ordered map, this will not be an issue as long as the order of the elements will be preserved over time. + +Several options are available to customize this serializer according to personal needs; here's the list: + +- `separator` is the field delimiter (one single-byte character only) +- `enclosure` is the field enclosure (one single-byte character only) +- `escape` is the escape character (at most one single-byte character); leaving it empty, the escape mechanism is disabled +- `memory` is the limit of data stored in memory before starting to write on a temporary file + +#### JSON Serializer Options + +This serializer, best suited as a [record](#record-options) serializer, converts an entity into a *javascript object notation* string; see [RFC 8259](https://www.rfc-editor.org/info/rfc8259) for a formal description of this format. + +Several options are available to customize this serializer according to personal needs; here's the list: + +- `depth` is the maximum depth; must be greater than *zero* +- `flags` are a series of directives to customize the behavior of the encoder; see the [official documentation](https://www.php.net/manual/en/json.constants.php) for more information + +#### NDJSON Serializer Options + +This serializer, best suited as a data serializer, converts an entity into a *newline delimited javascript object notation* string; see the [documentation](https://github.com/ndjson/ndjson-spec) for a formal description of this format. + +Since this serializer is an extension of the [JSON](#json-serializer-options) format, options of the latter are shared between the two formats. Moreover, while the specifications contemplate the newline character `\n` (optionally preceded by a carriage return `\r`) as the only line terminator, the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin offers the possibility to choose between different options; here's the list: + +- `Null Character` is the control character with the value *zero*, also known as `\0` +- `Line Feed` is the unicode character *000A*, also known as `\n` +- `Next Line` is the unicode character 0085 +- `Line Separator` is the unicode character *2028* +- `Paragraph Separator` is the unicode character *2029* +- `Carriage Return + Line Feed` are the unicode characters *000D + 000A*, also known as `\r\n` + +### Encoder Options + +In this section the encoder type that will be used when binary data have to be converted into a sequence of printable characters can be chosen and several settings can be configured. Options that appear in this section, after the type of encoder has been chosen, depend on the encoder itself; see the following sections for more information. + +Note that third-party plugins can add more encoders to those provided by default, see the [Format Signals](#format-signals) section for more information. + +#### UTF-8 Encoder Options + +This encoder ensures that a string is *UTF-8* encoded and is best suited when binary data are not involved; see [RFC 3629](https://www.rfc-editor.org/info/rfc3629) for a formal description of this format. + +Although in the vast majority of the systems the encoding will result in a NOOP (using the internal encoding), it is always possible to choose the source encoding from the configuration form. + +#### Base16 Encoder Options + +This encoder converts a string into hexadecimal representation; the conversion is done byte-wise with the high-nibble (half-byte) first; see [RFC 4648](https://www.rfc-editor.org/info/rfc4648) for a formal description of this format. + +Although very simple to use, space efficiency is only 50%, since each 4-bit value from the original data will be encoded as an 8-bit byte, doubling the length of the original string. + +#### Base64 Encoder Options + +This encoder converts a string with base 64 and is best suited when binary data are involved; see [RFC 4648](https://www.rfc-editor.org/info/rfc4648) for a formal description of this format. + + +## Signals + +The intended audience of this section are developers, who will have to develop a third-party plugin to extend the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin; see the [official documentation](https://github.com/osTicket/osTicket/blob/develop/setup/doc/signals.md) for an overview of how the signals are implemented and work on [osTicket](https://osticket.com/). + +The [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin provides several custom signals that allow third-party plugins interact with it by altering (ie add, remove or modify) various entities; although [osTicket](https://osticket.com/) uses strings as signal names, the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin implements each signal as an object available under the `Bitfinex\Data\Streamer\osTicket\Actions` namespace. Third-party plugins can use the `getName` (*static*) method of the object that provides the implementation of a signal (instead of the name directly) so that, in the rare case in which this API changes in the future, the code will not break. + +### Format Signals + +This set of signals allows a third-party plugin to alter (ie add, remove or modify) all formats of entities available. When, for example, a new [record](#record-options) or [encoder](#encoder-options) have to be added, this is the set of signals from which to choose the one to use. The names of the signals are self-explanatory and implementations can be found under the `Bitfinex\Data\Streamer\osTicket\Actions\Formats` namespace; here's the list: + +- `plugin.bitfinex.streamer.alter.formats.encoder` +- `plugin.bitfinex.streamer.alter.formats.record` +- `plugin.bitfinex.streamer.alter.formats.serializer` +- `plugin.bitfinex.streamer.alter.formats.stream` +- `plugin.bitfinex.streamer.alter.formats.tuple` + +### Option Signals + +This set of signals allows a third-party plugin to alter (ie add, remove or modify) all configuration options available. When, for example, an option label have to be updated or an option moved to another position, this is the set of signals from which to choose the one to use. The names of the signals are self-explanatory and implementations can be found under the `Bitfinex\Data\Streamer\osTicket\Actions\Options` namespace. + +To alter the configuration form as a whole, the `plugin.bitfinex.streamer.alter.options` signal can be used otherwise, to alter only a specific section, one of the following signals can be chosen: + +- `plugin.bitfinex.streamer.alter.options.tuple` +- `plugin.bitfinex.streamer.alter.options.record` +- `plugin.bitfinex.streamer.alter.options.stream` +- `plugin.bitfinex.streamer.alter.options.encoder` +- `plugin.bitfinex.streamer.alter.options.use_case` +- `plugin.bitfinex.streamer.alter.options.serializer` + +Note that this plugin introduces the use of the non-standard `#weight` attribute on the configuration options; this is basically an integer that will be used to sort all options in ascending order. If a third-party plugin needs to rearrange the options, it can play with the value of this property instead of moving the configuration array elements. + +### Use Case Signals + +This set of signals allows a third-party plugin to alter (ie add, remove or modify) all use cases available. When, for example, a new use case needs to be added or new properties have to be added to an existing one, this is the set of signals from which to choose the one to use. The names of the signals are self-explanatory and implementations can be found under the `Bitfinex\Data\Streamer\osTicket\Actions\UseCases` namespace. + +To alter the list of use cases provided by the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin, the `plugin.bitfinex.streamer.alter.use_cases` signal can be used otherwise, to alter only the properties provided by a specific use case, one of the following signals can be chosen: + +- `plugin.bitfinex.streamer.alter.use_cases.tickets_creation` + + +## Examples + +The intended audience of this section are developers, who will have to develop a third-party plugin to extend the [*bfx-ost-streamer*](https://github.com/bitfinexcom/bfx-ost-streamer) plugin. + +### Signal Examples + +In this section a series of examples on the use of signals by a third-party plugin can be found. + +#### Format Signal Examples + +In this section an example on how to add a new [stream](#stream-options) format is shown. + +```php + __('Stream Format Name'), + StreamFactory::INITIALIZER_KEY => function (...$arguments) { + return new /* a class that implements StreamInterface */($arguments); + }, + ]; + } + +} +``` + +#### Use Case Signal Examples + +In this section an example on how to add new information to the [tickets creation use case](#tickets-creation-use-cases-options) is shown. + +```php +getNumber(); + } + +} +``` + + +## Maintainers + +Current maintainers: + +- [Davide Scola](https://github.com/davide-scola) +- [Nicoletta Maia](https://github.com/nicoletta-maia) diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4dc0d99 --- /dev/null +++ b/composer.json @@ -0,0 +1,39 @@ +{ + "name": "bitfinex/bfx-ost-streamer", + "description": "Bitfinex osTicket Streamer Plugin", + "keywords": [ + "bitfinex", + "osTicket", + "streamer", + "beanstalk", + "kinesis" + ], + "type": "project", + "require": { + "php": ">=7.0", + "ext-json": "*", + "ext-filter": "*", + "ext-mbstring": "*", + "pda/pheanstalk": "^3.2" + }, + "license": "Apache-2.0", + "authors": [ + { + "name": "Davide Scola", + "email": "davide@bitfinex.com" + }, + { + "name": "Nicoletta Maia", + "email": "nicoletta@bitfinex.com" + } + ], + "minimum-stability": "stable", + "config": { + "vendor-dir": "lib" + }, + "autoload": { + "psr-4": { + "Bitfinex\\Data\\": "include" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..89144ec --- /dev/null +++ b/composer.lock @@ -0,0 +1,78 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "02f7ad2d9ae5582c5433a05536fd484a", + "packages": [ + { + "name": "pda/pheanstalk", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/pda/pheanstalk.git", + "reference": "57b6e76f1b06ca798e739a8dee92c2dac04fd170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pda/pheanstalk/zipball/57b6e76f1b06ca798e739a8dee92c2dac04fd170", + "reference": "57b6e76f1b06ca798e739a8dee92c2dac04fd170", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "psr-4": { + "Pheanstalk\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Annesley", + "email": "paul@annesley.cc", + "homepage": "http://paul.annesley.cc/", + "role": "Developer" + } + ], + "description": "PHP client for beanstalkd queue", + "homepage": "https://github.com/pda/pheanstalk", + "keywords": [ + "beanstalkd" + ], + "support": { + "issues": "https://github.com/pda/pheanstalk/issues", + "source": "https://github.com/pda/pheanstalk/tree/master" + }, + "time": "2018-09-19T12:16:28+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.0", + "ext-json": "*", + "ext-filter": "*", + "ext-mbstring": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.2.0" +} diff --git a/doc/record.gif b/doc/record.gif new file mode 100644 index 0000000..1770639 Binary files /dev/null and b/doc/record.gif differ diff --git a/doc/stream.gif b/doc/stream.gif new file mode 100644 index 0000000..5bc5500 Binary files /dev/null and b/doc/stream.gif differ diff --git a/doc/use-case.gif b/doc/use-case.gif new file mode 100644 index 0000000..cd6c710 Binary files /dev/null and b/doc/use-case.gif differ diff --git a/include/AbstractFactory.php b/include/AbstractFactory.php new file mode 100644 index 0000000..6f50e20 --- /dev/null +++ b/include/AbstractFactory.php @@ -0,0 +1,120 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data; + +/** + * The abstract factory. + */ +abstract class AbstractFactory { + + /** + * An action manager. + * + * @var null|ActionInterface + */ + protected $action; + + /** + * The description key in the mapping array. + * + * @var string + */ + const DESCRIPTION_KEY = 'description'; + + /** + * The initializer key in the mapping array. + * + * @var string + */ + const INITIALIZER_KEY = 'initializer'; + + /** + * Construct a factory. + * + * @param ActionInterface $action + * The action manager. + * + * @return self + */ + public function __construct(ActionInterface $action = NULL) { + $this->{'action'} = $action; + } + + /** + * Create an entity. + * + * @param string $format + * The entity format. + * @param mixed ...$arguments + * A list of arguments suitable for the entity constructor. + * + * @return mixed + * A new instance of the entity. Implementers are encouraged to use + * covariance to constrain the return type in concrete classes. + */ + public function create(string $format, ...$arguments) { + $mapping = $this->mapping(); + + if (\array_key_exists($format, $mapping) === FALSE) { + throw new \InvalidArgumentException('Not supported format'); + } + + return \call_user_func_array($mapping[$format][static::INITIALIZER_KEY], $arguments); + } + + /** + * Get all supported formats. + * + * @return string[] + * All supported formats. + */ + public function formats() : array { + return \array_map(function ($format) { + return $format[static::DESCRIPTION_KEY] ?: 'unknown'; + }, $this->mapping()); + } + + /** + * Get all entities mapping. + * + * @return array[] + * All entities mapping. + */ + protected function mapping() : array { + $mapping = $this->options(); + + if ($this->{'action'} instanceof ActionInterface) { + $this->{'action'}->trigger($mapping); + } + + return $mapping; + } + + /** + * Get default options. + * + * @return array[] + * Default options. + */ + abstract protected function options() : array; + +} diff --git a/include/ActionInterface.php b/include/ActionInterface.php new file mode 100644 index 0000000..b697cff --- /dev/null +++ b/include/ActionInterface.php @@ -0,0 +1,49 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data; + +/** + * The action interface. + */ +interface ActionInterface { + + /** + * Get the action name. + * + * @return string + * The action name. + */ + public static function getName() : string; + + /** + * Trigger the action. + * + * @param mixed $data + * The variable that will be passed to listeners by reference. + * @param mixed $context + * An additional variable that is passed by reference. + * + * @return void + */ + public function trigger(&$data, &$context = NULL); + +} diff --git a/include/Encoder/Base64Encoder.php b/include/Encoder/Base64Encoder.php new file mode 100644 index 0000000..3f4245d --- /dev/null +++ b/include/Encoder/Base64Encoder.php @@ -0,0 +1,50 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Encoder; + +/** + * The base64 string encoder. + */ +class Base64Encoder implements EncoderInterface { + + /** + * The base64 encoder format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_base64'; + + /** + * {@inheritDoc} + */ + public function encode(string $payload) { + return \base64_encode($payload); + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Encoder/EncoderFactory.php b/include/Encoder/EncoderFactory.php new file mode 100644 index 0000000..2915068 --- /dev/null +++ b/include/Encoder/EncoderFactory.php @@ -0,0 +1,67 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Encoder; + +use Bitfinex\Data\AbstractFactory; + +/** + * The encoder factory. + */ +class EncoderFactory extends AbstractFactory { + + /** + * {@inheritDoc} + * + * @return EncoderInterface + * A new instance of the encoder. + */ + public function create(string $format, ...$arguments) : EncoderInterface { + return parent::create($format, ...$arguments); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + return [ + Utf8Encoder::getFormatName() => [ + static::DESCRIPTION_KEY => 'UTF-8', + static::INITIALIZER_KEY => function (...$arguments) { + return new Utf8Encoder(...$arguments); + }, + ], + HexEncoder::getFormatName() => [ + static::DESCRIPTION_KEY => 'Base16', + static::INITIALIZER_KEY => function (...$arguments) { + return new HexEncoder(); + }, + ], + Base64Encoder::getFormatName() => [ + static::DESCRIPTION_KEY => 'Base64', + static::INITIALIZER_KEY => function (...$arguments) { + return new Base64Encoder(); + }, + ], + ]; + } + +} diff --git a/include/Encoder/EncoderInterface.php b/include/Encoder/EncoderInterface.php new file mode 100644 index 0000000..e9e6fec --- /dev/null +++ b/include/Encoder/EncoderInterface.php @@ -0,0 +1,55 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Encoder; + +/** + * The encoder interface. + */ +interface EncoderInterface { + + /** + * The encoder format group name. + * + * @var string + */ + const FORMAT_GROUP = 'enc'; + + /** + * Encode a payload. + * + * @param string $payload + * The payload to encode. + * + * @return bool|string + * The encoded representation of the given payload, FALSE otherwise. + */ + public function encode(string $payload); + + /** + * Get the format name of the encoder. + * + * @return string + * The format name of the encoder. + */ + public static function getFormatName() : string; + +} diff --git a/include/Encoder/HexEncoder.php b/include/Encoder/HexEncoder.php new file mode 100644 index 0000000..e704fd7 --- /dev/null +++ b/include/Encoder/HexEncoder.php @@ -0,0 +1,50 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Encoder; + +/** + * The hexadecimal string encoder. + */ +class HexEncoder implements EncoderInterface { + + /** + * The hex encoder format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_hex'; + + /** + * {@inheritDoc} + */ + public function encode(string $payload) { + return \bin2hex($payload); + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Encoder/Utf8Encoder.php b/include/Encoder/Utf8Encoder.php new file mode 100644 index 0000000..c6761d4 --- /dev/null +++ b/include/Encoder/Utf8Encoder.php @@ -0,0 +1,78 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Encoder; + +use Bitfinex\Data\Validator\Strings\NotBlankValidator; + +/** + * The UTF-8 string encoder. + */ +class Utf8Encoder implements EncoderInterface { + + /** + * The source encoding. + * + * If not specified, the internal encoding will be used. + * + * @var string + */ + protected $encoding; + + /** + * The utf8 encoder format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_utf8'; + + /** + * Construct a UTF-8 string encoder. + * + * @param string $encoding + * The source encoding. + * + * @return self + */ + public function __construct(string $encoding = NULL) { + if (NotBlankValidator::isValid($encoding) && \in_array($encoding, \mb_list_encodings())) { + $this->{'encoding'} = $encoding; + } + else { + $this->{'encoding'} = \mb_internal_encoding(); + } + } + + /** + * {@inheritDoc} + */ + public function encode(string $payload) { + return \mb_convert_encoding($payload, 'UTF-8', $this->{'encoding'}); + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Record/KinesisRecord.php b/include/Record/KinesisRecord.php new file mode 100644 index 0000000..59ce795 --- /dev/null +++ b/include/Record/KinesisRecord.php @@ -0,0 +1,162 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Record; + +use Bitfinex\Data\Encoder\Utf8Encoder; +use Bitfinex\Data\Tuple\TupleInterface; +use Bitfinex\Data\Encoder\EncoderFactory; +use Bitfinex\Data\Encoder\EncoderInterface; +use Bitfinex\Data\Serializer\JsonSerializer; +use Bitfinex\Data\Serializer\SerializerFactory; +use Bitfinex\Data\Serializer\SerializerInterface; +use Bitfinex\Data\Validator\Strings\KinesisStreamValidator; + +/** + * The Kinesis record. + * + * This implementation is suitable for small Kinesis streams that do not + * use multiple shards. + */ +class KinesisRecord implements RecordInterface { + + /** + * The internal representation of a Kinesis record. + * + * @var array + */ + protected $record; + + /** + * The encoder used to encode the data blob. + * + * @var EncoderInterface + */ + protected $encoder; + + /** + * The serializer used to serialize the record itself. + * + * @var SerializerInterface + */ + protected $serializer; + + /** + * The Kinesis record format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_kinesis'; + + /** + * Construct a Kinesis record. + * + * @param string $stream + * The name of the stream to put the data record into. + * @param EncoderInterface $encoder + * The Kinesis record encoder (default: UTF-8). + * @param SerializerInterface $serializer + * The Kinesis record serializer (default: JSON). + * + * @return self + */ + public function __construct( + string $stream, + EncoderInterface $encoder = NULL, + SerializerInterface $serializer = NULL + ) { + if (KinesisStreamValidator::isNotValid($stream)) { + throw new \InvalidArgumentException(); + } + + $this->{'record'} = [ + 'Data' => NULL, + 'StreamName' => $stream, + 'PartitionKey' => \str_replace(__NAMESPACE__, '', __CLASS__), + ]; + + if ($encoder instanceof EncoderInterface) { + $this->{'encoder'} = $encoder; + } + else { + $this->{'encoder'} = (new EncoderFactory())->create(Utf8Encoder::getFormatName()); + } + + if ($serializer instanceof SerializerInterface) { + $this->{'serializer'} = $serializer; + } + else { + $this->{'serializer'} = (new SerializerFactory())->create(JsonSerializer::getFormatName()); + } + } + + /** + * {@inheritDoc} + */ + public function getSerializer() : SerializerInterface { + return $this->{'serializer'}; + } + + /** + * {@inheritDoc} + */ + public function setSerializer(SerializerInterface $serializer) { + $this->{'serializer'} = $serializer; + } + + /** + * {@inheritDoc} + */ + public function update(TupleInterface $collection) : RecordInterface { + if (($payload = $this->{'encoder'}->encode($collection->serialize())) === FALSE) { + throw new \UnexpectedValueException(); + } + + $this->{'record'}['Data'] = $payload; + return $this; + } + + /** + * {@inheritDoc} + */ + public function serialize() : string { + if (($payload = $this->{'serializer'}->serialize($this->{'record'})) === FALSE) { + throw new \UnexpectedValueException(); + } + + return $payload; + } + + /** + * {@inheritDoc} + */ + public function unserialize($serialized) { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Record/RecordFactory.php b/include/Record/RecordFactory.php new file mode 100644 index 0000000..fd21973 --- /dev/null +++ b/include/Record/RecordFactory.php @@ -0,0 +1,55 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Record; + +use Bitfinex\Data\AbstractFactory; + +/** + * The record factory. + */ +class RecordFactory extends AbstractFactory { + + /** + * {@inheritDoc} + * + * @return RecordInterface + * A new instance of the record. + */ + public function create(string $format, ...$arguments) : RecordInterface { + return parent::create($format, ...$arguments); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + return [ + KinesisRecord::getFormatName() => [ + static::DESCRIPTION_KEY => 'Amazon Kinesis', + static::INITIALIZER_KEY => function (...$arguments) { + return new KinesisRecord(...$arguments); + }, + ], + ]; + } + +} diff --git a/include/Record/RecordInterface.php b/include/Record/RecordInterface.php new file mode 100644 index 0000000..df07f62 --- /dev/null +++ b/include/Record/RecordInterface.php @@ -0,0 +1,76 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Record; + +use Bitfinex\Data\Tuple\TupleInterface; +use Bitfinex\Data\Serializer\SerializerInterface; + +/** + * The record interface. + */ +interface RecordInterface extends \Serializable { + + /** + * The record format group name. + * + * @var string + */ + const FORMAT_GROUP = 'rec'; + + /** + * Get the record serializer. + * + * @return SerializerInterface + * The current record serializer. + */ + public function getSerializer() : SerializerInterface; + + /** + * Set the record serializer. + * + * @param SerializerInterface $serializer + * The serializer to use. + * + * @return void + */ + public function setSerializer(SerializerInterface $serializer); + + /** + * Update the record collection. + * + * @param TupleInterface $collection + * The record collection. + * + * @return RecordInterface + * The instance of the current object. + */ + public function update(TupleInterface $collection) : RecordInterface; + + /** + * Get the format name of the record. + * + * @return string + * The format name of the record. + */ + public static function getFormatName() : string; + +} diff --git a/include/Serializer/CsvSerializer.php b/include/Serializer/CsvSerializer.php new file mode 100644 index 0000000..05dfbe5 --- /dev/null +++ b/include/Serializer/CsvSerializer.php @@ -0,0 +1,148 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Serializer; + +use Bitfinex\Data\Validator\Strings\NotEmptyValidator; +use Bitfinex\Data\Validator\Strings\NotBlankValidator; +use Bitfinex\Data\Validator\Numbers\NonNegativeIntegerValidator; + +/** + * The CSV collection serializer. + */ +class CsvSerializer implements SerializerInterface { + + /** + * The maximum size of the CSV in memory (in bytes). + * + * @var int + */ + protected $memory; + + /** + * The escape character (at most one single-byte character). + * + * An empty string disables the proprietary escape mechanism. + * + * @var string + */ + protected $escape; + + /** + * The field delimiter (one single-byte character only). + * + * @var string + */ + protected $separator; + + /** + * The field enclosure (one single-byte character only). + * + * @var string + */ + protected $enclosure; + + /** + * Default escape character. + * + * @var string + */ + const DEFAULT_ESCAPE = '\\'; + + /** + * Default field delimiter. + * + * @var string + */ + const DEFAULT_SEPARATOR = ','; + + /** + * Default field enclosure. + * + * @var string + */ + const DEFAULT_ENCLOSURE = '"'; + + /** + * Default maximum memory, in bytes. + * + * @var int + */ + const DEFAULT_MEMORY = (2 * 1024 * 1024); + + /** + * The CSV serializer format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_csv'; + + /** + * Construct a CSV collection serializer. + * + * @param string $separator + * The field delimiter (one single-byte character only). + * @param string $enclosure + * The field enclosure (one single-byte character only). + * @param string $escape + * The escape character (at most one single-byte character). + * @param int $memory + * The maximum size of the CSV row in memory. + * + * @return self + */ + public function __construct( + string $separator = self::DEFAULT_SEPARATOR, + string $enclosure = self::DEFAULT_ENCLOSURE, + string $escape = self::DEFAULT_ESCAPE, + int $memory = self::DEFAULT_MEMORY + ) { + $this->{'escape'} = NotBlankValidator::isValid($escape) ? \trim($escape)[0] : ''; + $this->{'separator'} = NotEmptyValidator::isValid($separator) ? $separator[0] : static::DEFAULT_SEPARATOR; + $this->{'memory'} = NonNegativeIntegerValidator::isValid($memory) ? \intval($memory) : static::DEFAULT_MEMORY; + $this->{'enclosure'} = NotBlankValidator::isValid($enclosure) ? \trim($enclosure)[0] : static::DEFAULT_ENCLOSURE; + } + + /** + * {@inheritDoc} + */ + public function serialize(array $collection) { + $csv = FALSE; + + if (($fptr = \fopen(\sprintf('php://temp/maxmemory:%u', $this->{'memory'}), 'w+')) !== FALSE) { + if (\fputcsv($fptr, $collection, $this->{'separator'}, $this->{'enclosure'}, $this->{'escape'}) !== FALSE) { + $csv = \stream_get_contents($fptr, -1, 0); + } + + \fclose($fptr); + } + + return $csv; + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Serializer/JsonSerializer.php b/include/Serializer/JsonSerializer.php new file mode 100644 index 0000000..9aa258c --- /dev/null +++ b/include/Serializer/JsonSerializer.php @@ -0,0 +1,99 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Serializer; + +use Bitfinex\Data\Validator\Numbers\PositiveIntegerValidator; +use Bitfinex\Data\Validator\Numbers\NonNegativeIntegerValidator; + +/** + * The JSON collection serializer. + */ +class JsonSerializer implements SerializerInterface { + + /** + * Bitmask consisting of constants described on the JSON constants page. + * + * @var int + */ + protected $flags; + + /** + * The maximum depth. Must be greater than zero. + * + * @var int + */ + protected $depth; + + /** + * Default maximum depth. + * + * @var int + */ + const DEFAULT_DEPTH = 16; + + /** + * The JSON serializer format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_json'; + + /** + * Default bitmask. + * + * @var int + */ + const DEFAULT_FLAGS = \JSON_FORCE_OBJECT | \JSON_NUMERIC_CHECK | \JSON_UNESCAPED_UNICODE | \JSON_PRESERVE_ZERO_FRACTION; + + /** + * Construct a JSON collection serializer. + * + * @param int $flags + * Bitmask consisting of constants described on the JSON constants page. + * @param int $depth + * The maximum depth. Must be greater than zero. + * + * @return self + */ + public function __construct( + int $flags = self::DEFAULT_FLAGS, + int $depth = self::DEFAULT_DEPTH + ) { + $this->{'depth'} = PositiveIntegerValidator::isValid($depth) ? \intval($depth) : static::DEFAULT_DEPTH; + $this->{'flags'} = NonNegativeIntegerValidator::isValid($flags) ? \intval($flags) : static::DEFAULT_FLAGS; + } + + /** + * {@inheritDoc} + */ + public function serialize(array $collection) { + return \json_encode($collection, $this->{'flags'}, $this->{'depth'}); + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Serializer/LineDelimitedJsonSerializer.php b/include/Serializer/LineDelimitedJsonSerializer.php new file mode 100644 index 0000000..e092868 --- /dev/null +++ b/include/Serializer/LineDelimitedJsonSerializer.php @@ -0,0 +1,92 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Serializer; + +use Bitfinex\Data\Validator\Strings\NotEmptyValidator; + +/** + * The NDJSON collection serializer. + */ +class LineDelimitedJsonSerializer extends JsonSerializer { + + /** + * The boundary between lines. + * + * @var string + */ + protected $delimiter; + + /** + * Default boundary between lines. + * + * @var string + */ + const DEFAULT_DELIMITER = \PHP_EOL; + + /** + * The NDJSON serializer format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_ndjson'; + + /** + * Construct a line-delimited JSON collection serializer. + * + * @param string $delimiter + * A sequence of one or more characters for specifying the boundary between + * lines. + * @param int $flags + * Bitmask consisting of constants described on the JSON constants page. + * @param int $depth + * The maximum depth. Must be greater than zero. + * + * @return self + */ + public function __construct( + string $delimiter = self::DEFAULT_DELIMITER, + int $flags = self::DEFAULT_FLAGS, + int $depth = self::DEFAULT_DEPTH + ) { + parent::__construct($flags, $depth); + $this->{'delimiter'} = NotEmptyValidator::isValid($delimiter) ? $delimiter : static::DEFAULT_DELIMITER; + } + + /** + * {@inheritDoc} + */ + public function serialize(array $collection) { + if (($ndjson = parent::serialize($collection)) !== FALSE) { + $ndjson .= $this->{'delimiter'}; + } + + return $ndjson; + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Serializer/SerializerFactory.php b/include/Serializer/SerializerFactory.php new file mode 100644 index 0000000..51eaafe --- /dev/null +++ b/include/Serializer/SerializerFactory.php @@ -0,0 +1,67 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Serializer; + +use Bitfinex\Data\AbstractFactory; + +/** + * The serializer factory. + */ +class SerializerFactory extends AbstractFactory { + + /** + * {@inheritDoc} + * + * @return SerializerInterface + * A new instance of the serializer. + */ + public function create(string $format, ...$arguments) : SerializerInterface { + return parent::create($format, ...$arguments); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + return [ + CsvSerializer::getFormatName() => [ + static::DESCRIPTION_KEY => 'CSV', + static::INITIALIZER_KEY => function (...$arguments) { + return new CsvSerializer(...$arguments); + }, + ], + JsonSerializer::getFormatName() => [ + static::DESCRIPTION_KEY => 'JSON', + static::INITIALIZER_KEY => function (...$arguments) { + return new JsonSerializer(...$arguments); + }, + ], + LineDelimitedJsonSerializer::getFormatName() => [ + static::DESCRIPTION_KEY => 'NDJSON', + static::INITIALIZER_KEY => function (...$arguments) { + return new LineDelimitedJsonSerializer(...$arguments); + }, + ], + ]; + } + +} diff --git a/include/Serializer/SerializerInterface.php b/include/Serializer/SerializerInterface.php new file mode 100644 index 0000000..7017e10 --- /dev/null +++ b/include/Serializer/SerializerInterface.php @@ -0,0 +1,55 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Serializer; + +/** + * The serializer interface. + */ +interface SerializerInterface { + + /** + * The serializer format group name. + * + * @var string + */ + const FORMAT_GROUP = 'srz'; + + /** + * Serialize a collection. + * + * @param array $collection + * The collection to serialize. + * + * @return bool|string + * The serialized representation of the given collection, FALSE otherwise. + */ + public function serialize(array $collection); + + /** + * Get the format name of the serializer. + * + * @return string + * The format name of the serializer. + */ + public static function getFormatName() : string; + +} diff --git a/include/Stream/BeanstalkStream.php b/include/Stream/BeanstalkStream.php new file mode 100644 index 0000000..181c7e0 --- /dev/null +++ b/include/Stream/BeanstalkStream.php @@ -0,0 +1,181 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Stream; + +use Pheanstalk\Pheanstalk; +use Pheanstalk\PheanstalkInterface; +use Bitfinex\Data\Record\RecordInterface; +use Bitfinex\Data\Validator\Strings\HostnameValidator; +use Bitfinex\Data\Validator\Strings\BeanstalkTubeValidator; +use Bitfinex\Data\Validator\Numbers\PositiveWordValidator; +use Bitfinex\Data\Validator\Numbers\PositiveDoubleWordValidator; +use Bitfinex\Data\Validator\Numbers\NonNegativeDoubleWordValidator; + +/** + * The beanstalk stream. + */ +class BeanstalkStream implements StreamInterface { + + /** + * The beanstalk TTR (in seconds). + * + * @var int + */ + protected $ttr; + + /** + * The beanstalk stream. + * + * @var Pheanstalk + */ + protected $stream; + + /** + * The beanstalk delay (in seconds). + * + * @var int + */ + protected $delay; + + /** + * The beanstalk priority. + * + * @var int + */ + protected $priority; + + /** + * Default beanstalk hostname. + * + * @var string + */ + const DEFAULT_HOST = '127.0.0.1'; + + /** + * Default beanstalk TTR. + * + * @var int + */ + const DEFAULT_TTR = PheanstalkInterface::DEFAULT_TTR; + + /** + * The beanstalk stream format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_beanstalk'; + + /** + * Default beanstalk port number. + * + * @var int + */ + const DEFAULT_PORT = PheanstalkInterface::DEFAULT_PORT; + + /** + * Default beanstalk tube name. + * + * @var string + */ + const DEFAULT_TUBE = PheanstalkInterface::DEFAULT_TUBE; + + /** + * Default beanstalk delay. + * + * @var int + */ + const DEFAULT_DELAY = PheanstalkInterface::DEFAULT_DELAY; + + /** + * Default beanstalkd priority. + * + * @var int + */ + const DEFAULT_PRIORITY = PheanstalkInterface::DEFAULT_PRIORITY; + + /** + * Construct a beanstalk stream. + * + * @param string $host + * The hostname of the beanstalk instance. + * @param int $port + * The port on which the beanstalk instance is listening to. + * @param int $priority + * The job priority, smaller values most favorable. + * @param int $delay + * The number of seconds to wait before starting a job. + * @param int $ttr + * The number of seconds to allow a worker to run a job. + * + * @return self + */ + public function __construct( + string $host = self::DEFAULT_HOST, + int $port = self::DEFAULT_PORT, + int $priority = self::DEFAULT_PRIORITY, + int $delay = self::DEFAULT_DELAY, + int $ttr = self::DEFAULT_TTR + ) { + $host = HostnameValidator::isValid($host) ? $host : static::DEFAULT_HOST; + $port = PositiveWordValidator::isValid($port) ? \intval($port) : static::DEFAULT_PORT; + + $this->{'stream'} = new Pheanstalk($host, $port); + $this->{'ttr'} = PositiveDoubleWordValidator::isValid($ttr) ? \intval($ttr) : static::DEFAULT_TTR; + $this->{'delay'} = NonNegativeDoubleWordValidator::isValid($delay) ? \intval($delay) : static::DEFAULT_DELAY; + $this->{'priority'} = NonNegativeDoubleWordValidator::isValid($priority) ? \intval($priority) : static::DEFAULT_PRIORITY; + } + + /** + * {@inheritDoc} + */ + public function append(RecordInterface $record, string $queue = NULL) : bool { + try { + if ($queue === NULL) { + $queue = static::DEFAULT_TUBE; + } + elseif (BeanstalkTubeValidator::isNotValid($queue)) { + throw new \InvalidArgumentException(); + } + + return \is_int($this->{'stream'} + ->useTube($queue) + ->put( + $record->serialize(), + $this->{'priority'}, + $this->{'delay'}, + $this->{'ttr'} + ) + ); + } + catch (\Exception $ex) { + throw new \RuntimeException($ex->getMessage(), $ex->getCode(), $ex); + } + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Stream/StreamFactory.php b/include/Stream/StreamFactory.php new file mode 100644 index 0000000..f0e5ca8 --- /dev/null +++ b/include/Stream/StreamFactory.php @@ -0,0 +1,55 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Stream; + +use Bitfinex\Data\AbstractFactory; + +/** + * The stream factory. + */ +class StreamFactory extends AbstractFactory { + + /** + * {@inheritDoc} + * + * @return StreamInterface + * A new instance of the stream. + */ + public function create(string $format, ...$arguments) : StreamInterface { + return parent::create($format, ...$arguments); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + return [ + BeanstalkStream::getFormatName() => [ + static::DESCRIPTION_KEY => 'Beanstalk', + static::INITIALIZER_KEY => function (...$arguments) { + return new BeanstalkStream(...$arguments); + }, + ], + ]; + } + +} diff --git a/include/Stream/StreamInterface.php b/include/Stream/StreamInterface.php new file mode 100644 index 0000000..ffda411 --- /dev/null +++ b/include/Stream/StreamInterface.php @@ -0,0 +1,59 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Stream; + +use Bitfinex\Data\Record\RecordInterface; + +/** + * The stream interface. + */ +interface StreamInterface { + + /** + * The stream format group name. + * + * @var string + */ + const FORMAT_GROUP = 'stm'; + + /** + * Append a record to the stream. + * + * @param RecordInterface $record + * The record to append to the stream. + * @param string $queue + * The queue name where to append the record to. + * + * @return bool + * TRUE if the record has been appended, FALSE otherwise. + */ + public function append(RecordInterface $record, string $queue = NULL) : bool; + + /** + * Get the format name of the stream. + * + * @return string + * The format name of the stream. + */ + public static function getFormatName() : string; + +} diff --git a/include/Streamer/osTicket/Actions/AbstractSignal.php b/include/Streamer/osTicket/Actions/AbstractSignal.php new file mode 100644 index 0000000..3323357 --- /dev/null +++ b/include/Streamer/osTicket/Actions/AbstractSignal.php @@ -0,0 +1,65 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions; + +use Bitfinex\Data\ActionInterface; + +/** + * An osTicket signal. + */ +abstract class AbstractSignal implements ActionInterface { + + /** + * Name separator. + * + * @var string + */ + const NAME_SEPARATOR = '.'; + + /** + * Construct an osTicket signal. + * + * @return self + */ + public function __construct() { + if (\class_exists('\Signal') === FALSE) { + throw new \DomainException(); + } + } + + /** + * {@inheritDoc} + */ + public static function getName() : string { + return \implode(static::NAME_SEPARATOR, [ + 'plugin', + 'bitfinex', + 'streamer', + ]); + } + + /** + * {@inheritDoc} + */ + abstract public function trigger(&$data, &$context = NULL); + +} diff --git a/include/Streamer/osTicket/Actions/AlterSignal.php b/include/Streamer/osTicket/Actions/AlterSignal.php new file mode 100644 index 0000000..3633e96 --- /dev/null +++ b/include/Streamer/osTicket/Actions/AlterSignal.php @@ -0,0 +1,47 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions; + +/** + * An osTicket alter signal. + */ +abstract class AlterSignal extends AbstractSignal { + + /** + * {@inheritDoc} + */ + public static function getName() : string { + return parent::getName() . static::NAME_SEPARATOR . 'alter'; + } + + /** + * {@inheritDoc} + */ + public function trigger(&$data, &$context = NULL) { + \call_user_func_array(['\Signal', 'send'], [ + static::getName(), + $context, + &$data, + ]); + } + +} diff --git a/include/Streamer/osTicket/Actions/Formats/AbstractFormatsAlterSignal.php b/include/Streamer/osTicket/Actions/Formats/AbstractFormatsAlterSignal.php new file mode 100644 index 0000000..4fb97b9 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Formats/AbstractFormatsAlterSignal.php @@ -0,0 +1,47 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Formats; + +use Bitfinex\Data\Streamer\osTicket\Actions\AlterSignal; + +/** + * The osTicket abstract formats alter signal. + */ +abstract class AbstractFormatsAlterSignal extends AlterSignal { + + /** + * {@inheritDoc} + */ + public static function getName() : string { + return parent::getName() . static::NAME_SEPARATOR . + 'formats' . static::NAME_SEPARATOR . static::getContext(); + } + + /** + * Get the format name. + * + * @return string + * The format name. + */ + abstract protected static function getContext() : string; + +} diff --git a/include/Streamer/osTicket/Actions/Formats/EncoderFormatsAlterSignal.php b/include/Streamer/osTicket/Actions/Formats/EncoderFormatsAlterSignal.php new file mode 100644 index 0000000..23e6f21 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Formats/EncoderFormatsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Formats; + +/** + * The osTicket encoder formats alter signal. + */ +class EncoderFormatsAlterSignal extends AbstractFormatsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'encoder'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Formats/RecordFormatsAlterSignal.php b/include/Streamer/osTicket/Actions/Formats/RecordFormatsAlterSignal.php new file mode 100644 index 0000000..973ed8f --- /dev/null +++ b/include/Streamer/osTicket/Actions/Formats/RecordFormatsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Formats; + +/** + * The osTicket record formats alter signal. + */ +class RecordFormatsAlterSignal extends AbstractFormatsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'record'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Formats/SerializerFormatsAlterSignal.php b/include/Streamer/osTicket/Actions/Formats/SerializerFormatsAlterSignal.php new file mode 100644 index 0000000..dc98b05 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Formats/SerializerFormatsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Formats; + +/** + * The osTicket serializer formats alter signal. + */ +class SerializerFormatsAlterSignal extends AbstractFormatsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'serializer'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Formats/StreamFormatsAlterSignal.php b/include/Streamer/osTicket/Actions/Formats/StreamFormatsAlterSignal.php new file mode 100644 index 0000000..5ce947a --- /dev/null +++ b/include/Streamer/osTicket/Actions/Formats/StreamFormatsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Formats; + +/** + * The osTicket stream formats alter signal. + */ +class StreamFormatsAlterSignal extends AbstractFormatsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'stream'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Formats/TupleFormatsAlterSignal.php b/include/Streamer/osTicket/Actions/Formats/TupleFormatsAlterSignal.php new file mode 100644 index 0000000..02f4e05 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Formats/TupleFormatsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Formats; + +/** + * The osTicket tuple formats alter signal. + */ +class TupleFormatsAlterSignal extends AbstractFormatsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'tuple'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Options/AbstractOptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/AbstractOptionsAlterSignal.php new file mode 100644 index 0000000..0c0b5cf --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/AbstractOptionsAlterSignal.php @@ -0,0 +1,44 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +/** + * The osTicket abstract options alter signal. + */ +abstract class AbstractOptionsAlterSignal extends OptionsAlterSignal { + + /** + * {@inheritDoc} + */ + public static function getName() : string { + return parent::getName() . static::NAME_SEPARATOR . static::getContext(); + } + + /** + * Get the options section name. + * + * @return string + * The options section name. + */ + abstract protected static function getContext() : string; + +} diff --git a/include/Streamer/osTicket/Actions/Options/EncoderOptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/EncoderOptionsAlterSignal.php new file mode 100644 index 0000000..68c02b6 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/EncoderOptionsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +/** + * The osTicket encoder options alter signal. + */ +class EncoderOptionsAlterSignal extends AbstractOptionsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'encoder'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Options/OptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/OptionsAlterSignal.php new file mode 100644 index 0000000..9b454e7 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/OptionsAlterSignal.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +use Bitfinex\Data\Streamer\osTicket\Actions\AlterSignal; + +/** + * The osTicket options alter signal. + */ +class OptionsAlterSignal extends AlterSignal { + + /** + * {@inheritDoc} + */ + public static function getName() : string { + return parent::getName() . static::NAME_SEPARATOR . 'options'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Options/RecordOptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/RecordOptionsAlterSignal.php new file mode 100644 index 0000000..6084e2f --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/RecordOptionsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +/** + * The osTicket record options alter signal. + */ +class RecordOptionsAlterSignal extends AbstractOptionsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'record'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Options/SerializerOptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/SerializerOptionsAlterSignal.php new file mode 100644 index 0000000..d7ce405 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/SerializerOptionsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +/** + * The osTicket serializer options alter signal. + */ +class SerializerOptionsAlterSignal extends AbstractOptionsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'serializer'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Options/StreamOptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/StreamOptionsAlterSignal.php new file mode 100644 index 0000000..1031b92 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/StreamOptionsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +/** + * The osTicket stream options alter signal. + */ +class StreamOptionsAlterSignal extends AbstractOptionsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'stream'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Options/TupleOptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/TupleOptionsAlterSignal.php new file mode 100644 index 0000000..7e21efd --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/TupleOptionsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +/** + * The osTicket tuple options alter signal. + */ +class TupleOptionsAlterSignal extends AbstractOptionsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'tuple'; + } + +} diff --git a/include/Streamer/osTicket/Actions/Options/UseCaseOptionsAlterSignal.php b/include/Streamer/osTicket/Actions/Options/UseCaseOptionsAlterSignal.php new file mode 100644 index 0000000..56cb264 --- /dev/null +++ b/include/Streamer/osTicket/Actions/Options/UseCaseOptionsAlterSignal.php @@ -0,0 +1,36 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\Options; + +/** + * The osTicket use case options alter signal. + */ +class UseCaseOptionsAlterSignal extends AbstractOptionsAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return 'use_case'; + } + +} diff --git a/include/Streamer/osTicket/Actions/UseCases/AbstractUseCasesAlterSignal.php b/include/Streamer/osTicket/Actions/UseCases/AbstractUseCasesAlterSignal.php new file mode 100644 index 0000000..afbbd1c --- /dev/null +++ b/include/Streamer/osTicket/Actions/UseCases/AbstractUseCasesAlterSignal.php @@ -0,0 +1,44 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\UseCases; + +/** + * The osTicket abstract use cases alter signal. + */ +abstract class AbstractUseCasesAlterSignal extends UseCasesAlterSignal { + + /** + * {@inheritDoc} + */ + public static function getName() : string { + return parent::getName() . static::NAME_SEPARATOR . static::getContext(); + } + + /** + * Get the use case machine name. + * + * @return string + * The use case machine name. + */ + abstract protected static function getContext() : string; + +} diff --git a/include/Streamer/osTicket/Actions/UseCases/TicketsCreationUseCasesAlterSignal.php b/include/Streamer/osTicket/Actions/UseCases/TicketsCreationUseCasesAlterSignal.php new file mode 100644 index 0000000..6dca8bc --- /dev/null +++ b/include/Streamer/osTicket/Actions/UseCases/TicketsCreationUseCasesAlterSignal.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\UseCases; + +use Bitfinex\Data\Streamer\osTicket\UseCase\TicketsCreationUseCase; + +/** + * The osTicket tickets_creation use case alter signal. + */ +class TicketsCreationUseCasesAlterSignal extends AbstractUseCasesAlterSignal { + + /** + * {@inheritDoc} + */ + protected static function getContext() : string { + return TicketsCreationUseCase::getFormatName(); + } + +} diff --git a/include/Streamer/osTicket/Actions/UseCases/UseCasesAlterSignal.php b/include/Streamer/osTicket/Actions/UseCases/UseCasesAlterSignal.php new file mode 100644 index 0000000..1f6080b --- /dev/null +++ b/include/Streamer/osTicket/Actions/UseCases/UseCasesAlterSignal.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Actions\UseCases; + +use Bitfinex\Data\Streamer\osTicket\Actions\AlterSignal; + +/** + * The osTicket use cases alter signal. + */ +class UseCasesAlterSignal extends AlterSignal { + + /** + * {@inheritDoc} + */ + public static function getName() : string { + return parent::getName() . static::NAME_SEPARATOR . 'use_cases'; + } + +} diff --git a/include/Streamer/osTicket/Configuration/BitfinexStreamerPluginConfig.php b/include/Streamer/osTicket/Configuration/BitfinexStreamerPluginConfig.php new file mode 100644 index 0000000..736f0d9 --- /dev/null +++ b/include/Streamer/osTicket/Configuration/BitfinexStreamerPluginConfig.php @@ -0,0 +1,715 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Configuration; + +use Bitfinex\Data\Tuple\Sequence; +use Bitfinex\Data\ActionInterface; +use Bitfinex\Data\Encoder\Utf8Encoder; +use Bitfinex\Data\Record\KinesisRecord; +use Bitfinex\Data\Stream\BeanstalkStream; +use Bitfinex\Data\Serializer\CsvSerializer; +use Bitfinex\Data\Serializer\JsonSerializer; +use Bitfinex\Data\Serializer\LineDelimitedJsonSerializer; +use Bitfinex\Data\Streamer\osTicket\Factories\StreamFactory; +use Bitfinex\Data\Streamer\osTicket\Factories\RecordFactory; +use Bitfinex\Data\Streamer\osTicket\Factories\UseCaseFactory; +use Bitfinex\Data\Streamer\osTicket\Factories\EncoderFactory; +use Bitfinex\Data\Streamer\osTicket\Fields\BasicTextboxField; +use Bitfinex\Data\Streamer\osTicket\Factories\SerializerFactory; +use Bitfinex\Data\Streamer\osTicket\Fields\TertiumNonDaturField; +use Bitfinex\Data\Streamer\osTicket\Fields\JsonFlagsChoiceField; +use Bitfinex\Data\Streamer\osTicket\Fields\LineEndingChoiceField; +use Bitfinex\Data\Streamer\osTicket\Actions\Options\OptionsAlterSignal; +use Bitfinex\Data\Streamer\osTicket\Actions\Options\TupleOptionsAlterSignal; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\NotEmptyFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\NotBlankFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\HostnameFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Actions\Options\RecordOptionsAlterSignal; +use Bitfinex\Data\Streamer\osTicket\Actions\Options\StreamOptionsAlterSignal; +use Bitfinex\Data\Streamer\osTicket\Actions\Options\EncoderOptionsAlterSignal; +use Bitfinex\Data\Streamer\osTicket\Actions\Options\UseCaseOptionsAlterSignal; +use Bitfinex\Data\Streamer\osTicket\Actions\Options\SerializerOptionsAlterSignal; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\HelpdeskCodeFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\PositiveWordFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\BeanstalkTubeFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\KinesisStreamFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\PositiveIntegerFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\PositiveDoubleWordFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\NonNegativeIntegerFieldValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\Validators\NonNegativeDoubleWordFieldValidator; + +/** + * Configuration class to manage bfx-ost-streamer plugin. + */ +class BitfinexStreamerPluginConfig extends \PluginConfig implements \PluginCustomConfig { + + /** + * {@inheritDoc} + */ + public function getOptions() { + $weight = 0; + $increment = 100; + + $options = [ + 'general_options_subtitle' => new \SectionBreakField([ + 'label' => __('General Options'), + '#weight' => ($weight += $increment), + ]), + Helper::CODE => new BasicTextboxField([ + 'label' => __('Helpdesk code'), + 'hint' => __('A descriptive code for the helpdesk'), + 'default' => NULL, + 'required' => FALSE, + 'validators' => [ + [HelpdeskCodeFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'length' => HelpdeskCodeFieldValidator::length(), + 'validator-error' => __('Helpdesk code is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + '#weight' => ($weight += $increment), + ]), + 'stream_section' => new \SectionBreakField([ + 'label' => __('Stream'), + '#weight' => ($weight += $increment), + ]), + ]; + + $options += $this->getStreamOptions($weight, $increment); + + foreach ((new UseCaseFactory())->formats() as $name => $label) { + $options += [ + \sprintf('%s_subtitle', $name) => new \SectionBreakField([ + 'label' => \sprintf(__('%s use case'), $label), + '#weight' => ($weight += $increment), + ]), + ]; + + $options += $this->getUseCaseOptions($name, $weight, $increment); + } + + $this->trigger(new OptionsAlterSignal(), $options, [ + 'weight' => $weight, + 'increment' => $increment, + ]); + + \uasort($options, [$this, 'weightSort']); + return $options; + } + + /** + * {@inheritDoc} + */ + public function renderCustomConfig() { + $options = []; + $form = $this->getForm(); + include \BitfinexStreamerPlugin::PLUGIN_DIR . '/templates/configuration-form.tmpl.php'; + } + + /** + * {@inheritDoc} + */ + public function saveCustomConfig() { + $errors = []; + return $this->commitForm($errors); + } + + /** + * Get the stream options. + * + * @param int $weight + * The initial weight. + * @param int $increment + * The weight increment. + * + * @return \FormField[] + * The array of the stream options. + */ + protected function getStreamOptions(int &$weight = 0, int &$increment = 10) : array { + $options = [ + Helper::STREAM => new \ChoiceField([ + 'label' => __('Stream'), + 'hint' => __('The stream manager'), + 'default' => NULL, + 'required' => TRUE, + 'choices' => (new StreamFactory())->formats(), + 'configuration' => [ + 'multiselect' => FALSE, + 'classes' => 'custom-form-field custom-form-field--choice', + ], + '#weight' => ($weight += $increment), + ]), + Helper::STREAM_BEANSTALK_HOST => new BasicTextboxField([ + 'label' => __('Beanstalk host'), + 'hint' => __('The beanstalk host name'), + 'default' => BeanstalkStream::DEFAULT_HOST, + 'required' => TRUE, + 'validators' => [ + [HostnameFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'length' => HostnameFieldValidator::length(), + 'validator-error' => __('Beanstalk host name is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([Helper::STREAM => BeanstalkStream::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + Helper::STREAM_BEANSTALK_PORT => new BasicTextboxField([ + 'label' => __('Beanstalk port'), + 'hint' => __('The beanstalk port number'), + 'default' => BeanstalkStream::DEFAULT_PORT, + 'required' => TRUE, + 'validators' => [ + [PositiveWordFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'validator-error' => __('Beanstalk port number is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([Helper::STREAM => BeanstalkStream::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + Helper::STREAM_BEANSTALK_PRIORITY => new BasicTextboxField([ + 'label' => __('Beanstalk priority'), + 'hint' => __('The beanstalk job priority'), + 'default' => BeanstalkStream::DEFAULT_PRIORITY, + 'required' => TRUE, + 'validators' => [ + [NonNegativeDoubleWordFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'validator-error' => __('Beanstalk job priority is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([Helper::STREAM => BeanstalkStream::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + Helper::STREAM_BEANSTALK_DELAY => new BasicTextboxField([ + 'label' => __('Beanstalk delay'), + 'hint' => __('Seconds to wait before start a job'), + 'default' => BeanstalkStream::DEFAULT_DELAY, + 'required' => TRUE, + 'validators' => [ + [NonNegativeDoubleWordFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'validator-error' => __('Beanstalk job delay is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([Helper::STREAM => BeanstalkStream::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + Helper::STREAM_BEANSTALK_TTR => new BasicTextboxField([ + 'label' => __('Beanstalk time to run'), + 'hint' => __('Seconds a job can be reserved for'), + 'default' => BeanstalkStream::DEFAULT_TTR, + 'required' => TRUE, + 'validators' => [ + [PositiveDoubleWordFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'validator-error' => __('Beanstalk job TTR is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([Helper::STREAM => BeanstalkStream::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + ]; + + $this->trigger(new StreamOptionsAlterSignal(), $options, [ + 'weight' => $weight, + 'increment' => $increment, + ]); + + return $options; + } + + /** + * Get the use case options. + * + * @param string $usecase + * The use case machine name. + * @param int $weight + * The initial weight. + * @param int $increment + * The weight increment. + * + * @return \FormField[] + * The array of the use case options. + */ + protected function getUseCaseOptions(string $usecase, int &$weight = 0, int &$increment = 10) : array { + $options = [ + \sprintf(Helper::USE_CASE_ENABLED_FORMAT, $usecase) => new TertiumNonDaturField([ + 'label' => __('Enable this use case'), + 'default' => NULL, + 'required' => FALSE, + 'configuration' => [ + 'classes' => 'custom-form-field custom-form-field--boolean', + ], + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::USE_CASE_QUEUE_SUFFIX_FORMAT, \sprintf('%s_%s', $usecase, BeanstalkStream::getFormatName())) => new BasicTextboxField([ + 'label' => __('Beanstalk tube'), + 'hint' => __('The beanstalk tube name'), + 'default' => BeanstalkStream::DEFAULT_TUBE, + 'required' => TRUE, + 'validators' => [ + [BeanstalkTubeFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'length' => BeanstalkTubeFieldValidator::length(), + 'validator-error' => __('Beanstalk tube name is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + \Q::all([ + Helper::STREAM => BeanstalkStream::getFormatName(), + \sprintf(Helper::USE_CASE_ENABLED_FORMAT, $usecase) => 1, + ]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + ]; + + $options += $this->getTupleOptions($usecase, $weight, $increment); + $options += $this->getRecordOptions($usecase, $weight, $increment); + + $this->trigger(new UseCaseOptionsAlterSignal(), $options, [ + 'weight' => $weight, + 'use_case' => $usecase, + 'increment' => $increment, + ]); + + return $options; + } + + /** + * Get the tuple options. + * + * @param string $usecase + * The usecase machine name. + * @param int $weight + * The initial weight. + * @param int $increment + * The weight increment. + * + * @return \FormField[] + * The array of the tuple options. + */ + protected function getTupleOptions(string $usecase, int &$weight = 0, int &$increment = 10) : array { + $tuple_serializer = \sprintf(Helper::USE_CASE_TUPLE_SEQUENCE_SERIALIZER_FORMAT, $usecase); + + $options = [ + $tuple_serializer => new \ChoiceField([ + 'label' => __('Data serializer'), + 'hint' => __('The format of the streamed data'), + 'default' => NULL, + 'required' => TRUE, + 'choices' => (new SerializerFactory($usecase, Sequence::getFormatName()))->formats(), + 'configuration' => [ + 'multiselect' => FALSE, + 'classes' => 'custom-form-field custom-form-field--choice', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([\sprintf(Helper::USE_CASE_ENABLED_FORMAT, $usecase) => 1]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + ]; + + $options += $this->getSerializerOptions($tuple_serializer, $weight, $increment); + + $this->trigger(new TupleOptionsAlterSignal(), $options, [ + 'weight' => $weight, + 'use_case' => $usecase, + 'increment' => $increment, + ]); + + return $options; + } + + /** + * Get the record options. + * + * @param string $usecase + * The use case machine name. + * @param int $weight + * The initial weight. + * @param int $increment + * The weight increment. + * + * @return \FormField[] + * The array of the record options. + */ + protected function getRecordOptions(string $usecase, int &$weight = 0, int &$increment = 10) : array { + $record_type = \sprintf(Helper::USE_CASE_RECORD_FORMAT, $usecase); + $kinesis_encoder = \sprintf(Helper::USE_CASE_RECORD_KINESIS_ENCODER_FORMAT, $usecase); + $kinesis_serializer = \sprintf(Helper::USE_CASE_RECORD_KINESIS_SERIALIZER_FORMAT, $usecase); + + $options = [ + $record_type => new \ChoiceField([ + 'label' => __('Record type'), + 'hint' => __('The stream record type'), + 'default' => NULL, + 'required' => TRUE, + 'choices' => (new RecordFactory($usecase))->formats(), + 'configuration' => [ + 'multiselect' => FALSE, + 'classes' => 'custom-form-field custom-form-field--choice', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([\sprintf(Helper::USE_CASE_ENABLED_FORMAT, $usecase) => 1]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::USE_CASE_RECORD_KINESIS_STREAM_FORMAT, $usecase) => new BasicTextboxField([ + 'label' => __('Kinesis stream name'), + 'hint' => __('The name of the Kinesis stream'), + 'default' => NULL, + 'required' => TRUE, + 'validators' => [ + [KinesisStreamFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'length' => KinesisStreamFieldValidator::length(), + 'validator-error' => __('Kinesis stream name is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$record_type => KinesisRecord::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + $kinesis_encoder => new \ChoiceField([ + 'label' => __('Kinesis data encoder'), + 'hint' => __('Encoder used by Kinesis record'), + 'default' => NULL, + 'required' => TRUE, + 'choices' => (new EncoderFactory($usecase, KinesisRecord::getFormatName()))->formats(), + 'configuration' => [ + 'multiselect' => FALSE, + 'classes' => 'custom-form-field custom-form-field--choice', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$record_type => KinesisRecord::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + ]; + + $options += $this->getEncoderOptions($kinesis_encoder, $weight, $increment); + + $options += [ + $kinesis_serializer => new \ChoiceField([ + 'label' => __('Kinesis record serializer'), + 'hint' => __('Serializer used by Kinesis record'), + 'default' => NULL, + 'required' => TRUE, + 'choices' => (new SerializerFactory($usecase, KinesisRecord::getFormatName()))->formats(), + 'configuration' => [ + 'multiselect' => FALSE, + 'classes' => 'custom-form-field custom-form-field--choice', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$record_type => KinesisRecord::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + ]; + + $options += $this->getSerializerOptions($kinesis_serializer, $weight, $increment); + + $this->trigger(new RecordOptionsAlterSignal(), $options, [ + 'weight' => $weight, + 'use_case' => $usecase, + 'increment' => $increment, + ]); + + return $options; + } + + /** + * Get the serializer options. + * + * @param string $fid + * The id of the parent field. + * @param int $weight + * The initial weight. + * @param int $increment + * The weight increment. + * + * @return \FormField[] + * The array of the serializer options. + */ + protected function getSerializerOptions(string $fid, int &$weight = 0, int &$increment = 10) : array { + $namespace = \substr($fid, 0, \strrpos($fid, '_')); + + $options = [ + \sprintf(Helper::CSV_SEPARATOR_SUFFIX_FORMAT, $namespace) => new BasicTextboxField([ + 'label' => __('CSV separator'), + 'hint' => __('The field delimiter'), + 'default' => CsvSerializer::DEFAULT_SEPARATOR, + 'required' => TRUE, + 'validators' => [ + [NotEmptyFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'length' => 1, + 'validator-error' => __('CSV separator is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$fid => CsvSerializer::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::CSV_ENCLOSURE_SUFFIX_FORMAT, $namespace) => new BasicTextboxField([ + 'label' => __('CSV enclosure'), + 'hint' => __('The field enclosure'), + 'default' => CsvSerializer::DEFAULT_ENCLOSURE, + 'required' => TRUE, + 'validators' => [ + [NotBlankFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'length' => 1, + 'validator-error' => __('CSV enclosure is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$fid => CsvSerializer::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::CSV_ESCAPE_SUFFIX_FORMAT, $namespace) => new BasicTextboxField([ + 'label' => __('CSV escape'), + 'hint' => __('The escape character'), + 'default' => CsvSerializer::DEFAULT_ESCAPE, + 'required' => FALSE, + 'validators' => [ + [NotBlankFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'length' => 1, + 'validator-error' => __('CSV escape is not valid'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$fid => CsvSerializer::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::CSV_MEMORY_SUFFIX_FORMAT, $namespace) => new BasicTextboxField([ + 'label' => __('CSV maximum memory'), + 'hint' => __('CSV maximum memory, in bytes'), + 'default' => CsvSerializer::DEFAULT_MEMORY, + 'required' => TRUE, + 'validators' => [ + [NonNegativeIntegerFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'validator-error' => __('CSV memory must be non negative'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$fid => CsvSerializer::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::JSON_DEPTH_SUFFIX_FORMAT, $namespace) => new BasicTextboxField([ + 'label' => __('JSON depth'), + 'hint' => __('The JSON depth'), + 'default' => JsonSerializer::DEFAULT_DEPTH, + 'required' => TRUE, + 'validators' => [ + [PositiveIntegerFieldValidator::class, 'process'], + ], + 'configuration' => [ + 'validator-error' => __('JSON depth must be positive'), + 'classes' => 'custom-form-field custom-form-field--basictextbox', + ], + 'visibility' => new \VisibilityConstraint( + \Q::any([ + $fid => JsonSerializer::getFormatName(), + $fid . '__eq' => LineDelimitedJsonSerializer::getFormatName(), + ]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::JSON_FLAGS_SUFFIX_FORMAT, $namespace) => new JsonFlagsChoiceField([ + 'label' => __('JSON flags'), + 'hint' => __('JSON flags to use when serializing'), + 'default' => JsonSerializer::DEFAULT_FLAGS, + 'required' => FALSE, + 'configuration' => [ + 'classes' => 'custom-form-field custom-form-field--jsonflagschoice', + ], + 'visibility' => new \VisibilityConstraint( + \Q::any([ + $fid => JsonSerializer::getFormatName(), + $fid . '__eq' => LineDelimitedJsonSerializer::getFormatName(), + ]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + \sprintf(Helper::NDJSON_LINE_ENDING_SUFFIX_FORMAT, $namespace) => new LineEndingChoiceField([ + 'label' => __('Line ending'), + 'hint' => __('The NDJSON line ending'), + 'default' => LineDelimitedJsonSerializer::DEFAULT_DELIMITER, + 'required' => TRUE, + 'configuration' => [ + 'classes' => 'custom-form-field custom-form-field--lineendingchoice', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$fid => LineDelimitedJsonSerializer::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + ]; + + $this->trigger(new SerializerOptionsAlterSignal(), $options, [ + 'field_id' => $fid, + 'weight' => $weight, + 'increment' => $increment, + 'namespace' => $namespace, + ]); + + return $options; + } + + /** + * Get the encoder options. + * + * @param string $fid + * The id of the parent field. + * @param int $weight + * The initial weight. + * @param int $increment + * The weight increment. + * + * @return \FormField[] + * The array of the encoder options. + */ + protected function getEncoderOptions(string $fid, int &$weight = 0, int &$increment = 10) : array { + $encodings = \mb_list_encodings(); + $namespace = \substr($fid, 0, \strrpos($fid, '_')); + + $options = [ + \sprintf(Helper::UTF8_ENCODING_SUFFIX_FORMAT, $namespace) => new \ChoiceField([ + 'label' => __('UTF-8 source encoding'), + 'hint' => __('Encoding used by UTF-8 encoder'), + 'default' => NULL, + 'required' => FALSE, + 'choices' => \array_combine($encodings, $encodings), + 'configuration' => [ + 'multiselect' => FALSE, + 'classes' => 'custom-form-field custom-form-field--choice', + ], + 'visibility' => new \VisibilityConstraint( + new \Q([$fid => Utf8Encoder::getFormatName()]), + \VisibilityConstraint::VISIBLE + ), + '#weight' => ($weight += $increment), + ]), + ]; + + $this->trigger(new EncoderOptionsAlterSignal(), $options, [ + 'field_id' => $fid, + 'weight' => $weight, + 'increment' => $increment, + 'namespace' => $namespace, + ]); + + return $options; + } + + /** + * Sort fields by the weight property. + * + * @param \FormField $a + * First field for comparison. + * @param \FormField $b + * Second field for comparison. + * + * @return int + * An integer less than, equal to, or greater than zero if the first field + * is considered to be respectively less than, equal to, or greater than + * the second. + */ + protected function weightSort(\FormField $a, \FormField $b) : int { + $x = \is_array($a->ht) && isset($a->ht['#weight']) ? $a->ht['#weight'] : 0; + $y = \is_array($b->ht) && isset($b->ht['#weight']) ? $b->ht['#weight'] : 0; + + if ($x == $y) { + return 0; + } + + return $x < $y ? -1 : 1; + } + + /** + * Emit a signal. + * + * @param ActionInterface $action + * The signal to emit. + * @param mixed $data + * The variable that will be passed to listeners by reference. + * @param mixed $context + * An additional variable that describes the context. + * + * @return void + */ + protected function trigger(ActionInterface $action, &$data, $context = NULL) { + $action->trigger($data, $context); + } + +} diff --git a/include/Streamer/osTicket/Configuration/HasConfigurationManagementTrait.php b/include/Streamer/osTicket/Configuration/HasConfigurationManagementTrait.php new file mode 100644 index 0000000..249392e --- /dev/null +++ b/include/Streamer/osTicket/Configuration/HasConfigurationManagementTrait.php @@ -0,0 +1,141 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Configuration; + +use Bitfinex\Data\Streamer\osTicket\Fields\BasicTextboxField; +use Bitfinex\Data\Streamer\osTicket\Fields\TertiumNonDaturField; +use Bitfinex\Data\Streamer\osTicket\Fields\JsonFlagsChoiceField; +use Bitfinex\Data\Streamer\osTicket\Fields\LineEndingChoiceField; + +/** + * Trait of all classes that manage configuration options. + */ +trait HasConfigurationManagementTrait { + + /** + * Get configuration as a ChoiceField. + * + * @param string $name + * The configuration name. + * + * @return \ChoiceField + * The configuration as a ChoiceField. + */ + protected static function getConfigAsChoiceField(string $name) : \ChoiceField { + return static::getConfigAsFormField( + new \ChoiceField(), + $name + ); + } + + /** + * Get configuration as a BasicTextboxField. + * + * @param string $name + * The configuration name. + * + * @return BasicTextboxField + * The configuration as a BasicTextboxField. + */ + protected static function getConfigAsBasicTextboxField(string $name) : BasicTextboxField { + return static::getConfigAsFormField( + new BasicTextboxField(), + $name + ); + } + + /** + * Get configuration as a JsonFlagsChoiceField. + * + * @param string $name + * The configuration name. + * + * @return JsonFlagsChoiceField + * The configuration as a JsonFlagsChoiceField. + */ + protected static function getConfigAsJsonFlagsChoiceField(string $name) : JsonFlagsChoiceField { + return static::getConfigAsFormField( + new JsonFlagsChoiceField(), + $name + ); + } + + /** + * Get configuration as a LineEndingChoiceField. + * + * @param string $name + * The configuration name. + * + * @return LineEndingChoiceField + * The configuration as a LineEndingChoiceField. + */ + protected static function getConfigAsLineEndingChoiceField(string $name) : LineEndingChoiceField { + return static::getConfigAsFormField( + new LineEndingChoiceField(), + $name + ); + } + + /** + * Get configuration as a TertiumNonDaturField. + * + * @param string $name + * The configuration name. + * + * @return TertiumNonDaturField + * The configuration as a TertiumNonDaturField. + */ + protected static function getConfigAsTertiumNonDaturField(string $name) : TertiumNonDaturField { + return static::getConfigAsFormField( + new TertiumNonDaturField(), + $name + ); + } + + /** + * Get configuration as a FormField. + * + * @param \FormField $field + * The form field instance. + * @param string $name + * The configuration name. + * + * @return \FormField + * The configuration as a FormField. + */ + protected static function getConfigAsFormField(\FormField $field, string $name) : \FormField { + $plugin = \PluginManager::getInstance( + \sprintf('plugins/%s', \basename(\BitfinexStreamerPlugin::PLUGIN_DIR)) + ); + + if ($plugin instanceof \Plugin) { + $config = $plugin->getConfig(); + + if ($config instanceof \PluginConfig) { + $field->setValue($config->get($name)); + } + } + + return $field; + } + +} diff --git a/include/Streamer/osTicket/Configuration/Helper.php b/include/Streamer/osTicket/Configuration/Helper.php new file mode 100644 index 0000000..20e3bae --- /dev/null +++ b/include/Streamer/osTicket/Configuration/Helper.php @@ -0,0 +1,537 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Configuration; + +use Bitfinex\Data\Tuple\Sequence; +use Bitfinex\Data\Encoder\Utf8Encoder; +use Bitfinex\Data\Record\KinesisRecord; +use Bitfinex\Data\Stream\StreamInterface; +use Bitfinex\Data\Record\RecordInterface; +use Bitfinex\Data\Stream\BeanstalkStream; +use Bitfinex\Data\Encoder\EncoderInterface; +use Bitfinex\Data\Serializer\CsvSerializer; +use Bitfinex\Data\Serializer\JsonSerializer; +use Bitfinex\Data\Serializer\SerializerInterface; +use Bitfinex\Data\Serializer\LineDelimitedJsonSerializer; + +/** + * The configuration helper class. + */ +class Helper { + + use HasConfigurationManagementTrait; + + /** + * The helpdesk code option. + * + * @var string + */ + const CODE = 'code'; + + /** + * The stream manager option. + * + * @var string + */ + const STREAM = StreamInterface::FORMAT_GROUP; + + /** + * The Beanstalk host option. + * + * @var string + */ + const STREAM_BEANSTALK_HOST = BeanstalkStream::FORMAT_NAME . '_host'; + + /** + * The Beanstalk port option. + * + * @var string + */ + const STREAM_BEANSTALK_PORT = BeanstalkStream::FORMAT_NAME . '_port'; + + /** + * The Beanstalk priority option. + * + * @var string + */ + const STREAM_BEANSTALK_PRIORITY = BeanstalkStream::FORMAT_NAME . '_priority'; + + /** + * The Beanstalk delay option. + * + * @var string + */ + const STREAM_BEANSTALK_DELAY = BeanstalkStream::FORMAT_NAME . '_delay'; + + /** + * The Beanstalk time to run option. + * + * @var string + */ + const STREAM_BEANSTALK_TTR = BeanstalkStream::FORMAT_NAME . '_ttr'; + + /** + * The format of the use case "enabled" option. + * + * @var string + */ + const USE_CASE_ENABLED_FORMAT = '%s_enabled'; + + /** + * The use case option format for the tuple serializer. + * + * @var string + */ + const USE_CASE_TUPLE_SEQUENCE_SERIALIZER_FORMAT = '%s_' . Sequence::FORMAT_NAME . '_' . SerializerInterface::FORMAT_GROUP; + + /** + * The format of the use case record option. + * + * @var string + */ + const USE_CASE_RECORD_FORMAT = '%s_' . RecordInterface::FORMAT_GROUP; + + /** + * The use case option format for the Kinesis record stream. + * + * @var string + */ + const USE_CASE_RECORD_KINESIS_STREAM_FORMAT = '%s_' . KinesisRecord::FORMAT_NAME . '_stream'; + + /** + * The use case option format for the Kinesis record encoder. + * + * @var string + */ + const USE_CASE_RECORD_KINESIS_ENCODER_FORMAT = '%s_' . KinesisRecord::FORMAT_NAME . '_' . EncoderInterface::FORMAT_GROUP; + + /** + * The use case option format for the Kinesis record serializer. + * + * @var string + */ + const USE_CASE_RECORD_KINESIS_SERIALIZER_FORMAT = '%s_' . KinesisRecord::FORMAT_NAME . '_' . SerializerInterface::FORMAT_GROUP; + + /** + * The suffix format of the stream queue options. + * + * @var string + */ + const USE_CASE_QUEUE_SUFFIX_FORMAT = '%s_queue'; + + /** + * The suffix format of the UTF-8 encoding options. + * + * @var string + */ + const UTF8_ENCODING_SUFFIX_FORMAT = '%s_' . Utf8Encoder::FORMAT_NAME . '_encoding'; + + /** + * The suffix format of the CSV separator options. + * + * @var string + */ + const CSV_SEPARATOR_SUFFIX_FORMAT = '%s_' . CsvSerializer::FORMAT_NAME . '_separator'; + + /** + * The suffix format of the CSV enclosure options. + * + * @var string + */ + const CSV_ENCLOSURE_SUFFIX_FORMAT = '%s_' . CsvSerializer::FORMAT_NAME . '_enclosure'; + + /** + * The suffix format of the CSV escape options. + * + * @var string + */ + const CSV_ESCAPE_SUFFIX_FORMAT = '%s_' . CsvSerializer::FORMAT_NAME . '_escape'; + + /** + * The suffix format of the CSV maximum memory options. + * + * @var string + */ + const CSV_MEMORY_SUFFIX_FORMAT = '%s_' . CsvSerializer::FORMAT_NAME . '_memory'; + + /** + * The suffix format of the JSON depth options. + * + * @var string + */ + const JSON_DEPTH_SUFFIX_FORMAT = '%s_' . JsonSerializer::FORMAT_NAME . '_depth'; + + /** + * The suffix format of the JSON flags options. + * + * @var string + */ + const JSON_FLAGS_SUFFIX_FORMAT = '%s_' . JsonSerializer::FORMAT_NAME . '_flags'; + + /** + * The suffix format of the NDJSON line ending options. + * + * @var string + */ + const NDJSON_LINE_ENDING_SUFFIX_FORMAT = '%s_' . LineDelimitedJsonSerializer::FORMAT_NAME . '_eol'; + + /** + * Get the helpdesk code. + * + * @return null|string + * The helpdesk code. + */ + public static function getHelpdeskCode() { + return static::getConfigAsBasicTextboxField( + static::CODE + )->getClean(); + } + + /** + * Get the stream format. + * + * @return null|string + * The stream format. + */ + public static function getStreamFormat() { + return static::getConfigAsChoiceField( + static::STREAM + )->getClean(); + } + + /** + * Get the Beanstalk stream host name. + * + * @return null|string + * The Beanstalk stream host name. + */ + public static function getBeanstalkStreamHostName() { + return static::getConfigAsBasicTextboxField( + static::STREAM_BEANSTALK_HOST + )->getClean(); + } + + /** + * Get the Beanstalk stream port number. + * + * @return int + * The Beanstalk stream port number. + */ + public static function getBeanstalkStreamPortNumber() : int { + return \intval(static::getConfigAsBasicTextboxField( + static::STREAM_BEANSTALK_PORT + )->getClean()); + } + + /** + * Get the Beanstalk stream priority. + * + * @return int + * The Beanstalk stream priority. + */ + public static function getBeanstalkStreamPriority() : int { + return \intval(static::getConfigAsBasicTextboxField( + static::STREAM_BEANSTALK_PRIORITY + )->getClean()); + } + + /** + * Get the Beanstalk stream delay. + * + * @return int + * The Beanstalk stream delay. + */ + public static function getBeanstalkStreamDelay() : int { + return \intval(static::getConfigAsBasicTextboxField( + static::STREAM_BEANSTALK_DELAY + )->getClean()); + } + + /** + * Get the Beanstalk stream time to run. + * + * @return int + * The Beanstalk stream time to run. + */ + public static function getBeanstalkStreamTimeToRun() : int { + return \intval(static::getConfigAsBasicTextboxField( + static::STREAM_BEANSTALK_TTR + )->getClean()); + } + + /** + * Check whether the use case is enabled. + * + * @param string $context + * The use case machine name. + * + * @return bool + * Whether the use case is enabled. + */ + public static function isUseCaseEnabled(string $context) : bool { + return \boolval(static::getConfigAsTertiumNonDaturField( + \sprintf(static::USE_CASE_ENABLED_FORMAT, $context) + )->getClean()); + } + + /** + * Get the tuple format. + * + * @param string $context + * The use case in which the tuple is used. + * + * @return null|string + * The tuple format. + */ + public static function getTupleFormat(string $context) { + return Sequence::getFormatName(); + } + + /** + * Get the Sequence tuple serializer format. + * + * @param string $context + * The use case in which the Sequence tuple is used. + * + * @return null|string + * The Sequence tuple serializer format. + */ + public static function getSequenceTupleSerializerFormat(string $context) { + return static::getConfigAsChoiceField( + \sprintf(static::USE_CASE_TUPLE_SEQUENCE_SERIALIZER_FORMAT, $context) + )->getClean(); + } + + /** + * Get the record format. + * + * @param string $context + * The use case in which the record is used. + * + * @return null|string + * The record format. + */ + public static function getRecordFormat(string $context) { + return static::getConfigAsChoiceField( + \sprintf(static::USE_CASE_RECORD_FORMAT, $context) + )->getClean(); + } + + /** + * Get the Kinesis record stream name. + * + * @param string $context + * The use case in which the Kinesis record is used. + * + * @return null|string + * The Kinesis record stream name. + */ + public static function getKinesisRecordStreamName(string $context) { + return static::getConfigAsBasicTextboxField( + \sprintf(static::USE_CASE_RECORD_KINESIS_STREAM_FORMAT, $context) + )->getClean(); + } + + /** + * Get the Kinesis record encoder format. + * + * @param string $context + * The use case in which the Kinesis record is used. + * + * @return null|string + * The Kinesis record encoder format. + */ + public static function getKinesisRecordEncoderFormat(string $context) { + return static::getConfigAsChoiceField( + \sprintf(static::USE_CASE_RECORD_KINESIS_ENCODER_FORMAT, $context) + )->getClean(); + } + + /** + * Get the Kinesis record serializer format. + * + * @param string $context + * The use case in which the Kinesis record is used. + * + * @return null|string + * The Kinesis record serializer format. + */ + public static function getKinesisRecordSerializerFormat(string $context) { + return static::getConfigAsChoiceField( + \sprintf(static::USE_CASE_RECORD_KINESIS_SERIALIZER_FORMAT, $context) + )->getClean(); + } + + /** + * Get the stream queue name. + * + * @param string $context + * The use case in which the queue is used. + * @param string $format + * The format of the stream that uses the queue. + * + * @return null|string + * The stream queue name. + */ + public static function getUseCaseQueueName(string $context, string $format) { + return static::getConfigAsBasicTextboxField( + \sprintf(static::USE_CASE_QUEUE_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean(); + } + + /** + * Get the UTF-8 encoder source encoding. + * + * @param string $context + * The use case in which the encoder is used. + * @param string $format + * The format of the entity that uses the encoder. + * + * @return null|string + * The UTF-8 encoder source encoding. + */ + public static function getUtf8EncoderSourceEncondig(string $context, string $format) { + return static::getConfigAsChoiceField( + \sprintf(static::UTF8_ENCODING_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean(); + } + + /** + * Get the CSV serializer field separator. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return null|string + * The CSV serializer field separator. + */ + public static function getCsvSerializerFieldSeparator(string $context, string $format) { + return static::getConfigAsBasicTextboxField( + \sprintf(static::CSV_SEPARATOR_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean(); + } + + /** + * Get the CSV serializer field enclosure. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return null|string + * The CSV serializer field enclosure. + */ + public static function getCsvSerializerFieldEnclosure(string $context, string $format) { + return static::getConfigAsBasicTextboxField( + \sprintf(static::CSV_ENCLOSURE_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean(); + } + + /** + * Get the CSV serializer escape character. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return null|string + * The CSV serializer escape character. + */ + public static function getCsvSerializerEscapeCharacter(string $context, string $format) { + return static::getConfigAsBasicTextboxField( + \sprintf(static::CSV_ESCAPE_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean(); + } + + /** + * Get the CSV serializer memory limit. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return int + * The CSV serializer memory limit. + */ + public static function getCsvSerializerMemoryLimit(string $context, string $format) : int { + return \intval(static::getConfigAsBasicTextboxField( + \sprintf(static::CSV_MEMORY_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean()); + } + + /** + * Get the JSON serializer depth. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return int + * The JSON serializer depth. + */ + public static function getJsonSerializerDepth(string $context, string $format) : int { + return \intval(static::getConfigAsBasicTextboxField( + \sprintf(static::JSON_DEPTH_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean()); + } + + /** + * Get the JSON serializer flags. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return int + * The JSON serializer flags. + */ + public static function getJsonSerializerFlags(string $context, string $format) : int { + return \intval(static::getConfigAsJsonFlagsChoiceField( + \sprintf(static::JSON_FLAGS_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getClean()); + } + + /** + * Get the NDJSON serializer line ending. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return null|string + * The NDJSON serializer line ending. + */ + public static function getLineDelimitedJsonSerializerLineEnding(string $context, string $format) { + return static::getConfigAsLineEndingChoiceField( + \sprintf(static::NDJSON_LINE_ENDING_SUFFIX_FORMAT, \sprintf('%s_%s', $context, $format)) + )->getCleanDecoded(); + } + +} diff --git a/include/Streamer/osTicket/Factories/EncoderFactory.php b/include/Streamer/osTicket/Factories/EncoderFactory.php new file mode 100644 index 0000000..c803957 --- /dev/null +++ b/include/Streamer/osTicket/Factories/EncoderFactory.php @@ -0,0 +1,103 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Factories; + +use Bitfinex\Data\Encoder\Utf8Encoder; +use Bitfinex\Data\Encoder\EncoderInterface; +use Bitfinex\Data\Validator\Strings\NotBlankValidator; +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Encoder\EncoderFactory as UnbindedEncoderFactory; +use Bitfinex\Data\Streamer\osTicket\Actions\Formats\EncoderFormatsAlterSignal; + +/** + * The osTicket encoder factory. + */ +class EncoderFactory extends UnbindedEncoderFactory { + + /** + * The format of the entity that uses the encoder. + * + * @var string + */ + protected $format; + + /** + * The use case in which the encoder is used. + * + * @var string + */ + protected $context; + + /** + * Construct the osTicket encoder factory. + * + * @param string $context + * The use case in which the encoder is used. + * @param string $format + * The format of the entity that uses the encoder. + * + * @return self + */ + public function __construct(string $context, string $format) { + parent::__construct(new EncoderFormatsAlterSignal()); + + if (NotBlankValidator::isNotValid($context) || NotBlankValidator::isNotValid($format)) { + throw new \InvalidArgumentException(); + } + + $this->{'format'} = $format; + $this->{'context'} = $context; + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + $options = parent::options(); + + $options[Utf8Encoder::getFormatName()][static::INITIALIZER_KEY] = [ + $this, + 'createUtf8Encoder', + ]; + + return $options; + } + + /** + * Create an UTF-8 encoder. + * + * @param mixed ...$arguments + * A list of arguments suitable for the UTF-8 encoder constructor. If + * an argument is not provided, the Osticket configuration will be used. + * + * @return EncoderInterface + * A new instance of the UTF-8 encoder. + */ + protected function createUtf8Encoder(...$arguments) : EncoderInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $arguments[0] = Helper::getUtf8EncoderSourceEncondig($this->{'context'}, $this->{'format'}); + } + + return new Utf8Encoder(...$arguments); + } + +} diff --git a/include/Streamer/osTicket/Factories/RecordFactory.php b/include/Streamer/osTicket/Factories/RecordFactory.php new file mode 100644 index 0000000..0743984 --- /dev/null +++ b/include/Streamer/osTicket/Factories/RecordFactory.php @@ -0,0 +1,103 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Factories; + +use Bitfinex\Data\Record\KinesisRecord; +use Bitfinex\Data\Record\RecordInterface; +use Bitfinex\Data\Validator\Strings\NotBlankValidator; +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Record\RecordFactory as UnbindedRecordFactory; +use Bitfinex\Data\Streamer\osTicket\Actions\Formats\RecordFormatsAlterSignal; + +/** + * The osTicket record factory. + */ +class RecordFactory extends UnbindedRecordFactory { + + /** + * The use case in which the record is used. + * + * @var string + */ + protected $context; + + /** + * Construct the osTicket record factory. + * + * @param string $context + * The use case in which the record is used. + * + * @return self + */ + public function __construct(string $context) { + parent::__construct(new RecordFormatsAlterSignal()); + + if (NotBlankValidator::isNotValid($context)) { + throw new \InvalidArgumentException(); + } + + $this->{'context'} = $context; + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + $options = parent::options(); + + $options[KinesisRecord::getFormatName()][static::INITIALIZER_KEY] = [ + $this, + 'createKinesisRecord', + ]; + + return $options; + } + + /** + * Create a Kinesis record. + * + * @param mixed ...$arguments + * A list of arguments suitable for the Kinesis record constructor. If + * an argument is not provided, the Osticket configuration will be used. + * + * @return RecordInterface + * A new instance of the Kinesis record. + */ + protected function createKinesisRecord(...$arguments) : RecordInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $arguments[0] = Helper::getKinesisRecordStreamName($this->{'context'}); + } + + if (\array_key_exists(1, $arguments) === FALSE) { + $factory = new EncoderFactory($this->{'context'}, KinesisRecord::getFormatName()); + $arguments[1] = $factory->create(Helper::getKinesisRecordEncoderFormat($this->{'context'})); + } + + if (\array_key_exists(2, $arguments) === FALSE) { + $factory = new SerializerFactory($this->{'context'}, KinesisRecord::getFormatName()); + $arguments[2] = $factory->create(Helper::getKinesisRecordSerializerFormat($this->{'context'})); + } + + return new KinesisRecord(...$arguments); + } + +} diff --git a/include/Streamer/osTicket/Factories/SerializerFactory.php b/include/Streamer/osTicket/Factories/SerializerFactory.php new file mode 100644 index 0000000..201bb9b --- /dev/null +++ b/include/Streamer/osTicket/Factories/SerializerFactory.php @@ -0,0 +1,175 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Factories; + +use Bitfinex\Data\Serializer\CsvSerializer; +use Bitfinex\Data\Serializer\JsonSerializer; +use Bitfinex\Data\Serializer\SerializerInterface; +use Bitfinex\Data\Validator\Strings\NotBlankValidator; +use Bitfinex\Data\Serializer\LineDelimitedJsonSerializer; +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Serializer\SerializerFactory as UnbindedSerializerFactory; +use Bitfinex\Data\Streamer\osTicket\Actions\Formats\SerializerFormatsAlterSignal; + +/** + * The osTicket serializer factory. + */ +class SerializerFactory extends UnbindedSerializerFactory { + + /** + * The format of the entity that uses the serializer. + * + * @var string + */ + protected $format; + + /** + * The use case in which the serializer is used. + * + * @var string + */ + protected $context; + + /** + * Construct the osTicket serializer factory. + * + * @param string $context + * The use case in which the serializer is used. + * @param string $format + * The format of the entity that uses the serializer. + * + * @return self + */ + public function __construct(string $context, string $format) { + parent::__construct(new SerializerFormatsAlterSignal()); + + if (NotBlankValidator::isNotValid($context) || NotBlankValidator::isNotValid($format)) { + throw new \InvalidArgumentException(); + } + + $this->{'format'} = $format; + $this->{'context'} = $context; + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + $options = parent::options(); + + $options[CsvSerializer::getFormatName()][static::INITIALIZER_KEY] = [ + $this, + 'createCsvSerializer', + ]; + + $options[JsonSerializer::getFormatName()][static::INITIALIZER_KEY] = [ + $this, + 'createJsonSerializer', + ]; + + $options[LineDelimitedJsonSerializer::getFormatName()][static::INITIALIZER_KEY] = [ + $this, + 'createLineDelimitedJsonSerializer', + ]; + + return $options; + } + + /** + * Create a CSV serializer. + * + * @param mixed ...$arguments + * A list of arguments suitable for the CSV serializer constructor. If + * an argument is not provided, the Osticket configuration will be used. + * + * @return SerializerInterface + * A new instance of the CSV serializer. + */ + protected function createCsvSerializer(...$arguments) : SerializerInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $arguments[0] = Helper::getCsvSerializerFieldSeparator($this->{'context'}, $this->{'format'}); + } + + if (\array_key_exists(1, $arguments) === FALSE) { + $arguments[1] = Helper::getCsvSerializerFieldEnclosure($this->{'context'}, $this->{'format'}); + } + + if (\array_key_exists(2, $arguments) === FALSE) { + $arguments[2] = Helper::getCsvSerializerEscapeCharacter($this->{'context'}, $this->{'format'}); + } + + if (\array_key_exists(3, $arguments) === FALSE) { + $arguments[3] = Helper::getCsvSerializerMemoryLimit($this->{'context'}, $this->{'format'}); + } + + return new CsvSerializer(...$arguments); + } + + /** + * Create a JSON serializer. + * + * @param mixed ...$arguments + * A list of arguments suitable for the JSON serializer constructor. If + * an argument is not provided, the Osticket configuration will be used. + * + * @return SerializerInterface + * A new instance of the JSON serializer. + */ + protected function createJsonSerializer(...$arguments) : SerializerInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $arguments[0] = Helper::getJsonSerializerFlags($this->{'context'}, $this->{'format'}); + } + + if (\array_key_exists(1, $arguments) === FALSE) { + $arguments[1] = Helper::getJsonSerializerDepth($this->{'context'}, $this->{'format'}); + } + + return new JsonSerializer(...$arguments); + } + + /** + * Create a NDJSON serializer. + * + * @param mixed ...$arguments + * A list of arguments suitable for the NDJSON serializer constructor. If + * an argument is not provided, the Osticket configuration will be used. + * + * @return SerializerInterface + * A new instance of the NDJSON serializer. + */ + protected function createLineDelimitedJsonSerializer(...$arguments) : SerializerInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $arguments[0] = Helper::getLineDelimitedJsonSerializerLineEnding($this->{'context'}, $this->{'format'}); + } + + if (\array_key_exists(1, $arguments) === FALSE) { + $arguments[1] = Helper::getJsonSerializerFlags($this->{'context'}, $this->{'format'}); + } + + if (\array_key_exists(2, $arguments) === FALSE) { + $arguments[2] = Helper::getJsonSerializerDepth($this->{'context'}, $this->{'format'}); + } + + return new LineDelimitedJsonSerializer(...$arguments); + } + +} diff --git a/include/Streamer/osTicket/Factories/StreamFactory.php b/include/Streamer/osTicket/Factories/StreamFactory.php new file mode 100644 index 0000000..aff9cbe --- /dev/null +++ b/include/Streamer/osTicket/Factories/StreamFactory.php @@ -0,0 +1,92 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Factories; + +use Bitfinex\Data\Stream\StreamInterface; +use Bitfinex\Data\Stream\BeanstalkStream; +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Stream\StreamFactory as UnbindedStreamFactory; +use Bitfinex\Data\Streamer\osTicket\Actions\Formats\StreamFormatsAlterSignal; + +/** + * The osTicket stream factory. + */ +class StreamFactory extends UnbindedStreamFactory { + + /** + * Construct the osTicket stream factory. + * + * @return self + */ + public function __construct() { + parent::__construct(new StreamFormatsAlterSignal()); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + $options = parent::options(); + + $options[BeanstalkStream::getFormatName()][static::INITIALIZER_KEY] = [ + $this, + 'createBeanstalkStream', + ]; + + return $options; + } + + /** + * Create a Beanstalk stream. + * + * @param mixed ...$arguments + * A list of arguments suitable for the Beanstalk stream constructor. If + * an argument is not provided, the Osticket configuration will be used. + * + * @return StreamInterface + * A new instance of the Beanstalk stream. + */ + protected function createBeanstalkStream(...$arguments) : StreamInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $arguments[0] = Helper::getBeanstalkStreamHostName(); + } + + if (\array_key_exists(1, $arguments) === FALSE) { + $arguments[1] = Helper::getBeanstalkStreamPortNumber(); + } + + if (\array_key_exists(2, $arguments) === FALSE) { + $arguments[2] = Helper::getBeanstalkStreamPriority(); + } + + if (\array_key_exists(3, $arguments) === FALSE) { + $arguments[3] = Helper::getBeanstalkStreamDelay(); + } + + if (\array_key_exists(4, $arguments) === FALSE) { + $arguments[4] = Helper::getBeanstalkStreamTimeToRun(); + } + + return new BeanstalkStream(...$arguments); + } + +} diff --git a/include/Streamer/osTicket/Factories/TupleFactory.php b/include/Streamer/osTicket/Factories/TupleFactory.php new file mode 100644 index 0000000..a2d9a56 --- /dev/null +++ b/include/Streamer/osTicket/Factories/TupleFactory.php @@ -0,0 +1,98 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Factories; + +use Bitfinex\Data\Tuple\Sequence; +use Bitfinex\Data\Tuple\TupleInterface; +use Bitfinex\Data\Validator\Strings\NotBlankValidator; +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Tuple\TupleFactory as UnbindedTupleFactory; +use Bitfinex\Data\Streamer\osTicket\Actions\Formats\TupleFormatsAlterSignal; + +/** + * The osTicket tuple factory. + */ +class TupleFactory extends UnbindedTupleFactory { + + /** + * The use case in which the tuple is used. + * + * @var string + */ + protected $context; + + /** + * Construct the osTicket tuple factory. + * + * @param string $context + * The use case in which the tuple is used. + * + * @return self + */ + public function __construct(string $context) { + parent::__construct(new TupleFormatsAlterSignal()); + + if (NotBlankValidator::isNotValid($context)) { + throw new \InvalidArgumentException(); + } + + $this->{'context'} = $context; + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + $options = parent::options(); + + $options[Sequence::getFormatName()][static::INITIALIZER_KEY] = [ + $this, + 'createSequenceTuple', + ]; + + return $options; + } + + /** + * Create a Sequence tuple. + * + * @param mixed ...$arguments + * A list of arguments suitable for the Sequence tuple constructor. If + * an argument is not provided, the Osticket configuration will be used. + * + * @return TupleInterface + * A new instance of the Sequence tuple. + */ + protected function createSequenceTuple(...$arguments) : TupleInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $arguments[0] = []; + } + + if (\array_key_exists(1, $arguments) === FALSE) { + $factory = new SerializerFactory($this->{'context'}, Sequence::getFormatName()); + $arguments[1] = $factory->create(Helper::getSequenceTupleSerializerFormat($this->{'context'})); + } + + return new Sequence(...$arguments); + } + +} diff --git a/include/Streamer/osTicket/Factories/UseCaseFactory.php b/include/Streamer/osTicket/Factories/UseCaseFactory.php new file mode 100644 index 0000000..8fda93c --- /dev/null +++ b/include/Streamer/osTicket/Factories/UseCaseFactory.php @@ -0,0 +1,92 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Factories; + +use Bitfinex\Data\UseCase\UseCaseInterface; +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Streamer\osTicket\UseCase\TicketsCreationUseCase; +use Bitfinex\Data\UseCase\UseCaseFactory as UnbindedUseCaseFactory; +use Bitfinex\Data\Streamer\osTicket\Actions\UseCases\UseCasesAlterSignal; + +/** + * The osTicket use case factory. + */ +class UseCaseFactory extends UnbindedUseCaseFactory { + + /** + * Construct the osTicket use case factory. + * + * @return self + */ + public function __construct() { + parent::__construct(new UseCasesAlterSignal()); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + $options = parent::options(); + + $options[TicketsCreationUseCase::getFormatName()] = [ + static::DESCRIPTION_KEY => 'Tickets creation', + static::INITIALIZER_KEY => [$this, 'createTicketsCreationUseCase'], + ]; + + return $options; + } + + /** + * Create a Tickets Creation use case. + * + * @param mixed ...$arguments + * A list of arguments suitable for the Tickets Creation constructor. + * If an argument is not provided, the Osticket configuration will be used. + * + * @return UseCaseInterface + * A new instance of the Tickets Creation use case. + */ + protected function createTicketsCreationUseCase(...$arguments) : UseCaseInterface { + if (\array_key_exists(0, $arguments) === FALSE) { + $factory = new TupleFactory(TicketsCreationUseCase::getFormatName()); + $arguments[0] = $factory->create(Helper::getTupleFormat(TicketsCreationUseCase::getFormatName())); + } + + if (\array_key_exists(1, $arguments) === FALSE) { + $factory = new RecordFactory(TicketsCreationUseCase::getFormatName()); + $arguments[1] = $factory->create(Helper::getRecordFormat(TicketsCreationUseCase::getFormatName())); + } + + if (\array_key_exists(2, $arguments) === FALSE) { + $factory = new StreamFactory(); + $arguments[2] = $factory->create(Helper::getStreamFormat()); + } + + if (\array_key_exists(3, $arguments) === FALSE) { + $cname = \get_class($arguments[2]); + $arguments[3] = Helper::getUseCaseQueueName(TicketsCreationUseCase::getFormatName(), $cname::getFormatName()); + } + + return new TicketsCreationUseCase(...$arguments); + } + +} diff --git a/include/Streamer/osTicket/Fields/BasicTextboxField.php b/include/Streamer/osTicket/Fields/BasicTextboxField.php new file mode 100644 index 0000000..6c007c0 --- /dev/null +++ b/include/Streamer/osTicket/Fields/BasicTextboxField.php @@ -0,0 +1,126 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields; + +use Bitfinex\Data\Validator\Strings\NotEmptyValidator; + +/** + * The basic textbox field. + */ +class BasicTextboxField extends \TextboxField { + + /** + * {@inheritDoc} + */ + public static $widget = __NAMESPACE__ . '\Widgets\BasicTextboxWidget'; + + /** + * Default field length. + * + * @var int + */ + const DEFAULT_LENGTH = 0x10; + + /** + * {@inheritDoc} + */ + public function getConfigurationOptions() { + $configuration = parent::getConfigurationOptions(); + + $has_length = \array_key_exists('length', $configuration) + && $configuration['length'] instanceof \FormField; + + if ($has_length) { + $configuration['length']->set('default', static::DEFAULT_LENGTH); + } + + foreach (['validator', 'regex', 'validator-error'] as $name) { + unset($configuration[$name]); + } + + return $configuration; + } + + /** + * {@inheritDoc} + */ + public function validateEntry($value) { + if (isset($value) === FALSE && \count($this->{'_errors'}) > 0) { + return; + } + + if ($this->get('required') && NotEmptyValidator::isNotValid($value) && $this->hasData()) { + $this->{'_errors'}[] = $this->getLabel() + ? \sprintf(__('%s is a required field'), $this->getLabel()) + : __('This is a required field'); + + return; + } + + if (NotEmptyValidator::isValid($value)) { + $validators = $this->get('validators'); + + if (isset($validators) === TRUE) { + if (\is_array($validators) === TRUE) { + foreach ($validators as $validator) { + if (\is_callable($validator) === TRUE) { + \call_user_func_array($validator, [$this, $value]); + } + } + } + elseif (\is_callable($validators) === TRUE) { + \call_user_func_array($validators, [$this, $value]); + } + } + } + } + + /** + * {@inheritDoc} + */ + public function whatChanged($before, $after) { + if (NotEmptyValidator::isValid($before)) { + $format = __('changed from %1$s to %2$s'); + } + else { + $format = __('set to %2$s'); + } + + return \sprintf($format, $this->display($before), $this->display($after)); + } + + /** + * {@inheritDoc} + */ + public function getSearchMethodWidgets() { + $widgets = parent::getSearchMethodWidgets(); + + foreach ($widgets as &$widget) { + if (\is_array($widget) === TRUE) { + $widget[0] = \get_class($this); + } + } + + return $widgets; + } + +} diff --git a/include/Streamer/osTicket/Fields/FlagsChoiceField.php b/include/Streamer/osTicket/Fields/FlagsChoiceField.php new file mode 100644 index 0000000..f992abc --- /dev/null +++ b/include/Streamer/osTicket/Fields/FlagsChoiceField.php @@ -0,0 +1,193 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields; + +/** + * The flags choice field. + */ +class FlagsChoiceField extends \ChoiceField { + + /** + * {@inheritDoc} + */ + public static $widget = __NAMESPACE__ . '\Widgets\FlagsBoxChoicesWidget'; + + /** + * Name of the flag whose value is zero. + * + * @var int + */ + const FLAG_NONE = 0x0000; + + /** + * {@inheritDoc} + */ + public function getConfigurationOptions() { + $options_text = [ + 'default' => __('(Enter the sum of keys). Value(s) selected from the list initially'), + 'choices' => __('List choices, one per line. Specify key:value names, defining keys in powers of two, ie 1, 2, 4, and so on. This means the individual flags in combined choices do not overlap.'), + ]; + + $configuration = parent::getConfigurationOptions(); + + foreach ($options_text as $option => $text) { + $has_option = \array_key_exists($option, $configuration) + && $configuration[$option] instanceof \FormField; + + if ($has_option) { + $configuration[$option]->set('hint', $text); + } + } + + foreach (['prompt', 'multiselect'] as $name) { + unset($configuration[$name]); + } + + return $configuration; + } + + /** + * {@inheritDoc} + */ + public function getConfiguration() { + parent::getConfiguration(); + + $this->_config['multiple'] = TRUE; + return $this->_config; + } + + /** + * {@inheritDoc} + */ + public function to_config($value) { + if (\is_array($value) === TRUE) { + unset($value['multiple']); + } + + return $value; + } + + /** + * {@inheritDoc} + */ + public function to_database($value) { + if (\is_array($value) === TRUE) { + return \array_sum(\array_keys($value)); + } + + return $value; + } + + /** + * {@inheritDoc} + */ + public function to_php($value) { + if (\is_numeric($value) === TRUE) { + $bitmap = \intval($value); + $value = []; + + foreach ($this->getChoices() as $flag => $label) { + if (($bitmap & $flag) !== static::FLAG_NONE) { + $value[$flag] = $label; + } + } + } + + return $value; + } + + /** + * {@inheritDoc} + */ + public function getClean($validate = TRUE) { + $value = parent::getClean($validate); + + return \is_array($value) === FALSE + ? static::FLAG_NONE + : $this->to_database($value); + } + + /** + * {@inheritDoc} + */ + public function whatChanged($before, $after) { + if (\is_array($before) === TRUE) { + $before = \array_keys($before); + } + + if (\is_array($after) === TRUE) { + $after = \array_keys($after); + } + + return parent::whatChanged($before, $after); + } + + /** + * {@inheritDoc} + */ + public function toString($value) { + if (\is_array($value) === TRUE) { + return \implode(' | ', $value); + } + + return parent::toString($value); + } + + /** + * {@inheritDoc} + */ + public function getSearchQ($method, $value, $name = FALSE) { + $name = $name ?: $this->get('name'); + + if (\is_array($value) === TRUE) { + $constraints = []; + + foreach ($value as $flag => $label) { + $constraints[] = \Q::any([ + "{$name}__hasbit" => $flag, + ]); + } + + $criteria = \Q::any($constraints); + } + else { + $criteria = \Q::all([ + new \Q(["{$name}__isnull" => FALSE]), + new \Q(["{$name}__gt" => static::FLAG_NONE]), + ]); + } + + switch ($method) { + case 'nset': + case '!includes': + return \Q::not($criteria); + + case 'set': + case 'includes': + return $criteria; + + default: + return parent::getSearchQ($method, $value, $name); + } + } + +} diff --git a/include/Streamer/osTicket/Fields/JsonFlagsChoiceField.php b/include/Streamer/osTicket/Fields/JsonFlagsChoiceField.php new file mode 100644 index 0000000..be77281 --- /dev/null +++ b/include/Streamer/osTicket/Fields/JsonFlagsChoiceField.php @@ -0,0 +1,83 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields; + +/** + * The JSON flags choice field. + */ +final class JsonFlagsChoiceField extends FlagsChoiceField { + + /** + * {@inheritDoc} + */ + public function __construct(array $options = []) { + $options['choices'] = [ + \JSON_HEX_TAG => __('Json Hex Tag'), + \JSON_HEX_AMP => __('Json Hex Amp'), + \JSON_HEX_APOS => __('Json Hex Apos'), + \JSON_HEX_QUOT => __('Json Hex Quot'), + \JSON_FORCE_OBJECT => __('Json Force Object'), + \JSON_NUMERIC_CHECK => __('Json Numeric Check'), + \JSON_PRETTY_PRINT => __('Json Pretty Print'), + \JSON_UNESCAPED_SLASHES => __('Json Unescaped Slashes'), + \JSON_UNESCAPED_UNICODE => __('Json Unescaped Unicode'), + \JSON_PARTIAL_OUTPUT_ON_ERROR => __('Json Partial Output On Error'), + \JSON_PRESERVE_ZERO_FRACTION => __('Json Preserve Zero Fraction'), + ]; + + if (\defined('\JSON_UNESCAPED_LINE_TERMINATORS')) { + $options['choices'][\JSON_UNESCAPED_LINE_TERMINATORS] = __('Json Unescaped Line Terminators'); + } + + if (\defined('\JSON_INVALID_UTF8_IGNORE')) { + $options['choices'][\JSON_INVALID_UTF8_IGNORE] = __('Json Invalid UTF-8 Ignore'); + } + + if (\defined('\JSON_INVALID_UTF8_SUBSTITUTE')) { + $options['choices'][\JSON_INVALID_UTF8_SUBSTITUTE] = __('Json Invalid UTF-8 Substitute'); + } + + \ksort($options['choices']); + parent::__construct($options); + } + + /** + * {@inheritDoc} + */ + public function getConfigurationOptions() { + $configuration = parent::getConfigurationOptions(); + $has_default = \array_key_exists('default', $configuration) + && $configuration['default'] instanceof \FormField; + + if ($has_default) { + $configuration['default'] = new static([ + 'label' => $configuration['default']->get('label'), + 'required' => $configuration['default']->get('required'), + 'hint' => __('Value(s) selected from the list initially'), + ]); + } + + unset($configuration['choices']); + return $configuration; + } + +} diff --git a/include/Streamer/osTicket/Fields/LineEndingChoiceField.php b/include/Streamer/osTicket/Fields/LineEndingChoiceField.php new file mode 100644 index 0000000..9c92c9e --- /dev/null +++ b/include/Streamer/osTicket/Fields/LineEndingChoiceField.php @@ -0,0 +1,166 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields; + +use Bitfinex\Data\Validator\Strings\NotEmptyValidator; + +/** + * The line ending choice field. + */ +final class LineEndingChoiceField extends \ChoiceField { + + /** + * {@inheritDoc} + */ + public function __construct(array $options = []) { + $has_default = \array_key_exists('default', $options) === TRUE + && \is_string($options['default']) === TRUE + && NotEmptyValidator::isValid($options['default']); + + if ($has_default) { + if ($this->isEncodedOptionKey($options['default']) === FALSE) { + $options['default'] = $this->encodeOptionKey($options['default']); + } + } + + $options['choices'] = [ + $this->encodeOptionKey("\000") => __('Null Character'), + $this->encodeOptionKey("\n") => __('Line Feed'), + $this->encodeOptionKey("\u{0085}") => __('Next Line'), + $this->encodeOptionKey("\u{2028}") => __('Line Separator'), + $this->encodeOptionKey("\u{2029}") => __('Paragraph Separator'), + $this->encodeOptionKey("\r\n") => __('Carriage Return + Line Feed'), + ]; + + parent::__construct($options); + } + + /** + * {@inheritDoc} + */ + public function getConfigurationOptions() { + $configuration = parent::getConfigurationOptions(); + $has_default = \array_key_exists('default', $configuration) + && $configuration['default'] instanceof \FormField; + + if ($has_default) { + $configuration['default'] = new static([ + 'label' => $configuration['default']->get('label'), + 'hint' => __('Value selected from the list initially'), + 'required' => $configuration['default']->get('required'), + ]); + } + + foreach (['choices', 'multiselect'] as $name) { + unset($configuration[$name]); + } + + return $configuration; + } + + /** + * {@inheritDoc} + */ + public function getConfiguration() { + parent::getConfiguration(); + + $this->_config['multiselect'] = FALSE; + return $this->_config; + } + + /** + * {@inheritDoc} + */ + public function to_config($value) { + if (\is_array($value) === TRUE) { + unset($value['multiselect']); + } + + return $value; + } + + /** + * Get the decoded clean option key value. + * + * @return null|string + * The decoded decoded option key value, NULL otherwise. + */ + public function getCleanDecoded() { + $value = $this->getClean(); + + if (\is_string($value) && $this->isEncodedOptionKey($value)) { + $decoded = $this->decodeOptionKey($value); + + if (\is_string($decoded) === TRUE) { + return $decoded; + } + } + + return NULL; + } + + /** + * Encode an option key. + * + * @param string $value + * The key value. + * + * @return string + * The encoded key value. + */ + protected function encodeOptionKey(string $value) : string { + return \base64_encode($value); + } + + /** + * Decode an encoded option key. + * + * @param string $value + * The encoded option key. + * + * @return bool|string + * The decoded option key value, FALSE on error. + */ + protected function decodeOptionKey(string $value) { + return \base64_decode($value, TRUE); + } + + /** + * Check whether a value is an encoded string. + * + * @param string $value + * The string value to check. + * + * @return bool + * Whether the given value is an encoded string. + */ + protected function isEncodedOptionKey(string $value) : bool { + $decoded = $this->decodeOptionKey($value); + + if (\is_string($decoded) === TRUE) { + return $this->encodeOptionKey($decoded) === $value; + } + + return $decoded; + } + +} diff --git a/include/Streamer/osTicket/Fields/TertiumNonDaturField.php b/include/Streamer/osTicket/Fields/TertiumNonDaturField.php new file mode 100644 index 0000000..0ddf5c7 --- /dev/null +++ b/include/Streamer/osTicket/Fields/TertiumNonDaturField.php @@ -0,0 +1,40 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields; + +/** + * The tertium non datur field. + */ +class TertiumNonDaturField extends \BooleanField { + + /** + * {@inheritDoc} + */ + public function getClean($validate = TRUE) { + if (!isset($this->{'_clean'}) && !isset($this->{'value'})) { + $this->{'value'} = $this->parse($this->getWidget()->{'value'}); + } + + return parent::getClean($validate); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/AbstractFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/AbstractFieldValidator.php new file mode 100644 index 0000000..9b31afc --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/AbstractFieldValidator.php @@ -0,0 +1,79 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Strings\NotBlankValidator; +use Bitfinex\Data\Streamer\osTicket\Fields\BasicTextboxField; + +/** + * The abstract form field validator. + */ +abstract class AbstractFieldValidator implements FieldValidatorInterface { + + /** + * {@inheritDoc} + */ + public static function length() : int { + return BasicTextboxField::DEFAULT_LENGTH; + } + + /** + * {@inheritDoc} + */ + public static function process(\FormField $field, $value) { + if (static::isNotValid($value)) { + $error = static::error(); + $configuration = $field->getConfiguration(); + + $has_message = \array_key_exists('validator-error', $configuration) + && NotBlankValidator::isValid($configuration['validator-error']); + + if ($has_message) { + $error = $field->getLocal('validator-error', $configuration['validator-error']); + } + + $field->addError($error); + } + } + + /** + * Provides default error message. + * + * @return string + * The default error message string. + */ + protected static function error() : string { + return __('Not a valid field value'); + } + + /** + * Checks whether a value violates at least one constraint of a set. + * + * @param mixed $value + * The value to be inspected. + * + * @return bool + * TRUE if value violates a constraint, FALSE otherwise. + */ + abstract protected static function isNotValid($value) : bool; + +} diff --git a/include/Streamer/osTicket/Fields/Validators/BeanstalkTubeFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/BeanstalkTubeFieldValidator.php new file mode 100644 index 0000000..70cc4a5 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/BeanstalkTubeFieldValidator.php @@ -0,0 +1,52 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Strings\BeanstalkTubeValidator; + +/** + * The beanstalk tube field validator. + */ +class BeanstalkTubeFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + public static function length() : int { + return \intval(BeanstalkTubeValidator::getMaximumLength()); + } + + /** + * {@inheritDoc} + */ + protected static function error() : string { + return __('Not a valid beanstalk tube name'); + } + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return BeanstalkTubeValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/FieldValidatorInterface.php b/include/Streamer/osTicket/Fields/Validators/FieldValidatorInterface.php new file mode 100644 index 0000000..ba8bdd6 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/FieldValidatorInterface.php @@ -0,0 +1,49 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +/** + * The form field validator interface. + */ +interface FieldValidatorInterface { + + /** + * Returns the maximum allowed length of the field. + * + * @return int + * The maximum allowed length of the field. + */ + public static function length() : int; + + /** + * Checks whether a value respects a set of constraints. + * + * @param \FormField $field + * The form field that provides the value. + * @param mixed $value + * The value to be inspected. + * + * @return void + */ + public static function process(\FormField $field, $value); + +} diff --git a/include/Streamer/osTicket/Fields/Validators/HelpdeskCodeFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/HelpdeskCodeFieldValidator.php new file mode 100644 index 0000000..cf05a50 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/HelpdeskCodeFieldValidator.php @@ -0,0 +1,52 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Strings\HelpdeskCodeValidator; + +/** + * The helpdesk code field validator. + */ +class HelpdeskCodeFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + public static function length() : int { + return \intval(HelpdeskCodeValidator::getMaximumLength()); + } + + /** + * {@inheritDoc} + */ + protected static function error() : string { + return __('Not a valid helpdesk code'); + } + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return HelpdeskCodeValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/HostnameFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/HostnameFieldValidator.php new file mode 100644 index 0000000..b65f526 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/HostnameFieldValidator.php @@ -0,0 +1,52 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Strings\HostnameValidator; + +/** + * The hostname field validator. + */ +class HostnameFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + public static function length() : int { + return \intval(HostnameValidator::getMaximumLength()); + } + + /** + * {@inheritDoc} + */ + protected static function error() : string { + return __('Not a valid host name'); + } + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return HostnameValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/KinesisStreamFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/KinesisStreamFieldValidator.php new file mode 100644 index 0000000..bc10cba --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/KinesisStreamFieldValidator.php @@ -0,0 +1,52 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Strings\KinesisStreamValidator; + +/** + * The Kinesis stream field validator. + */ +class KinesisStreamFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + public static function length() : int { + return \intval(KinesisStreamValidator::getMaximumLength()); + } + + /** + * {@inheritDoc} + */ + protected static function error() : string { + return __('Not a valid Kinesis stream name'); + } + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return KinesisStreamValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/NonNegativeDoubleWordFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/NonNegativeDoubleWordFieldValidator.php new file mode 100644 index 0000000..9c37794 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/NonNegativeDoubleWordFieldValidator.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Numbers\NonNegativeDoubleWordValidator; + +/** + * The non negative double word field validator. + */ +class NonNegativeDoubleWordFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return NonNegativeDoubleWordValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/NonNegativeIntegerFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/NonNegativeIntegerFieldValidator.php new file mode 100644 index 0000000..a208282 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/NonNegativeIntegerFieldValidator.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Numbers\NonNegativeIntegerValidator; + +/** + * The non negative integer field validator. + */ +class NonNegativeIntegerFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return NonNegativeIntegerValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/NotBlankFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/NotBlankFieldValidator.php new file mode 100644 index 0000000..f41d9be --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/NotBlankFieldValidator.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Strings\NotBlankValidator; + +/** + * The not blank field validator. + */ +class NotBlankFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return NotBlankValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/NotEmptyFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/NotEmptyFieldValidator.php new file mode 100644 index 0000000..ef62e83 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/NotEmptyFieldValidator.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Strings\NotEmptyValidator; + +/** + * The not empty field validator. + */ +class NotEmptyFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return NotEmptyValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/PositiveDoubleWordFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/PositiveDoubleWordFieldValidator.php new file mode 100644 index 0000000..3569421 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/PositiveDoubleWordFieldValidator.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Numbers\PositiveDoubleWordValidator; + +/** + * The positive double word field validator. + */ +class PositiveDoubleWordFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return PositiveDoubleWordValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/PositiveIntegerFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/PositiveIntegerFieldValidator.php new file mode 100644 index 0000000..11cf4e4 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/PositiveIntegerFieldValidator.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Numbers\PositiveIntegerValidator; + +/** + * The positive integer field validator. + */ +class PositiveIntegerFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return PositiveIntegerValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Validators/PositiveWordFieldValidator.php b/include/Streamer/osTicket/Fields/Validators/PositiveWordFieldValidator.php new file mode 100644 index 0000000..d727782 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Validators/PositiveWordFieldValidator.php @@ -0,0 +1,38 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Validators; + +use Bitfinex\Data\Validator\Numbers\PositiveWordValidator; + +/** + * The positive word field validator. + */ +class PositiveWordFieldValidator extends AbstractFieldValidator { + + /** + * {@inheritDoc} + */ + protected static function isNotValid($value) : bool { + return PositiveWordValidator::isNotValid($value); + } + +} diff --git a/include/Streamer/osTicket/Fields/Widgets/BasicTextboxWidget.php b/include/Streamer/osTicket/Fields/Widgets/BasicTextboxWidget.php new file mode 100644 index 0000000..ec7720d --- /dev/null +++ b/include/Streamer/osTicket/Fields/Widgets/BasicTextboxWidget.php @@ -0,0 +1,40 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Widgets; + +/** + * The basic text box widget. + */ +class BasicTextboxWidget extends \TextboxWidget { + + /** + * {@inheritDoc} + */ + public function render($options = [], $extraConfig = FALSE) { + if (isset($this->{'value'}) === FALSE) { + $this->{'value'} = $this->{'field'}->parse($this->{'field'}->get('default')); + } + + parent::render($options, $extraConfig); + } + +} diff --git a/include/Streamer/osTicket/Fields/Widgets/FlagsBoxChoicesWidget.php b/include/Streamer/osTicket/Fields/Widgets/FlagsBoxChoicesWidget.php new file mode 100644 index 0000000..cb2d7b7 --- /dev/null +++ b/include/Streamer/osTicket/Fields/Widgets/FlagsBoxChoicesWidget.php @@ -0,0 +1,54 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\Fields\Widgets; + +/** + * The flags box choices widget. + */ +class FlagsBoxChoicesWidget extends \BoxChoicesWidget { + + /** + * {@inheritDoc} + */ + public function render($options = []) { + if (isset($this->{'value'}) === TRUE) { + $this->{'value'} = $this->{'field'}->parse($this->{'value'}); + } + else { + $this->{'value'} = $this->{'field'}->parse($this->{'field'}->get('default')); + + if (isset($this->{'value'}) === FALSE) { + $config = $this->{'field'}->getConfiguration(); + + $has_default = \is_array($config) === TRUE + && \array_key_exists('default', $config) === TRUE; + + if ($has_default) { + $this->{'value'} = $this->{'field'}->parse($config['default']); + } + } + } + + parent::render($options); + } + +} diff --git a/include/Streamer/osTicket/UseCase/TicketsCreationUseCase.php b/include/Streamer/osTicket/UseCase/TicketsCreationUseCase.php new file mode 100644 index 0000000..abbd575 --- /dev/null +++ b/include/Streamer/osTicket/UseCase/TicketsCreationUseCase.php @@ -0,0 +1,128 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Streamer\osTicket\UseCase; + +use Bitfinex\Data\Tuple\TupleInterface; +use Bitfinex\Data\Stream\StreamInterface; +use Bitfinex\Data\Record\RecordInterface; +use Bitfinex\Data\UseCase\AbstractUseCase; +use Bitfinex\Data\Streamer\osTicket\Configuration\Helper; +use Bitfinex\Data\Streamer\osTicket\Actions\UseCases\TicketsCreationUseCasesAlterSignal; + +/** + * The tickets creation use case. + */ +class TicketsCreationUseCase extends AbstractUseCase { + + /** + * The data tuple. + * + * @var TupleInterface + */ + protected $tuple; + + /** + * The stream queue name. + * + * @var null|string + */ + protected $queue; + + /** + * The action manager. + * + * @var \Bitfinex\Data\ActionInterface + */ + protected $action; + + /** + * Construct a tickets creation use case. + * + * @param TupleInterface $tuple + * The use case tuple. + * @param RecordInterface $record + * The use case record. + * @param StreamInterface $stream + * The use case stream. + * @param string $queue + * The stream queue name. + * + * @return self + */ + public function __construct(TupleInterface $tuple, RecordInterface $record, StreamInterface $stream, string $queue = NULL) { + $this->{'tuple'} = $tuple; + $this->{'queue'} = $queue; + $this->{'record'} = $record; + $this->{'stream'} = $stream; + $this->{'action'} = new TicketsCreationUseCasesAlterSignal(); + + if (\class_exists('\Signal') === TRUE) { + \call_user_func_array(['\Signal', 'connect'], [ + 'ticket.created', + [$this, 'onTicketCreated'], + ]); + } + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return 'tickets_creation'; + } + + /** + * Callback function for the "ticket.created" event. + * + * @param \Ticket $ticket + * The newly created ticket. + * + * @return void + */ + public function onTicketCreated(\Ticket $ticket) { + $data = [ + 'helpdesk_code' => Helper::getHelpdeskCode(), + 'datetime_complete' => $ticket->getCreateDate(), + 'department_id' => $ticket->getDeptId(), + 'department_name' => $ticket->getDeptName(), + 'helptopic_id' => $ticket->getTopicId(), + 'helptopic_label' => $ticket->getHelpTopic(), + ]; + + $this->{'action'}->trigger($data, $ticket); + + try { + $this->resolve( + $this->{'tuple'}->clear()->addRange($data), + $this->{'queue'} + ); + } + catch (\RuntimeException $ex) { + $GLOBALS['ost']->logWarning( + \sprintf('%s (%s)', \basename(\BitfinexStreamerPlugin::PLUGIN_DIR), static::getFormatName()), + $ex->getMessage(), + FALSE + ); + } + } + +} diff --git a/include/Tuple/Sequence.php b/include/Tuple/Sequence.php new file mode 100644 index 0000000..30a9df9 --- /dev/null +++ b/include/Tuple/Sequence.php @@ -0,0 +1,145 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Tuple; + +use Bitfinex\Data\Serializer\CsvSerializer; +use Bitfinex\Data\Serializer\SerializerFactory; +use Bitfinex\Data\Serializer\SerializerInterface; + +/** + * The sequence. + */ +class Sequence extends \ArrayIterator implements TupleInterface { + + /** + * The sequence serializer. + * + * @var SerializerInterface + */ + protected $serializer; + + /** + * The sequence tuple format name. + * + * @var string + */ + const FORMAT_NAME = self::FORMAT_GROUP . '_sequence'; + + /** + * Construct a sequence. + * + * @param array $collection + * An ordered list used to initialize the sequence. + * @param SerializerInterface $serializer + * The sequence serializer (default: CSV). + * + * @return self + */ + public function __construct(array $collection = [], SerializerInterface $serializer = NULL) { + parent::__construct($collection); + + if ($serializer instanceof SerializerInterface) { + $this->{'serializer'} = $serializer; + } + else { + $this->{'serializer'} = (new SerializerFactory())->create(CsvSerializer::getFormatName()); + } + } + + /** + * {@inheritDoc} + */ + public function getSerializer() : SerializerInterface { + return $this->{'serializer'}; + } + + /** + * {@inheritDoc} + */ + public function setSerializer(SerializerInterface $serializer) { + $this->{'serializer'} = $serializer; + } + + /** + * {@inheritDoc} + */ + public function add($item, $offset = NULL) : TupleInterface { + if ($offset === NULL) { + $this->append($item); + } + else { + $this->offsetSet($offset, $item); + } + + return $this; + } + + /** + * {@inheritDoc} + */ + public function addRange(array $collection) : TupleInterface { + foreach ($collection as $offset => $item) { + $this->add($item, $offset); + } + + return $this; + } + + /** + * {@inheritDoc} + */ + public function clear() : TupleInterface { + $this->rewind(); + + while ($this->valid()) { + $this->offsetUnset($this->key()); + } + + return $this; + } + + /** + * {@inheritDoc} + */ + public function serialize() : string { + if (($payload = $this->{'serializer'}->serialize($this->getArrayCopy())) === FALSE) { + throw new \UnexpectedValueException(); + } + + return $payload; + } + + /** + * {@inheritDoc} + */ + public function unserialize($serialized) { + throw new \BadMethodCallException('Not implemented'); + } + + /** + * {@inheritDoc} + */ + public static function getFormatName() : string { + return static::FORMAT_NAME; + } + +} diff --git a/include/Tuple/TupleFactory.php b/include/Tuple/TupleFactory.php new file mode 100644 index 0000000..56184ca --- /dev/null +++ b/include/Tuple/TupleFactory.php @@ -0,0 +1,55 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Tuple; + +use Bitfinex\Data\AbstractFactory; + +/** + * The tuple factory. + */ +class TupleFactory extends AbstractFactory { + + /** + * {@inheritDoc} + * + * @return TupleInterface + * A new instance of the tuple. + */ + public function create(string $format, ...$arguments) : TupleInterface { + return parent::create($format, ...$arguments); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + return [ + Sequence::getFormatName() => [ + static::DESCRIPTION_KEY => 'Sequence', + static::INITIALIZER_KEY => function (...$arguments) { + return new Sequence(...$arguments); + }, + ], + ]; + } + +} diff --git a/include/Tuple/TupleInterface.php b/include/Tuple/TupleInterface.php new file mode 100644 index 0000000..7a1871a --- /dev/null +++ b/include/Tuple/TupleInterface.php @@ -0,0 +1,97 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Tuple; + +use Bitfinex\Data\Serializer\SerializerInterface; + +/** + * The tuple interface. + */ +interface TupleInterface extends \SeekableIterator, \ArrayAccess, \Serializable, \Countable { + + /** + * The tuple format group name. + * + * @var string + */ + const FORMAT_GROUP = 'tpl'; + + /** + * Get the tuple serializer. + * + * @return SerializerInterface + * The current tuple serializer. + */ + public function getSerializer() : SerializerInterface; + + /** + * Set the tuple serializer. + * + * @param SerializerInterface $serializer + * The serializer to use. + * + * @return void + */ + public function setSerializer(SerializerInterface $serializer); + + /** + * Add an item to the tuple. + * + * @param mixed $item + * The item to add to the tuple. + * @param null|int|string $offset + * The offset of the item; if not specified, the item is added at the end + * of the tuple. + * + * @return TupleInterface + * The instance of the current object. + */ + public function add($item, $offset = NULL) : TupleInterface; + + /** + * Add the items of the specified collection to the tuple, honoring offsets. + * + * @param array $collection + * The items collection. + * + * @return TupleInterface + * The instance of the current object. + */ + public function addRange(array $collection) : TupleInterface; + + /** + * Remove all elements from the tuple. + * + * @return TupleInterface + * The instance of the current object. + */ + public function clear() : TupleInterface; + + /** + * Get the format name of the tuple. + * + * @return string + * The format name of the tuple. + */ + public static function getFormatName() : string; + +} diff --git a/include/UseCase/AbstractUseCase.php b/include/UseCase/AbstractUseCase.php new file mode 100644 index 0000000..928ca6f --- /dev/null +++ b/include/UseCase/AbstractUseCase.php @@ -0,0 +1,90 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\UseCase; + +use Bitfinex\Data\Tuple\TupleInterface; +use Bitfinex\Data\Stream\StreamInterface; +use Bitfinex\Data\Record\RecordInterface; + +/** + * An abstract use case. + */ +abstract class AbstractUseCase implements UseCaseInterface { + + /** + * The use case stream. + * + * @var StreamInterface + */ + protected $stream; + + /** + * The use case record. + * + * @var RecordInterface + */ + protected $record; + + /** + * {@inheritDoc} + */ + public function getStream() : StreamInterface { + return $this->{'stream'}; + } + + /** + * {@inheritDoc} + */ + public function setStream(StreamInterface $stream) { + $this->{'stream'} = $stream; + } + + /** + * {@inheritDoc} + */ + public function getRecord() : RecordInterface { + return $this->{'record'}; + } + + /** + * {@inheritDoc} + */ + public function setRecord(RecordInterface $record) { + $this->{'record'} = $record; + } + + /** + * {@inheritDoc} + */ + public function resolve(TupleInterface $tuple, string $queue = NULL) { + $this->getStream()->append( + $this->getRecord()->update($tuple), + $queue + ); + } + + /** + * {@inheritDoc} + */ + abstract public static function getFormatName() : string; + +} diff --git a/include/UseCase/UseCaseFactory.php b/include/UseCase/UseCaseFactory.php new file mode 100644 index 0000000..d4fed03 --- /dev/null +++ b/include/UseCase/UseCaseFactory.php @@ -0,0 +1,48 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\UseCase; + +use Bitfinex\Data\AbstractFactory; + +/** + * The use case factory. + */ +class UseCaseFactory extends AbstractFactory { + + /** + * {@inheritDoc} + * + * @return UseCaseInterface + * A new instance of the use case. + */ + public function create(string $format, ...$arguments) : UseCaseInterface { + return parent::create($format, ...$arguments); + } + + /** + * {@inheritDoc} + */ + protected function options() : array { + return []; + } + +} diff --git a/include/UseCase/UseCaseInterface.php b/include/UseCase/UseCaseInterface.php new file mode 100644 index 0000000..1f13d50 --- /dev/null +++ b/include/UseCase/UseCaseInterface.php @@ -0,0 +1,89 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\UseCase; + +use Bitfinex\Data\Tuple\TupleInterface; +use Bitfinex\Data\Stream\StreamInterface; +use Bitfinex\Data\Record\RecordInterface; + +/** + * The use case interface. + */ +interface UseCaseInterface { + + /** + * Get the use case stream. + * + * @return StreamInterface + * The current use case stream. + */ + public function getStream() : StreamInterface; + + /** + * Set the use case stream. + * + * @param StreamInterface $stream + * The stream to use. + * + * @return void + */ + public function setStream(StreamInterface $stream); + + /** + * Get the use case record. + * + * @return RecordInterface + * The current use case record. + */ + public function getRecord() : RecordInterface; + + /** + * Set the use case record. + * + * @param RecordInterface $record + * The record to use. + * + * @return void + */ + public function setRecord(RecordInterface $record); + + /** + * Resolve the use case. + * + * @param TupleInterface $tuple + * The tuple to which the use case applies. + * @param string $queue + * The queue name. + * + * @return void + */ + public function resolve(TupleInterface $tuple, string $queue = NULL); + + /** + * Get the format name of the use case. + * + * @return string + * The format name of the use case. + */ + public static function getFormatName() : string; + +} diff --git a/include/Validator/Numbers/AbstractIntegerValidator.php b/include/Validator/Numbers/AbstractIntegerValidator.php new file mode 100644 index 0000000..30878c5 --- /dev/null +++ b/include/Validator/Numbers/AbstractIntegerValidator.php @@ -0,0 +1,63 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Numbers; + +/** + * The abstract integer validator. + */ +abstract class AbstractIntegerValidator implements NumberValidatorInterface { + + /** + * {@inheritDoc} + */ + abstract public static function getLowerEndpoint(); + + /** + * {@inheritDoc} + */ + abstract public static function getUpperEndpoint(); + + /** + * {@inheritDoc} + */ + public static function isValid($value) : bool { + return static::isNotValid($value) === FALSE; + } + + /** + * {@inheritDoc} + */ + public static function isNotValid($value) : bool { + $options = ['options' => []]; + + if (($endpoint = static::getLowerEndpoint()) !== NULL) { + $options['options']['min_range'] = \intval($endpoint); + } + + if (($endpoint = static::getUpperEndpoint()) !== NULL) { + $options['options']['max_range'] = \intval($endpoint); + } + + return \filter_var($value, \FILTER_VALIDATE_INT, $options) === FALSE; + } + +} diff --git a/include/Validator/Numbers/NonNegativeDoubleWordValidator.php b/include/Validator/Numbers/NonNegativeDoubleWordValidator.php new file mode 100644 index 0000000..1fe0e38 --- /dev/null +++ b/include/Validator/Numbers/NonNegativeDoubleWordValidator.php @@ -0,0 +1,43 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Numbers; + +/** + * The non negative double word validator. + */ +class NonNegativeDoubleWordValidator extends AbstractIntegerValidator { + + /** + * {@inheritDoc} + */ + public static function getLowerEndpoint() { + return 0x00000000; + } + + /** + * {@inheritDoc} + */ + public static function getUpperEndpoint() { + return 0xFFFFFFFF; + } + +} diff --git a/include/Validator/Numbers/NonNegativeIntegerValidator.php b/include/Validator/Numbers/NonNegativeIntegerValidator.php new file mode 100644 index 0000000..574a865 --- /dev/null +++ b/include/Validator/Numbers/NonNegativeIntegerValidator.php @@ -0,0 +1,43 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Numbers; + +/** + * The non negative integer validator. + */ +class NonNegativeIntegerValidator extends AbstractIntegerValidator { + + /** + * {@inheritDoc} + */ + public static function getLowerEndpoint() { + return 0; + } + + /** + * {@inheritDoc} + */ + public static function getUpperEndpoint() { + return NULL; + } + +} diff --git a/include/Validator/Numbers/NumberValidatorInterface.php b/include/Validator/Numbers/NumberValidatorInterface.php new file mode 100644 index 0000000..89585b8 --- /dev/null +++ b/include/Validator/Numbers/NumberValidatorInterface.php @@ -0,0 +1,47 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Numbers; + +use Bitfinex\Data\Validator\ValidatorInterface; + +/** + * The number validator interface. + */ +interface NumberValidatorInterface extends ValidatorInterface { + + /** + * Get the interval lower endpoint. + * + * @return null|int|float + * The interval lower endpoint, NULL if not applicable. + */ + public static function getLowerEndpoint(); + + /** + * Get the interval upper endpoint. + * + * @return null|int|float + * The interval upper endpoint, NULL if not applicable. + */ + public static function getUpperEndpoint(); + +} diff --git a/include/Validator/Numbers/PositiveDoubleWordValidator.php b/include/Validator/Numbers/PositiveDoubleWordValidator.php new file mode 100644 index 0000000..e97045e --- /dev/null +++ b/include/Validator/Numbers/PositiveDoubleWordValidator.php @@ -0,0 +1,43 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Numbers; + +/** + * The positive double word validator. + */ +class PositiveDoubleWordValidator extends AbstractIntegerValidator { + + /** + * {@inheritDoc} + */ + public static function getLowerEndpoint() { + return 0x00000001; + } + + /** + * {@inheritDoc} + */ + public static function getUpperEndpoint() { + return 0xFFFFFFFF; + } + +} diff --git a/include/Validator/Numbers/PositiveIntegerValidator.php b/include/Validator/Numbers/PositiveIntegerValidator.php new file mode 100644 index 0000000..9fd442e --- /dev/null +++ b/include/Validator/Numbers/PositiveIntegerValidator.php @@ -0,0 +1,43 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Numbers; + +/** + * The positive integer validator. + */ +class PositiveIntegerValidator extends AbstractIntegerValidator { + + /** + * {@inheritDoc} + */ + public static function getLowerEndpoint() { + return 1; + } + + /** + * {@inheritDoc} + */ + public static function getUpperEndpoint() { + return NULL; + } + +} diff --git a/include/Validator/Numbers/PositiveWordValidator.php b/include/Validator/Numbers/PositiveWordValidator.php new file mode 100644 index 0000000..593e06e --- /dev/null +++ b/include/Validator/Numbers/PositiveWordValidator.php @@ -0,0 +1,43 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Numbers; + +/** + * The positive word validator. + */ +class PositiveWordValidator extends AbstractIntegerValidator { + + /** + * {@inheritDoc} + */ + public static function getLowerEndpoint() { + return 0x0001; + } + + /** + * {@inheritDoc} + */ + public static function getUpperEndpoint() { + return 0xFFFF; + } + +} diff --git a/include/Validator/Strings/AbstractRegularExpressionValidator.php b/include/Validator/Strings/AbstractRegularExpressionValidator.php new file mode 100644 index 0000000..b7579e1 --- /dev/null +++ b/include/Validator/Strings/AbstractRegularExpressionValidator.php @@ -0,0 +1,62 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +/** + * The abstract regular expression validator. + */ +abstract class AbstractRegularExpressionValidator implements StringValidatorInterface { + + /** + * {@inheritDoc} + */ + abstract public static function getMaximumLength(); + + /** + * {@inheritDoc} + */ + public static function isValid($value) : bool { + return static::isNotValid($value) === FALSE; + } + + /** + * {@inheritDoc} + */ + public static function isNotValid($value) : bool { + $options = [ + 'options' => [ + 'regexp' => static::getSearchPattern(), + ], + ]; + + return \filter_var($value, \FILTER_VALIDATE_REGEXP, $options) === FALSE; + } + + /** + * Get the regular expression search pattern. + * + * @return string + * The regular expression search pattern. + */ + abstract protected static function getSearchPattern() : string; + +} diff --git a/include/Validator/Strings/BeanstalkTubeValidator.php b/include/Validator/Strings/BeanstalkTubeValidator.php new file mode 100644 index 0000000..0ec50ea --- /dev/null +++ b/include/Validator/Strings/BeanstalkTubeValidator.php @@ -0,0 +1,45 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +/** + * The Beanstalk tube name validator. + */ +class BeanstalkTubeValidator extends AbstractRegularExpressionValidator { + + /** + * {@inheritDoc} + */ + public static function getMaximumLength() { + return 0xC8; + } + + /** + * {@inheritDoc} + */ + protected static function getSearchPattern() : string { + return \sprintf('|^[a-z0-9+/;.$_)(][-a-z0-9+/;.$_)(]{0,%d}$|i', + static::getMaximumLength() - 0x01 + ); + } + +} diff --git a/include/Validator/Strings/HelpdeskCodeValidator.php b/include/Validator/Strings/HelpdeskCodeValidator.php new file mode 100644 index 0000000..a81c937 --- /dev/null +++ b/include/Validator/Strings/HelpdeskCodeValidator.php @@ -0,0 +1,45 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +/** + * The helpdesk code validator. + */ +class HelpdeskCodeValidator extends AbstractRegularExpressionValidator { + + /** + * {@inheritDoc} + */ + public static function getMaximumLength() { + return 0x08; + } + + /** + * {@inheritDoc} + */ + protected static function getSearchPattern() : string { + return \sprintf('/^[a-z][-a-z0-9_]{0,%d}$/i', + static::getMaximumLength() - 0x01 + ); + } + +} diff --git a/include/Validator/Strings/HostnameValidator.php b/include/Validator/Strings/HostnameValidator.php new file mode 100644 index 0000000..c7927ac --- /dev/null +++ b/include/Validator/Strings/HostnameValidator.php @@ -0,0 +1,51 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +/** + * The host name validator. + */ +class HostnameValidator implements StringValidatorInterface { + + /** + * {@inheritDoc} + */ + public static function getMaximumLength() { + return 0xFD; + } + + /** + * {@inheritDoc} + */ + public static function isValid($value) : bool { + return static::isNotValid($value) === FALSE; + } + + /** + * {@inheritDoc} + */ + public static function isNotValid($value) : bool { + return \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4 | \FILTER_FLAG_IPV6) === FALSE + && \filter_var($value, \FILTER_VALIDATE_DOMAIN, \FILTER_FLAG_HOSTNAME) === FALSE; + } + +} diff --git a/include/Validator/Strings/KinesisStreamValidator.php b/include/Validator/Strings/KinesisStreamValidator.php new file mode 100644 index 0000000..a1ad108 --- /dev/null +++ b/include/Validator/Strings/KinesisStreamValidator.php @@ -0,0 +1,45 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +/** + * The Kinesis stream name validator. + */ +class KinesisStreamValidator extends AbstractRegularExpressionValidator { + + /** + * {@inheritDoc} + */ + public static function getMaximumLength() { + return 0x80; + } + + /** + * {@inheritDoc} + */ + protected static function getSearchPattern() : string { + return \sprintf('/^[-a-z0-9_.]{1,%d}$/i', + static::getMaximumLength() + ); + } + +} diff --git a/include/Validator/Strings/NotBlankValidator.php b/include/Validator/Strings/NotBlankValidator.php new file mode 100644 index 0000000..98107b4 --- /dev/null +++ b/include/Validator/Strings/NotBlankValidator.php @@ -0,0 +1,51 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +/** + * The not blank validator. + */ +class NotBlankValidator implements StringValidatorInterface { + + /** + * {@inheritDoc} + */ + public static function getMaximumLength() { + return NULL; + } + + /** + * {@inheritDoc} + */ + public static function isValid($value) : bool { + return $value !== NULL + && \preg_match('/\S/', \strval($value)) === 1; + } + + /** + * {@inheritDoc} + */ + public static function isNotValid($value) : bool { + return static::isValid($value) === FALSE; + } + +} diff --git a/include/Validator/Strings/NotEmptyValidator.php b/include/Validator/Strings/NotEmptyValidator.php new file mode 100644 index 0000000..d09a9a8 --- /dev/null +++ b/include/Validator/Strings/NotEmptyValidator.php @@ -0,0 +1,51 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +/** + * The not empty validator. + */ +class NotEmptyValidator implements StringValidatorInterface { + + /** + * {@inheritDoc} + */ + public static function getMaximumLength() { + return NULL; + } + + /** + * {@inheritDoc} + */ + public static function isValid($value) : bool { + return $value !== NULL + && \strlen(\strval($value)) > 0; + } + + /** + * {@inheritDoc} + */ + public static function isNotValid($value) : bool { + return static::isValid($value) === FALSE; + } + +} diff --git a/include/Validator/Strings/StringValidatorInterface.php b/include/Validator/Strings/StringValidatorInterface.php new file mode 100644 index 0000000..fc1d968 --- /dev/null +++ b/include/Validator/Strings/StringValidatorInterface.php @@ -0,0 +1,39 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator\Strings; + +use Bitfinex\Data\Validator\ValidatorInterface; + +/** + * The string validator interface. + */ +interface StringValidatorInterface extends ValidatorInterface { + + /** + * Get the string maximum length. + * + * @return null|int + * The string maximum length, NULL if not applicable. + */ + public static function getMaximumLength(); + +} diff --git a/include/Validator/ValidatorInterface.php b/include/Validator/ValidatorInterface.php new file mode 100644 index 0000000..27f11dc --- /dev/null +++ b/include/Validator/ValidatorInterface.php @@ -0,0 +1,51 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +namespace Bitfinex\Data\Validator; + +/** + * The validator interface. + */ +interface ValidatorInterface { + + /** + * Checks whether a value respects a set of constraints. + * + * @param mixed $value + * The value to be inspected. + * + * @return bool + * TRUE if value respects all constraints, FALSE otherwise. + */ + public static function isValid($value) : bool; + + /** + * Checks whether a value violates at least one constraint of a set. + * + * @param mixed $value + * The value to be inspected. + * + * @return bool + * TRUE if value violates a constraint, FALSE otherwise. + */ + public static function isNotValid($value) : bool; + +} diff --git a/plugin.php b/plugin.php new file mode 100644 index 0000000..e9588bd --- /dev/null +++ b/plugin.php @@ -0,0 +1,33 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +/** + * The bfx-ost-streamer plugin configuration. + */ +return [ + 'id' => /* notrans */ 'bfx:ost:streamer', + 'version' => '1.0.0', + 'name' => /* trans */ 'Bitfinex osTicket Streamer', + 'author' => 'Davide Scola, Nicoletta Maia', + 'description' => /* trans */ 'Adds the ability to stream data.', + 'url' => 'https://github.com/bitfinexcom/helpdesk', + 'plugin' => 'BitfinexStreamerPlugin.php:BitfinexStreamerPlugin', +]; diff --git a/templates/configuration-form.tmpl.php b/templates/configuration-form.tmpl.php new file mode 100644 index 0000000..67e4ad9 --- /dev/null +++ b/templates/configuration-form.tmpl.php @@ -0,0 +1,100 @@ +, + * Nicoletta Maia . + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing permissions + * and limitations under the License. + */ +?> +getTitle()) : ?> +

+ getTitle()); ?>: + getInstructions()); ?> +

+ + +getFields() as $field) : ?> +
isVisible() ? ' style="display:none;"' : ''; ?>> + + isBlockLevel()) : ?> +
+ getLocal('label')); ?>: + + isRequired()) : ?> + * + + + get('hint')) : ?> +
+ getLocal('hint')); ?> +
+ +
+ +
+ + + render($options); ?> + + errors() as $error) : ?> +
+ + + isBlockLevel()) : ?> +
+ +
+ +