JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-}JFIFICC_PROFILElcmsmntrRGB XYZ  acspMSFTsawsctrl-hand=@=@t," desc_cprt wtptrXYZ,gXYZ@bXYZTrTRCh`gTRCh`bTRCh`descuRGBtextCC0XYZ TXYZ o8XYZ bXYZ $curv*|uN  bj. C$)j.~39?FWM6Tv\dluV~,6۾ewC    #%$""!&+7/&)4)!"0A149;>>>%.DIC;C  ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|WH?cS?Ne.r˿ޱ5\YYhFOejT7PZ[qs2c/$Ep[Gqo(Nù=QHci;OipX=Ģ8d^mQeӴm1OsL/x2];i6p!zU -/uX!=<-} .
LIBYA CYBER ARMY
Logo of a company Instagram@3g86    Server : Apache
System : Linux uta-edu.server.ly 4.18.0-513.11.1.el8_9.x86_64 #1 SMP Wed Jan 17 02:00:40 EST 2024 x86_64
User : utripoli ( 1001)
PHP Version : 7.4.33
Disable Function : NONE
Directory :  /home/utripoli/public_html/alqalam/plugins/reports/counter/classes/COUNTER/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/utripoli/public_html/alqalam/plugins/reports/counter/classes/COUNTER/COUNTER.php
<?php

/**
 * Copyright (c) 2015 University of Pittsburgh
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

namespace COUNTER {
    /**
     * COUNTER Reports classes, release 4.1
     * Represents the COUNTER XSD schema in class form
     *
     * @link http://www.niso.org/schemas/sushi
     *
     * @author Clinton Graham, University of Pittsburgh Library System, University of Pittsburgh <ctgraham@pitt.edu> +1-412-383-1057
     * @copyright 2015 University of Pittsburgh
     * @license http://www.gnu.org/licenses/gpl-2.0.html GPL 2.0 or later
     *
     * @package COUNTER
     *
     * @version 0.3
     *
     * @section DESCRIPTION
     *
     * This is a set of classes to represent the Project COUNTER schema ( http://www.projectcounter.org/ )
     * It is basically an encapsulation of DOMDocument, with type checking.
     * Construct any object, then cast it as a string to retrieve the XML, or call asDOMDocument() to retrieve the DOM.
     * $report = new COUNTER\Report(
     * 	'reportId',
     * 	'reportVersion',
     * 	'reportName',
     * 	'reportTitle',
     * 	new COUNTER\Customer(
     * 		'customerId',
     * 		new COUNTER\ReportItems(
     * 			'itemPlatform',
     * 			'itemName',
     * 			'Journal',
     * 			array(
     * 				new COUNTER\Metric(
     * 					new COUNTER\DateRange(date_create("first day of previous month"), date_create("last day of previous month")),
     * 					'Requests',
     * 					array(new COUNTER\PerformanceCounter('ft_html', 128), new COUNTER\PerformanceCounter('ft_pdf', 129))
     * 				),
     * 				new COUNTER\Metric(
     * 					new COUNTER\DateRange(date_create("first day of this month"), date_create("last day of this month")),
     * 					'Requests',
     * 					new COUNTER\PerformanceCounter('other', 121)
     * 				)
     * 			)
     * 		)
     * 	),
     * 	new COUNTER\Vendor('vendorId')
     * );
     * echo $report;
     */

    /**
     * COUNTER report builder class
     * Other classes in this package extend from this core class to have access to several generic functions
     *
     * @todo should "tool-like" functions be moved to static calls from an non-inherited Tools class?
     */
    class ReportBuilder
    {
        public const COUNTER_NAMESPACE = 'http://www.niso.org/schemas/counter';

        /**
         * Validate that $object is a $className instance.  If valid, return the object, otherwise, throw an exception
         *
         * @param object $object
         * @param string $className If no namespace specified, defaults to the COUNTER namespace
         *
         * @throws Exception
         *
         * @return object
         */
        protected function validateOneOf($object, $className)
        {
            if (strpos($className, '\\') === false) {
                $expectedClassname = 'COUNTER\\' . $className;
            } elseif (strpos($className, '\\') === 0) {
                $expectedClassname = substr($className, 1);
            } else {
                $expectedClassname = $className;
            }
            if (is_null($object)) {
                throw new \Exception('Invalid object. Expected "' . $expectedClassname . '", got "NULL"');
            }
            if (is_array($object)) {
                throw new \Exception('Invalid class. Expected "' . $expectedClassname . '", got unparsable array');
            }
            if (is_string($object)) {
                switch ($className) {
                    case '\DateTime':
                        $date = date_create($object);
                        if ($date) {
                            return $date;
                        }
                        break;
                    default:
                }
                throw new \Exception('Invalid class. Expected "' . $expectedClassname . '", got unparsable string');
            }
            if ($expectedClassname == get_class($object) || is_subclass_of($object, $expectedClassname)) {
                return $object;
            }
            throw new \Exception('Invalid class. Expected "' . $expectedClassname . '", got "' . get_class($object) . '"');
        }

        /**
         * Validate that $objects is an array of $className instances.  If valid, return the array, otherwise, throw an exception
         *
         * @param object $objects
         * @param string $className
         *
         * @throws Exception
         *
         * @return array
         */
        protected function validateOneOrMoreOf($objects, $className)
        {
            if (is_array($objects)) {
                foreach ($objects as $object) {
                    $this->validateOneOf($object, $className);
                }
                return $objects;
            }
            return [$this->validateOneOf($objects, $className)];
        }

        /**
         * Validate that $objects is an array of $className instances, or is empty.  If valid, return the array or empty, otherwise, throw an exception
         *
         * @param object $objects
         * @param string $className
         *
         * @throws Exception
         *
         * @return array
         */
        protected function validateZeroOrMoreOf($objects, $className)
        {
            if (empty($objects)) {
                return;
            }
            return $this->validateOneOrMoreOf($objects, $className);
        }

        /**
         * Validate that $object is a $className instance, or is empty.  If valid, return the object or empty, otherwise, throw an exception
         *
         * @param object $object
         * @param string $className
         *
         * @throws Exception
         *
         * @return object
         */
        protected function validateZeroOrOneOf($object, $className)
        {
            if (empty($object)) {
                return;
            }
            return $this->validateOneOf($object, $className);
        }

        /**
         * Validate that $yr is an integer.  If valid, return the year, otherwise, throw an exception
         *
         * @param int $int
         *
         * @throws Exception
         *
         * @return int
         */
        protected function validatePositiveInteger($int)
        {
            $intval = intval($int);
            if (!is_int($intval) || $intval < 0) {
                throw new \Exception('Invalid positive integer: ' . gettype($int) . ' value ' . $int);
            }
            return $intval;
        }

        /**
         * Validate that $string is string.  If valid, return the string, otherwise, throw an exception
         *
         * @param string $string
         *
         * @throws Exception
         *
         * @return string
         */
        protected function validateString($string)
        {
            if (!is_string($string)) {
                throw new \Exception('Invalid string: ' . gettype($string));
            }
            return $string;
        }

        /**
         * Validate that $array is an array of strings.  If valid, return the array, otherwise, throw an exception
         *
         * @param array $array
         *
         * @throws Exception
         *
         * @return array
         */
        protected function validateStrings($array)
        {
            if (is_array($array)) {
                foreach ($array as $string) {
                    $this->validateString($string);
                }
                return $array;
            }
            if (is_string($array)) {
                return [$array];
            }
            if (!empty($array)) {
                throw new \Exception('Invalid string array: ' . gettype($array));
            }
        }

        /**
         * Check an array to see if it has associative (non-numeric) keys
         *
         * @param array $array
         *
         * @return bool
         */
        protected static function isAssociative($array)
        {
            return count(array_filter(array_keys($array), 'is_string')) > 0;
        }

        /**
         * Given an classname and an array, call the $classname::build method and return the built object(s)
         * The array can be associative (for a single object), or an array of associative arrays (for multiple objects)
         *
         * @param string $classname
         * @param array $array
         *
         * @return mixed object or array of objects
         */
        protected function buildMultiple($classname, $array)
        {
            if (!is_array($array)) {
                return [];
            }
            if (self::isAssociative($array)) {
                return $classname::build($array);
            }
            $elements = [];
            foreach ($array as $element) {
                $elements[] = $classname::build($element);
            }
            return $elements;
        }

        /**
         * Return an array of valid Item Data Types
         *
         * @return array
         *
         * @todo verify addition of "Article" here for proposed release 4.2.
         */
        protected function getItemDataTypes()
        {
            return ['Journal', 'Database', 'Platform', 'Book', 'Collection', 'Multimedia', 'Article'];
        }

        /**
         * Return an array of valid Identifier Types
         *
         * @return array
         */
        protected function getIdentifierTypes()
        {
            return ['Online_ISSN', 'Print_ISSN', 'Online_ISBN', 'Print_ISBN', 'DOI', 'Proprietary'];
        }

        /**
         * Return an array of valid Contributor Identifier Types
         *
         * @return array
         */
        protected function getContributorIdentifierTypes()
        {
            return ['ORCID', 'ISNI', 'Proprietary'];
        }

        /**
         * Return an array of valid Date Types
         *
         * @return array
         *
         * @todo these values are preliminary; need an update from COUNTER
         */
        protected function getDateTypes()
        {
            return ['PubDate', 'FirstAccessedOnline', 'Proprietary'];
        }

        /**
         * Return an array of valid Date Types
         *
         * @return array
         *
         * @todo these values are preliminary; need an update from COUNTER
         */
        protected function getAttributeTypes()
        {
            return ['ArticleVersion', 'ArticleType', 'QualificationName', 'QualificationLevel'];
        }

        /**
         * Return an array of valid Metric Types
         *
         * @return array
         */
        protected function getMetricTypes()
        {
            return ['abstract', 'audio', 'data_set', 'ft_epub', 'ft_html', 'ft_html_mobile', 'ft_pdf', 'ft_pdf_mobile', 'ft_ps', 'ft_ps_mobile', 'ft_total', 'image', 'multimedia', 'no_license', 'other', 'podcast', 'record_view', 'reference', 'result_click', 'search_fed', 'search_reg', 'sectioned_html', 'toc', 'turnaway', 'video'];
        }

        /**
         * Return an array of valid Categories
         *
         * @return array
         */
        protected function getCategories()
        {
            return ['Requests', 'Searches', 'Access_denied'];
        }

        /**
         * Output this object as XML
         * Inherited by all children of this object; all children must implement asDOMDocument().
         *
         * @return string
         */
        public function __toString()
        {
            $doc = $this->asDOMDocument();
            $doc->formatOutput = true;
            return $doc->saveXML();
        }

        /**
         * Do NOT Output this object as a DOMDocument
         * This method must be implemented in the subclass
         *
         * @throws Exception
         */
        public function asDOMDocument()
        {
            throw new \Exception(get_class($this) . ' does not implement asDOMDocument()');
        }

        /**
         * Do NOT build this object
         * This method must be implemented in the subclass
         * Subclasses should call this method if unable to build the object in order to report an error.
         *
         * @throws Exception
         */
        public static function build($array)
        {
            throw new \Exception('Failed to build ' . static::class . ' from data ' . var_export($array, true));
        }
    }

    /**
     * COUNTER reports base class
     *
     */
    class Reports extends ReportBuilder
    {
        /**
         * @var array one or more COUNTER\Report objects
         */
        private $report = [];

        /**
         * Construct the object
         *
         * @param array $reports COUNTER\Report array
         *
         * @throws Exception
         */
        public function __construct($reports)
        {
            $this->report = $this->validateOneOrMoreOf($reports, 'Report');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['Report'])) {
                    // Nicely structured associative array
                    $reports = parent::buildMultiple('COUNTER\Report', $array['Report']);
                    return new self($reports);
                }
                if (!parent::isAssociative($array)) {
                    // Just an array of reports
                    $reports = parent::buildMultiple('COUNTER\Report', $array);
                    return new self($reports);
                }
            }
            parent::build($array);
        }

        /**
         * Add a report
         *
         * @param object $report CounterReport
         *
         * @throws Exception
         */
        public function addReport($report)
        {
            $this->report[] = $this->validateOneOf($report, 'Report');
        }

        /**
         * Get an array of reports
         *
         * @return array COUNTER\Report array
         */
        public function getReports()
        {
            return $this->report;
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElementNS(self::COUNTER_NAMESPACE, 'Reports'));
            $xmlns = $doc->createAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation');
            $xmlns->value = self::COUNTER_NAMESPACE . ' http://www.niso.org/schemas/sushi/counter4_1.xsd';
            $root->appendChild($xmlns);
            foreach ($this->report as $rep) {
                $root->appendChild($doc->importNode($rep->asDOMDocument()->documentElement, true));
            }
            return $doc;
        }
    }

    /**
     * COUNTER report instance class
     */
    class Report extends ReportBuilder
    {
        /**
         * @var string Report attribute "Created"
         */
        private $created;
        /**
         * @var string Report attribute "ID"
         */
        private $id;
        /**
         * @var string Report attribute "Version"
         */
        private $version;
        /**
         * @var string Report attribute "Name"
         */
        private $name;
        /**
         * @var string Report attribute "Title"
         */
        private $title;
        /**
         * @var COUNTER\Vendor
         */
        private $vendor;
        /**
         * @var array one or more COUNTER\Customer objects
         */
        private $customer;

        /**
         * Construct the object
         *
         * @param string $id
         * @param string $version
         * @param string $name
         * @param string $title
         * @param string $customers COUNTER\Customer
         * @param object $vendor COUNTER\Vendor array
         * @param string $created optional
         *
         * @throws Exception
         */
        public function __construct($id, $version, $name, $title, $customers, $vendor, $created = '')
        {
            foreach (['id', 'version', 'name', 'title', 'created'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            if (!$created) {
                $this->created = date("Y-m-d\Th:i:sP");
            }
            $this->vendor = $this->validateOneOf($vendor, 'Vendor');
            $this->customer = $this->validateOneOrMoreOf($customers, 'Customer');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['ID']) && isset($array['Version']) && isset($array['Name']) && isset($array['Title']) && isset($array['Customer']) && isset($array['Vendor'])) {
                    // Nicely structured associative array
                    $customers = parent::buildMultiple('COUNTER\Customer', $array['Customer']);
                    return new self(
                        $array['ID'],
                        $array['Version'],
                        $array['Name'],
                        $array['Title'],
                        $customers,
                        Vendor::build($array['Vendor']),
                        $array['Created'] ?? ''
                    );
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('Report'));
            foreach (['Created', 'ID', 'Version', 'Name', 'Title'] as $arg) {
                $lcarg = strtolower($arg);
                $attrAttr = $doc->createAttribute($arg);
                $attrAttr->appendChild($doc->createTextNode($this->$lcarg));
                $root->appendChild($attrAttr);
            }
            $root->appendChild($doc->importNode($this->vendor->asDOMDocument()->documentElement, true));
            foreach ($this->customer as $customer) {
                $root->appendChild($doc->importNode($customer->asDOMDocument()->documentElement, true));
            }
            return $doc;
        }
    }

    /**
     * COUNTER vendor class
     */
    class Vendor extends ReportBuilder
    {
        /**
         * @var string Vendor element "Name"
         */
        private $name;
        /**
         * @var string Vendor element "ID"
         */
        private $id;
        /**
         * @var array zero or more COUNTER\Contact elements
         */
        private $contact = [];
        /**
         * @var string Vendor element "WebSiteUrl"
         */
        private $webSiteUrl;
        /**
         * @var string Vendor element "LogoUrl"
         */
        private $logoUrl;

        /**
         * Construct the object
         *
         * @param string $id
         * @param string $name optional
         * @param array $contacts optional COUNTER\Contact array
         * @param string $webSiteUrl optional
         * @param string $logoUrl optional
         *
         * @throws Exception
         */
        public function __construct($id, $name = '', $contacts = [], $webSiteUrl = '', $logoUrl = '')
        {
            foreach (['id', 'name', 'webSiteUrl', 'logoUrl'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            $this->contact = $this->validateZeroOrMoreOf($contacts, 'Contact');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['ID'])) {
                    // Nicely structured associative array
                    $contacts = parent::buildMultiple('COUNTER\Contact', $array['Contact'] ?? []);
                    return new self(
                        $array['ID'],
                        $array['Name'] ?? '',
                        $contacts,
                        $array['WebSiteUrl'] ?? '',
                        $array['LogoUrl'] ?? ''
                    );
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('Vendor'));
            if ($this->name) {
                $root->appendChild($doc->createElement('Name'))->appendChild($doc->createTextNode($this->name));
            }
            $root->appendChild($doc->createElement('ID'))->appendChild($doc->createTextNode($this->id));
            if ($this->contact) {
                foreach ($this->contact as $contact) {
                    $root->appendChild($doc->importNode($contact->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->webSiteUrl) {
                $root->appendChild($doc->createElement('WebSiteUrl'))->appendChild($doc->createTextNode($this->webSiteUrl));
            }
            if ($this->logoUrl) {
                $root->appendChild($doc->createElement('LogoUrl'))->appendChild($doc->createTextNode($this->logoUrl));
            }
            return $doc;
        }
    }

    /**
     * COUNTER contact class
     */
    class Contact extends ReportBuilder
    {
        /**
         * @var string Contact element "Contact"
         */
        private $contact;
        /**
         * @var string Contact element "Email"
         */
        private $email;

        /**
         * Construct the object
         *
         * @param string $contact optional
         * @param string $email optional
         *
         * @throws Exception
         */
        public function __construct($contact = '', $email = '')
        {
            foreach (['contact', 'email'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['E-mail'])) {
                    $array['Email'] = $array['E-mail'];
                    unset($array['E-mail']);
                }
                if (isset($array['Contact']) || isset($array['Email'])) {
                    return new self($array['Contact'] ? $array['Contact'] : '', $array['Email'] ? $array['Email'] : '');
                }
                if (count(array_keys($array)) == 1 && parent::isAssociative($array)) {
                    // Loosely structured associative array (name/email => name/email)
                    foreach ($array as $k => $v) {
                        if (filter_var($k, FILTER_VALIDATE_EMAIL)) {
                            // email => name
                            return new self($v, $k);
                        }
                        // name => email
                        return new self($k, $v);
                    }
                } elseif (count(array_keys($array)) == 1 && !parent::isAssociative($array)) {
                    // Loosely array with a name or email
                    if (filter_var($k, FILTER_VALIDATE_EMAIL)) {
                        // email
                        return new self('', $array[0]);
                    }
                    // name
                    return new self($array[0]);
                }
            } elseif (is_string($array)) {
                // Just a name or email
                if (filter_var($array, FILTER_VALIDATE_EMAIL)) {
                    // email
                    return new self('', $array);
                }
                // name
                return new self($array);
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('Contact'));
            if ($this->contact) {
                $root->appendChild($doc->createElement('Contact'))->appendChild($doc->createTextNode($this->contact));
            }
            if ($this->email) {
                $root->appendChild($doc->createElement('E-mail'))->appendChild($doc->createTextNode($this->email));
            }
            return $doc;
        }
    }

    /**
     * COUNTER customer class
     */
    class Customer extends ReportBuilder
    {
        /**
         * @var string Customer element "Name"
         */
        private $name;
        /**
         * @var string Customer element "ID"
         */
        private $id;
        /**
         * @var array zero or more COUNTER\Contact elements
         */
        private $contact;
        /**
         * @var string Customer element "WebSiteUrl"
         */
        private $webSiteUrl;
        /**
         * @var string Customer element "LogoUrl"
         */
        private $logoUrl;
        /**
         * @var string Customer element "Consortium"
         */
        private $consortium;
        /**
         * @var array zero or more COUNTER\Identifier elements
         */
        private $institutionalIdentifier;
        /**
         * @var array one or more COUNTER\ReportItem elements
         */
        private $reportItems;

        /**
         * Construct the object
         *
         * @param string $id
         * @param array $reportItems COUNTER\ReportItems array
         * @param string $name optional
         * @param array $contacts optional COUNTER\Contacts array
         * @param string $webSiteUrl optional
         * @param string $logoUrl optional
         * @param object $consortium optional COUNTER\Consortium
         * @param array $institutionalIdentifier optional COUNTER\Identifier array
         *
         * @throws Exception
         */
        public function __construct($id, $reportItems, $name = '', $contacts = [], $webSiteUrl = '', $logoUrl = '', $consortium = null, $institutionalIdentifier = [])
        {
            foreach (['id', 'name', 'webSiteUrl', 'logoUrl'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            $this->reportItems = $this->validateOneOrMoreOf($reportItems, 'ReportItems');
            $this->contact = $this->validateZeroOrMoreOf($contacts, 'Contact');
            $this->consortium = $this->validateZeroOrOneOf($consortium, 'Consortium');
            $this->institutionalIdentifier = $this->validateZeroOrMoreOf($institutionalIdentifier, 'Identifier');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['ID']) && isset($array['ReportItems'])) {
                    // Nicely structured associative array
                    $items = parent::buildMultiple('COUNTER\ReportItems', $array['ReportItems']);
                    $ids = parent::buildMultiple('COUNTER\Identifier', $array['InstitutionalIdentifier'] ?? []);
                    $contacts = parent::buildMultiple('COUNTER\Contact', $array['Contact'] ?? []);
                    return new self(
                        $array['ID'],
                        $items,
                        $array['Name'] ?? '',
                        $contacts,
                        $array['WebSiteUrl'] ?? '',
                        $array['LogoUrl'] ?? '',
                        isset($array['Consortium']) ? Consortium::build($array['Consortium']) : null,
                        $ids
                    );
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('Customer'));
            if ($this->name) {
                $root->appendChild($doc->createElement('Name'))->appendChild($doc->createTextNode($this->name));
            }
            $root->appendChild($doc->createElement('ID'))->appendChild($doc->createTextNode($this->id));
            if ($this->contact) {
                foreach ($this->contact as $contact) {
                    $root->appendChild($doc->importNode($contact->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->webSiteUrl) {
                $root->appendChild($doc->createElement('WebSiteUrl'))->appendChild($doc->createTextNode($this->webSiteUrl));
            }
            if ($this->logoUrl) {
                $root->appendChild($doc->createElement('LogoUrl'))->appendChild($doc->createTextNode($this->logoUrl));
            }
            if ($this->consortium) {
                $root->appendChild($doc->importNode($this->consortium->asDOMDocument()->documentElement, true));
            }
            if ($this->institutionalIdentifier) {
                foreach ($this->institutionalIdentifier as $id) {
                    $root->appendChild($doc->importNode($id->asDOMDocument()->documentElement, true));
                }
            }
            foreach ($this->reportItems as $rep) {
                $root->appendChild($doc->importNode($rep->asDOMDocument()->documentElement, true));
            }
            return $doc;
        }
    }

    /**
     * COUNTER consortium class
     */
    class Consortium extends ReportBuilder
    {
        /**
         * @var string Consortium element "Code"
         */
        private $code;
        /**
         * @var string Consortium element "WellKnownName"
         */
        private $wellKnownName;

        /**
         * Construct the object
         *
         * @param string $wellKnownName
         * @param string $code optional
         */
        public function __construct($wellKnownName, $code = '')
        {
            foreach (['wellKnownName', 'code'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['WellKnownName'])) {
                    // Nicely structured associative array
                    return new self($array['WellKnownName'], $array['Code'] ? $array['Code'] : '');
                }
                if (count(array_keys($array)) == 1 && parent::isAssociative($array)) {
                    // Loosely structured associative array (name => code)
                    foreach ($array as $k => $v) {
                        return new self($k, $v);
                    }
                } elseif (count(array_keys($array)) == 1 && !parent::isAssociative($array)) {
                    // Loosely array with a name
                    return new self($array[0]);
                }
            } elseif (is_string($array)) {
                // Just a name
                return new self($array);
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('Consortium'));
            if ($this->code) {
                $root->appendChild($doc->createElement('Code'))->appendChild($doc->createTextNode($this->code));
            }
            $root->appendChild($doc->createElement('WellKnownName'))->appendChild($doc->createTextNode($this->wellKnownName));
            return $doc;
        }
    }

    /**
     * COUNTER report item class
     */
    class ReportItems extends ReportBuilder
    {
        /**
         * @var COUNTER\ParentItem ReportItem element "ParentItem"
         */
        private $parentItem;
        /**
         * @var array zero or more COUNTER\Identifier elements
         */
        private $itemIdentifier;
        /**
         * @var array zero or more COUNTER\ItemContributor elements
         */
        private $itemContributor;
        /**
         * @var array zero or more COUNTER\ItemDate elements
         */
        private $itemDate;
        /**
         * @var array zero or more COUNTER\ItemAttribute elements
         */
        private $itemAttribute;
        /**
         * @var string ReportItem element "ItemPlatform"
         */
        private $itemPlatform;
        /**
         * @var string ReportItem element "ItemPublisher"
         */
        private $itemPublisher;
        /**
         * @var string ReportItem element "ItemName"
         */
        private $itemName;
        /**
         * @var COUNTER\ItemDataType ReportItem element "ItemData"
         */
        private $itemDataType;
        /**
         * @var array one or more COUNTER\Metric elements
         */
        private $itemPerformance;

        /**
         * Construct the object
         *
         * @param string $itemPlatform
         * @param string $itemName
         * @param string $itemDataType
         * @param array $itemPerformance COUNTER\Metric array
         * @param object $parentItem optional COUNTER\ParentItem
         * @param array $itemIdentifiers optional COUNTER\Identifier array
         * @param array $itemContributors optional COUNTER\Contributor array
         * @param array $itemDates optional COUNTER\Date array
         * @param array $itemAttributes optional COUNTER\ItemAttribute array
         * @param string $itemPublisher optional
         *
         * @throws Exception
         */
        public function __construct($itemPlatform, $itemName, $itemDataType, $itemPerformance, $parentItem = null, $itemIdentifiers = [], $itemContributors = [], $itemDates = [], $itemAttributes = [], $itemPublisher = '')
        {
            foreach (['itemPlatform', 'itemPublisher', 'itemName', 'itemDataType'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            if (!in_array($itemDataType, $this->getItemDataTypes())) {
                throw new \Exception('Invalid item data type: ' . $itemDataType);
            }
            $this->itemPerformance = $this->validateOneOrMoreOf($itemPerformance, 'Metric');
            $this->parentItem = $this->validateZeroOrOneOf($parentItem, 'ParentItem');
            $this->itemIdentifier = $this->validateZeroOrMoreOf($itemIdentifiers, 'Identifier');
            $this->itemContributor = $this->validateZeroOrMoreOf($itemContributors, 'ItemContributor');
            $this->itemDate = $this->validateZeroOrMoreOf($itemDates, 'ItemDate');
            $this->itemAttribute = $this->validateZeroOrMoreOf($itemAttributes, 'ItemAttribute');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['ItemPlatform']) && isset($array['ItemName']) && isset($array['ItemDataType']) && isset($array['ItemPerformance'])) {
                    // Nicely structured associative array
                    $performance = parent::buildMultiple('COUNTER\Metric', $array['ItemPerformance']);
                    $ids = parent::buildMultiple('COUNTER\Identifier', $array['ItemIdentifier'] ?? []);
                    $contributors = parent::buildMultiple('COUNTER\ItemContributor', $array['ItemContributor'] ?? []);
                    $dates = parent::buildMultiple('COUNTER\ItemDate', $array['ItemDate'] ?? []);
                    $attributes = parent::buildMultiple('COUNTER\ItemAttribute', $array['ItemAttribute'] ?? []);
                    return new self(
                        $array['ItemPlatform'],
                        $array['ItemName'],
                        $array['ItemDataType'],
                        $performance,
                        isset($array['ParentItem']) ? ParentItem::build($array['ParentItem']) : null,
                        $ids,
                        $contributors,
                        $dates,
                        $attributes,
                        $array['ItemPublisher'] ?? ''
                    );
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ReportItems'));
            if ($this->parentItem) {
                $root->appendChild($doc->importNode($this->parentItem->asDOMDocument()->documentElement, true));
            }
            if ($this->itemIdentifier) {
                foreach ($this->itemIdentifier as $id) {
                    $root->appendChild($doc->importNode($id->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemContributor) {
                foreach ($this->itemContributor as $contrib) {
                    $root->appendChild($doc->importNode($contrib->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemDate) {
                foreach ($this->itemDate as $date) {
                    $root->appendChild($doc->importNode($date->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemAttribute) {
                foreach ($this->itemAttribute as $attrib) {
                    $root->appendChild($doc->importNode($attrib->asDOMDocument()->documentElement, true));
                }
            }
            $root->appendChild($doc->createElement('ItemPlatform'))->appendChild($doc->createTextNode($this->itemPlatform));
            if ($this->itemPublisher) {
                $root->appendChild($doc->createElement('ItemPublisher'))->appendChild($doc->createTextNode($this->itemPublisher));
            }
            $root->appendChild($doc->createElement('ItemName'))->appendChild($doc->createTextNode($this->itemName));
            $root->appendChild($doc->createElement('ItemDataType'))->appendChild($doc->createTextNode($this->itemDataType));
            foreach ($this->itemPerformance as $perf) {
                $root->appendChild($doc->importNode($perf->asDOMDocument()->documentElement, true));
            }
            return $doc;
        }
    }

    /**
     * COUNTER parent item class
     */
    class ParentItem extends ReportBuilder
    {
        /**
         * @var array zero or more COUNTER\Identifier elements
         */
        private $itemIdentifier;
        /**
         * @var array zero or more COUNTER\ItemContributor elements
         */
        private $itemContributor;
        /**
         * @var array zero or more COUNTER\ItemDate elements
         */
        private $itemDate;
        /**
         * @var array zero or more COUNTER\ItemAttribute elements
         */
        private $itemAttribute;
        /**
         * @var string ParentItem element "ItemPublisher"
         */
        private $itemPublisher;
        /**
         * @var string ParentItem element "ItemName"
         */
        private $itemName;
        /**
         * @var COUNTER\DataType ParentItem element "ItemDataType"
         */
        private $itemDataType;

        /**
         * Construct the object
         *
         * @param string $itemName
         * @param string $itemDataType
         * @param array $itemIdentifiers optional COUNTER\Identifier array
         * @param array $itemContributors optional COUNTER\ItemContributor array
         * @param array $itemDates optional COUNTER\ItemDate array
         * @param array $itemAttributes optional COUNTER\ItemAttribute array
         * @param string $itemPublisher optional
         *
         * @throws Exception
         */
        public function __construct($itemName, $itemDataType, $itemIdentifiers = [], $itemContributors = [], $itemDates = [], $itemAttributes = [], $itemPublisher = '')
        {
            foreach (['itemName', 'itemDataType', 'itemPublisher'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            if (!in_array($itemDataType, $this->getItemDataTypes())) {
                throw new \Exception('Invalid type: ' . $type);
            }
            $this->itemIdentifier = $this->validateZeroOrMoreOf($itemIdentifiers, 'Identifier');
            $this->itemContributor = $this->validateZeroOrMoreOf($itemContributors, 'ItemContributor');
            $this->itemDate = $this->validateZeroOrMoreOf($itemDates, 'ItemDate');
            $this->itemAttribute = $this->validateZeroOrMoreOf($itemAttributes, 'ItemAttribute');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['ItemName']) && isset($array['ItemDataType'])) {
                    // Nicely structured associative array
                    $ids = parent::buildMultiple('COUNTER\Identifier', $array['ItemIdentifier'] ?? []);
                    $contributors = parent::buildMultiple('COUNTER\ItemContributor', $array['ItemContributor'] ?? []);
                    $dates = parent::buildMultiple('COUNTER\ItemDate', $array['ItemDate'] ?? []);
                    $attributes = parent::buildMultiple('COUNTER\ItemAttribute', $array['ItemAttribute'] ?? []);
                    return new self(
                        $array['ItemName'],
                        $array['ItemDataType'],
                        $ids,
                        $contributors,
                        $dates,
                        $attributes,
                        $array['ItemPublisher'] ?? ''
                    );
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ParentItem'));
            if ($this->itemIdentifier) {
                foreach ($this->itemIdentifier as $id) {
                    $root->appendChild($doc->importNode($id->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemContributor) {
                foreach ($this->itemContributor as $contrib) {
                    $root->appendChild($doc->importNode($contrib->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemDate) {
                foreach ($this->itemDate as $date) {
                    $root->appendChild($doc->importNode($date->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemAttribute) {
                foreach ($this->itemAttribute as $attrib) {
                    $root->appendChild($doc->importNode($attrib->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemPublisher) {
                $root->appendChild($doc->createElement('ItemPublisher'))->appendChild($doc->createTextNode($this->itemPublisher));
            }
            $root->appendChild($doc->createElement('ItemName'))->appendChild($doc->createTextNode($this->itemName));
            $root->appendChild($doc->createElement('ItemDataType'))->appendChild($doc->createTextNode($this->itemDataType));
            return $doc;
        }
    }

    /**
     * COUNTER item contributor class
     */
    class ItemContributor extends ReportBuilder
    {
        /**
         * @var array zero or more COUNTER\ItemContributorID elements
         */
        private $itemContributorId;
        /**
         * @var string ItemContributor element "Name"
         */
        private $itemContributorName;
        /**
         * @var string ItemContributor element "Affiliation"
         */
        private $itemContributorAffiliation;
        /**
         * @var string ItemContributor element "Role"
         */
        private $itemContributorRole;

        /**
         * Construct the object
         *
         * @param array $itemContributorIds optional COUNTER\ContributorId array
         * @param string $itemContributorName optional
         * @param array $itemContributorAffiliations optional string array
         * @param array $itemContributorRoles optional string array
         *
         * @throws Exception
         */
        public function __construct($itemContributorIds = [], $itemContributorName = '', $itemContributorAffiliations = [], $itemContributorRoles = [])
        {
            $this->itemContributorId = $this->validateZeroOrMoreOf($itemContributorIds, 'ItemContributorId');
            $this->itemContributorName = $this->validateString($itemContributorName);
            $this->itemContributorAffiliation = $this->validateStrings($itemContributorAffiliations);
            $this->itemContributorRole = $this->validateStrings($itemContributorRoles);
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['ItemContributorID']) || isset($array['ItemContributorName']) || isset($array['ItemContributorAffiliation']) || isset($array['ItemContributorRole'])) {
                    // Nicely structured associative array
                    $ids = parent::buildMultiple('COUNTER\ItemContributorId', $array['ItemContributorID'] ?? []);
                    return new self(
                        $ids,
                        $array['ItemContributorName'] ?? '',
                        $array['ItemContributorAffiliation'] ?? '',
                        $array['ItemContributorRole'] ?? ''
                    );
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ItemContributor'));
            if ($this->itemContributorId) {
                foreach ($this->itemContributorId as $id) {
                    $root->appendChild($doc->importNode($id->asDOMDocument()->documentElement, true));
                }
            }
            if ($this->itemContributorName) {
                $root->appendChild($doc->createElement('ItemContributorName'))->appendChild($doc->createTextNode($this->itemContributorName));
            }
            if ($this->itemContributorAffiliation) {
                foreach ($this->itemContributorAffiliation as $affiliation) {
                    $root->appendChild($doc->createElement('ItemContributorAffiliation', $affiliation));
                }
            }
            if ($this->itemContributorRole) {
                foreach ($this->itemContributorRole as $role) {
                    $root->appendChild($doc->createElement('ItemContributorRole', $role));
                }
            }
            return $doc;
        }
    }

    /**
     * COUNTER contributor id class
     */
    class ItemContributorId extends ReportBuilder
    {
        /**
         * @var string ItemContributorID element "Type"
         */
        private $type;
        /**
         * @var string ItemContributorID element "Value"
         */
        private $value;

        /**
         * Construct the object
         *
         * @param string $type
         * @param string $value
         *
         * @throws Exception
         */
        public function __construct($type, $value)
        {
            foreach (['type', 'value'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            if (!in_array($type, $this->getContributorIdentifierTypes())) {
                throw new \Exception('Invalid type: ' . $type);
            }
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['Type']) && isset($array['Value'])) {
                    // Nicely structured associative array
                    return new self($array['Type'], $array['Value']);
                }
                if (count(array_keys($array)) == 1 && parent::isAssociative($array)) {
                    // Loosely structured associative array (type => value)
                    foreach ($array as $k => $v) {
                        return new self($k, $v);
                    }
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ItemContributorID'));
            $root->appendChild($doc->createElement('Type'))->appendChild($doc->createTextNode($this->type));
            $root->appendChild($doc->createElement('Value'))->appendChild($doc->createTextNode($this->value));
            return $doc;
        }
    }

    /**
     * COUNTER item identifier class
     */
    class Identifier extends ReportBuilder
    {
        /**
         * @var string Identifier element "Type"
         */
        private $type;
        /**
         * @var string Identifier element "Type"
         */
        private $value;

        /**
         * Construct the object
         *
         * @param string $type
         * @param string $value
         *
         * @throws Exception
         */
        public function __construct($type, $value)
        {
            foreach (['type', 'value'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            if (!in_array($type, $this->getIdentifierTypes())) {
                throw new \Exception('Invalid type: ' . $type);
            }
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['Type']) && isset($array['Value'])) {
                    // Nicely structured associative array
                    return new self($array['Type'], $array['Value']);
                }
                if (count(array_keys($array)) == 1 && parent::isAssociative($array)) {
                    // Loosely structured associative array (type => value)
                    foreach ($array as $k => $v) {
                        return new self($k, $v);
                    }
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ItemIdentifier'));
            $root->appendChild($doc->createElement('Type'))->appendChild($doc->createTextNode($this->type));
            $root->appendChild($doc->createElement('Value'))->appendChild($doc->createTextNode($this->value));
            return $doc;
        }
    }

    /**
     * COUNTER item date class
     */
    class ItemDate extends ReportBuilder
    {
        /**
         * @var string ItemDate element "Type"
         */
        private $type;
        /**
         * @var string ItemDate element "Value"
         */
        private $value;

        /**
         * Construct the object
         *
         * @param string $type
         * @param string $value
         *
         * @throws Exception
         */
        public function __construct($type, $value)
        {
            $this->type = $this->validateString($type);
            if (!in_array($type, $this->getDateTypes())) {
                throw new \Exception('Invalid type: ' . $type);
            }
            $this->value = $this->validateOneOf($value, '\DateTime');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['Type']) && isset($array['Value'])) {
                    // Nicely structured associative array
                    return new self($array['Type'], $array['Value']);
                }
                if (count(array_keys($array)) == 1 && parent::isAssociative($array)) {
                    // Loosely structured associative array (type => value)
                    foreach ($array as $k => $v) {
                        return new self($k, $v);
                    }
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ItemDate'));
            $root->appendChild($doc->createElement('Type'))->appendChild($doc->createTextNode($this->type));
            $root->appendChild($doc->createElement('Value'))->appendChild($doc->createTextNode(date_format($this->value, 'Y-m-d')));
            return $doc;
        }
    }

    /**
     * COUNTER item attribute class
     */
    class ItemAttribute extends ReportBuilder
    {
        /**
         * @var string ItemAttribute element "Type"
         */
        private $type;
        /**
         * @var string ItemAttribute element "Value"
         */
        private $value;

        /**
         * Construct the object
         *
         * @param string $type
         * @param string $value
         *
         * @throws Exception
         */
        public function __construct($type, $value)
        {
            foreach (['type', 'value'] as $arg) {
                $this->$arg = $this->validateString($$arg);
            }
            if (!in_array($type, $this->getAttributeTypes())) {
                throw new \Exception('Invalid type: ' . $type);
            }
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['Type']) && isset($array['Value'])) {
                    // Nicely structured associative array
                    return new self($array['Type'], $array['Value']);
                }
                if (count(array_keys($array)) == 1 && parent::isAssociative($array)) {
                    // Loosely structured associative array (type => value)
                    foreach ($array as $k => $v) {
                        return new self($k, $v);
                    }
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ItemAttribute'));
            $root->appendChild($doc->createElement('Type'))->appendChild($doc->createTextNode($this->type));
            $root->appendChild($doc->createElement('Value'))->appendChild($doc->createTextNode($this->value));
            return $doc;
        }
    }

    /**
     * COUNTER performance counter class
     */
    class Metric extends ReportBuilder
    {
        /**
         * @var int Metric element "PubYr"
         */
        private $pubYr;
        /**
         * @var int Metric element "PubYrFrom"
         */
        private $pubYrFrom;
        /**
         * @var int Metric element "PubYrTo"
         */
        private $pubYrTo;
        /**
         * @var COUNTER\DateRange Metric element "Period"
         */
        private $period;
        /**
         * @var COUNTER\Category Metric element "Category"
         */
        private $category;
        /**
         * @var array one or more COUNTER\PerformanceCounter elements
         */
        private $instance;

        /**
         * Construct the object
         *
         * @param array $period COUNTER\DateRange array
         * @param array $category COUNTER\Category array
         * @param array $instances COUNTER\PerformanceCounter array
         * @param int $pubYrFrom optional
         * @param int $pubYrTo optional
         * @param int $pubYr optional
         * @param null|mixed $pubYrFrom
         * @param null|mixed $pubYrTo
         * @param null|mixed $pubYr
         *
         * @throws Exception
         */
        public function __construct($period, $category, $instances, $pubYrFrom = null, $pubYrTo = null, $pubYr = null)
        {
            $this->period = $this->validateOneOf($period, 'DateRange');
            $this->category = $this->validateString($category);
            if (!in_array($category, $this->getCategories())) {
                throw new \Exception('Invalid category: ' . $category);
            }
            $this->instance = $this->validateOneOrMoreOf($instances, 'PerformanceCounter');
            if ($pubYrFrom) {
                $this->pubYrFrom = $this->validatePositiveInteger($pubYrFrom);
            }
            if ($pubYrTo) {
                $this->pubYrTo = $this->validatePositiveInteger($pubYrTo);
            }
            if ($pubYr) {
                $this->pubYr = $this->validatePositiveInteger($pubYr);
            }
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['Period']) && isset($array['Instance']) && isset($array['Category'])) {
                    // Nicely structured associative array
                    $instances = parent::buildMultiple('COUNTER\PerformanceCounter', $array['Instance']);
                    return new self(
                        DateRange::build($array['Period']),
                        $array['Category'],
                        $instances,
                        $array['PubYrFrom'] ?? null,
                        $array['PubYrTo'] ?? null,
                        $array['PubYr'] ?? null
                    );
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('ItemPerformance'));
            if ($this->period) {
                $root->appendChild($doc->importNode($this->period->asDOMDocument()->documentElement, true));
            }
            if ($this->category) {
                $root->appendChild($doc->createElement('Category'))->appendChild($doc->createTextNode($this->category));
            }
            foreach ($this->instance as $instance) {
                $root->appendChild($doc->importNode($instance->asDOMDocument()->documentElement, true));
            }
            foreach (['pubYr', 'pubYrFrom', 'pubYrTo'] as $pubYrKey) {
                if ($this->$pubYrKey) {
                    $root->appendChild($doc->createElement(ucfirst($pubYrKey)))->appendChild($doc->createTextNode($this->$pubYrKey));
                    $attr = $doc->createAttribute(ucfirst($pubYrKey));
                    $attr->value = $this->$pubYrKey;
                    $root->appendChild($attr);
                }
            }
            return $doc;
        }
    }

    /**
     * COUNTER date range class
     */
    class DateRange extends ReportBuilder
    {
        /**
         * @var \DateTime DateRange element "Begin"
         */
        private $begin;
        /**
         * @var \DateTime DateRange element "End"
         */
        private $end;

        /**
         * Construct the object
         *
         * @param DateTime $begin
         * @param DateTime $end
         *
         * @throws Exception
         */
        public function __construct($begin, $end)
        {
            $this->begin = $this->validateOneOf($begin, '\DateTime');
            $this->end = $this->validateOneOf($end, '\DateTime');
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['Begin']) && isset($array['End'])) {
                    // Nicely structured associative array
                    return new self($array['Begin'], $array['End']);
                }
                if (count(array_keys($array)) == 2 && !parent::isAssociative($array)) {
                    // Unstructured array of two elements, assume begin and end dates
                    return new self($array[0], $array[1]);
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('Period'));
            $root->appendChild($doc->createElement('Begin'))->appendChild($doc->createTextNode(date_format($this->begin, 'Y-m-d')));
            $root->appendChild($doc->createElement('End'))->appendChild($doc->createTextNode(date_format($this->end, 'Y-m-d')));
            return $doc;
        }
    }

    /**
     * COUNTER performance counter class
     */
    class PerformanceCounter extends ReportBuilder
    {
        /**
         * @var COUNTER\MetricType PerformanceCounter element "MetricType"
         */
        private $metricType;
        /**
         * @var int PerformanceCounter element "Count"
         */
        private $count;

        /**
         * Construct the object
         *
         * @param string $metricType
         * @param int $count
         *
         * @throws Exception
         */
        public function __construct($metricType, $count)
        {
            $this->metricType = $this->validateString($metricType);
            if (!in_array($metricType, $this->getMetricTypes())) {
                throw new \Exception('Invalid metric type: ' . $metricType);
            }
            $this->count = $this->validatePositiveInteger($count);
        }

        /**
         * Construct the object from an array
         *
         * @param array $array Hash of key-values
         *
         * @throws Exception
         *
         * @return \self
         */
        public static function build($array)
        {
            if (is_array($array)) {
                if (isset($array['MetricType']) && isset($array['Count'])) {
                    // Nicely structured associative array
                    return new self($array['MetricType'], $array['Count']);
                }
                if (count(array_keys($array)) == 1 && parent::isAssociative($array)) {
                    // Loosely structured associative array (type => count)
                    foreach ($array as $k => $v) {
                        return new self($k, $v);
                    }
                }
            }
            parent::build($array);
        }

        /**
         * Output this object as a DOMDocument
         *
         * @return DOMDocument
         */
        public function asDOMDocument()
        {
            $doc = new \DOMDocument();
            $root = $doc->appendChild($doc->createElement('Instance'));
            $root->appendChild($doc->createElement('MetricType'))->appendChild($doc->createTextNode($this->metricType));
            $root->appendChild($doc->createElement('Count'))->appendChild($doc->createTextNode($this->count));
            return $doc;
        }
    }

}

3g86 2022