Initial commit

This commit is contained in:
2019-11-20 07:44:43 +01:00
commit 5bf49c4a81
41188 changed files with 5459177 additions and 0 deletions

10
web/vendor/.htaccess vendored Normal file
View File

@@ -0,0 +1,10 @@
# Apache 2.2
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
Require all denied
</IfModule>

21
web/vendor/analog/analog/LICENSE vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2012 Johnny Broadway
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,155 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
/**
* SplClassLoader implementation that implements the technical interoperability
* standards for PHP 5.3 namespaces and class names.
*
* http://groups.google.com/group/php-standards/web/psr-0-final-proposal?pli=1
*
* // Example which loads classes for the Doctrine Common package in the
* // Doctrine\Common namespace.
* $classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine');
* $classLoader->register();
*
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman S. Borschel <roman@code-factory.org>
* @author Matthew Weier O'Phinney <matthew@zend.com>
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
* @author Fabien Potencier <fabien.potencier@symfony-project.org>
*/
class SplClassLoader
{
private $_fileExtension = '.php';
private $_namespace;
private $_includePath;
private $_namespaceSeparator = '\\';
/**
* Creates a new <tt>SplClassLoader</tt> that loads classes of the
* specified namespace.
*
* @param string $ns The namespace to use.
*/
public function __construct($ns = null, $includePath = null)
{
$this->_namespace = $ns;
$this->_includePath = $includePath;
}
/**
* Sets the namespace separator used by classes in the namespace of this class loader.
*
* @param string $sep The separator to use.
*/
public function setNamespaceSeparator($sep)
{
$this->_namespaceSeparator = $sep;
}
/**
* Gets the namespace seperator used by classes in the namespace of this class loader.
*
* @return void
*/
public function getNamespaceSeparator()
{
return $this->_namespaceSeparator;
}
/**
* Sets the base include path for all class files in the namespace of this class loader.
*
* @param string $includePath
*/
public function setIncludePath($includePath)
{
$this->_includePath = $includePath;
}
/**
* Gets the base include path for all class files in the namespace of this class loader.
*
* @return string $includePath
*/
public function getIncludePath()
{
return $this->_includePath;
}
/**
* Sets the file extension of class files in the namespace of this class loader.
*
* @param string $fileExtension
*/
public function setFileExtension($fileExtension)
{
$this->_fileExtension = $fileExtension;
}
/**
* Gets the file extension of class files in the namespace of this class loader.
*
* @return string $fileExtension
*/
public function getFileExtension()
{
return $this->_fileExtension;
}
/**
* Installs this class loader on the SPL autoload stack.
*/
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
}
/**
* Uninstalls this class loader from the SPL autoloader stack.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $className The name of the class to load.
* @return void
*/
public function loadClass($className)
{
if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) {
$fileName = '';
$namespace = '';
if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension;
require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName;
}
}
}

View File

@@ -0,0 +1,16 @@
<?php
// 1. Install the Amon PHP lib from http://amon.cx/guide/clients/php/
require 'amon.php';
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Amon::init (
'http://127.0.0.1',
2464
));
Analog::log ('Error message');
Analog::log ('Debug info', Analog::DEBUG);
?>

View File

@@ -0,0 +1,18 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Buffer::init (
Analog\Handler\Mail::init (
'you@example.com',
'Log messages',
'noreply@example.com'
)
));
// will all be sent as one email instead of three
Analog::log ('Message one');
Analog::log ('Message two');
Analog::log ('Message three');
?>

View File

@@ -0,0 +1,19 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\ChromeLogger::init ());
// debug-level message
Analog::debug ($_SERVER);
// an info message
Analog::info ('An error message');
// a warning message
Analog::warning ('Turn back before it\'s too late');
// an error with no file/line #'s
Analog::log ('Another error message');
?>

View File

@@ -0,0 +1,11 @@
<?php
require '../lib/Analog.php';
Analog::log ('foo');
Analog::log ('bar');
echo file_get_contents (Analog::handler ());
unlink (Analog::handler ());
?>

View File

@@ -0,0 +1,15 @@
<?php
require '../lib/Analog.php';
$log_file = 'log.txt';
Analog::handler (Analog\Handler\File::init ($log_file));
Analog::log ('foo');
Analog::log ('bar');
echo file_get_contents ($log_file);
unlink ($log_file);
?>

View File

@@ -0,0 +1,16 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\FirePHP::init ());
// debug-level message
Analog::log (array ('A debug message', __FILE__, __LINE__), Analog::DEBUG);
// an info message
Analog::log (array ('An error message', __FILE__, __LINE__), Analog::INFO);
// an error with no file/line #'s
Analog::log ('Another error message');
?>

View File

@@ -0,0 +1,16 @@
<?php
// 1. Install the GELF classes from https://github.com/Graylog2/gelf-php
require 'GELFMessage.php';
require 'GELFMessagePublisher.php';
require '../lib/Analog.php';
Analog::handler (Analog\Handler\GELF::init (
'localhost'
));
Analog::log ('Error message');
Analog::log (array ('Debug info', __FILE__, __LINE__), Analog::DEBUG);
?>

View File

@@ -0,0 +1,9 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Ignore::init ());
Analog::log ('Hellooooooo');
?>

View File

@@ -0,0 +1,24 @@
<?php
require '../lib/Analog.php';
$log = '';
Analog::handler (Analog\Handler\LevelBuffer::init (
Analog\Handler\Variable::init ($log),
Analog::CRITICAL
));
// none of these will trigger sending the log
Analog::log ('Debugging...', Analog::DEBUG);
Analog::log ('Minor warning...', Analog::WARNING);
Analog::log ('An error...', Analog::ERROR);
echo "Log is still empty:\n" . $log . "\n";
// but this will, and will include all the others in the log
Analog::log ('Oh noes!', Analog::URGENT);
echo "Log now has everything:\n" . $log;
?>

View File

@@ -0,0 +1,13 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Mail::init (
'you@example.com',
'Log message',
'noreply@example.com'
));
Analog::log ('Error message');
?>

View File

@@ -0,0 +1,21 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Mongo::init (
'localhost:27017',
'testing',
'log'
));
Analog::log ('Error message');
Analog::log ('Debug info', Analog::DEBUG);
$m = new MongoClient ('mongodb://localhost:27017');
$cur = $m->testing->log->find ();
foreach ($cur as $doc) {
print_r ($doc);
}
$m->testing->log->remove ();
?>

View File

@@ -0,0 +1,27 @@
<?php
require '../lib/Analog.php';
$errors = "Errors:\n";
$warnings = "Warnings:\n";
$debug = "Debug:\n";
Analog::handler (Analog\Handler\Multi::init (array (
Analog::ERROR => Analog\Handler\Variable::init ($errors),
Analog::WARNING => Analog\Handler\Variable::init ($warnings),
Analog::DEBUG => Analog\Handler\Variable::init ($debug)
)));
Analog::log ('First error');
Analog::log ('Emergency!', Analog::URGENT);
Analog::log ('A warning...', Analog::WARNING);
Analog::log ('Some info', Analog::INFO);
Analog::log ('Debugging output', Analog::DEBUG);
echo $errors;
echo "-----\n";
echo $warnings;
echo "-----\n";
echo $debug;
?>

View File

@@ -0,0 +1,14 @@
<?php
require '../lib/Analog.php';
$log = '';
Analog::handler (Analog\Handler\Post::init ('http://localhost:8080/'));
Analog::log ('foo');
Analog::log ('bar');
echo $log;
?>

View File

@@ -0,0 +1,19 @@
<?php
require 'SplClassLoader.php';
$loader = new SplClassLoader ('Analog', '../lib');
$loader->register ();
use \Analog\Analog;
$log = '';
Analog::handler (\Analog\Handler\Variable::init ($log));
Analog::log ('Test one');
Analog::log ('Test two');
echo $log;
?>

View File

@@ -0,0 +1,13 @@
<?php
/**
* This works with test_post.php to verify sent data.
* Run me via:
*
* php -S localhost:8080 server.php
*
* Note: Requires PHP 5.4+
*/
file_put_contents ('php://stdout', 'Logged: ' . join (' - ', $_POST) . "\n");
?>

View File

@@ -0,0 +1,9 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Slackbot::init ('teamname', 'token', 'channel'));
Analog::log ('Error message', Analog::WARNING);
?>

View File

@@ -0,0 +1,9 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Stderr::init ());
Analog::log ('Output to php://stderr');
?>

View File

@@ -0,0 +1,9 @@
<?php
require '../lib/Analog.php';
Analog::handler (Analog\Handler\Syslog::init ('analog', 'user'));
Analog::log ('Error message', Analog::WARNING);
?>

View File

@@ -0,0 +1,24 @@
<?php
require '../lib/Analog.php';
$log = '';
Analog::handler (Analog\Handler\Threshold::init (
Analog\Handler\Variable::init ($log),
Analog::ERROR
));
// these will be ignored
Analog::log ('Debugging...', Analog::DEBUG);
Analog::log ('Minor warning...', Analog::WARNING);
echo "Log is still empty:\n" . $log . "\n";
// but these will be logged
Analog::log ('An error...', Analog::ERROR);
Analog::log ('Oh noes!', Analog::URGENT);
echo "Log now has everything:\n" . $log;
?>

View File

@@ -0,0 +1,14 @@
<?php
require '../lib/Analog.php';
$log = '';
Analog::handler (Analog\Handler\Variable::init ($log));
Analog::log ('foo');
Analog::log ('bar');
echo $log;
?>

22
web/vendor/analog/analog/lib/Analog.php vendored Normal file
View File

@@ -0,0 +1,22 @@
<?php
/**
* Register a very simple autoloader for the pre-built handlers
* based on the current working directory.
*/
spl_autoload_register (function ($class) {
$file = str_replace ('\\', DIRECTORY_SEPARATOR, ltrim ($class, '\\')) . '.php';
if (file_exists (__DIR__ . DIRECTORY_SEPARATOR . $file)) {
require_once $file;
return true;
}
return false;
});
/**
* We simply alias extend the main class so that Analog is
* available as a global class. This saves us adding
* `use \Analog\Analog` at the top of every file,
* or worse, typeing `\Analog\Analog::log()` everywhere.
*/
class_alias ('\Analog\Analog', 'Analog');

View File

@@ -0,0 +1,265 @@
<?php
namespace Analog;
/**
* Analog - PHP 5.3+ logging class
*
* Copyright (c) 2012 Johnny Broadway
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A short and simple logging class for based on the idea of using closures for
* configurability and extensibility. Functions as a static class, but you can
* completely control the formatting and writing of log messages through closures.
*
* By default, this class will write to a file named /tmp/log.txt using a format
* "machine - date - level - message\n".
*
* I wrote this because I wanted something simple and small like KLogger, and
* preferably not torn out of a wider framework if possible. After searching,
* I wasn't happy with the single-purpose libraries I found. With KLogger for
* example, I didn't want an object instance but rather a static class, and I
* wanted more flexibility in the back-end.
*
* I also found that the ones that had really flexible back-ends supported a lot
* that I could never personally foresee needing, and could be easier to extend
* with new back-ends that may be needed over time. Closures seem a natural fit for
* this kind of thing.
*
* What about Analog, the logfile analyzer? Well, since it hasn't been updated
* since 2004, I think it's safe to call a single-file PHP logging class the
* same thing without it being considered stepping on toes :)
*
* Usage:
*
* <?php
*
* require_once ('Analog.php');
*
* // Default logging to /tmp/analog.txt
* Analog::log ('Log this error');
*
* // Log to a MongoDB log collection
* Analog::handler (function ($info) {
* static $conn = null;
* if (! $conn) {
* $conn = new Mongo ('localhost:27017');
* }
* $conn->mydb->log->insert ($info);
* });
*
* // Log an alert
* Analog::log ('The sky is falling!', Analog::ALERT);
*
* // Log some debug info
* Analog::log ('Debugging info', Analog::DEBUG);
*
* ?>
*
* @package Analog
* @author Johnny Broadway
*/
class Analog {
/**
* List of severity levels.
*/
const URGENT = 0; // It's an emergency
const ALERT = 1; // Immediate action required
const CRITICAL = 2; // Critical conditions
const ERROR = 3; // An error occurred
const WARNING = 4; // Something unexpected happening
const NOTICE = 5; // Something worth noting
const INFO = 6; // Information, not an error
const DEBUG = 7; // Debugging messages
/**
* The default format for log messages (machine, date, level, message)
* written to a file. To change the order of items in the string,
* use `%1$s` references.
*/
public static $format = "%s - %s - %d - %s\n";
/**
* The default date/time format for log messages written to a file.
* Feeds into the `$format` property.
*/
public static $date_format = 'Y-m-d H:i:s';
/**
* Timezone for date/time values.
*/
public static $timezone = 'GMT';
/**
* Default log level.
*/
public static $default_level = 3;
/**
* The method of saving the log output. See Analog::handler()
* for details on setting this.
*/
private static $handler = null;
/**
* The name of the current machine, defaults to $_SERVER['SERVER_ADDR']
* on first call to format_message(), or 'localhost' if $_SERVER['SERVER_ADDR']
* is not set (e.g., during CLI use).
*/
public static $machine = null;
/**
* Handler getter/setter. If no handler is provided, it will set it to
* sys_get_temp_dir() . '/analog.txt' as a default. Usage:
*
* Analog::handler ('my_log.txt');
*
* Using a closure:
*
* Analog::handler (function ($msg) {
* return error_log ($msg);
* });
*/
public static function handler ($handler = false) {
if ($handler) {
self::$handler = $handler;
} elseif (! self::$handler) {
self::$handler = realpath (sys_get_temp_dir ()) . DIRECTORY_SEPARATOR . 'analog.txt';
}
return self::$handler;
}
/**
* Get the log info as an associative array.
*/
private static function get_struct ($message, $level) {
if (self::$machine === null) {
self::$machine = (isset ($_SERVER['SERVER_ADDR'])) ? $_SERVER['SERVER_ADDR'] : 'localhost';
}
$dt = new \DateTime ('now', new \DateTimeZone (self::$timezone));
return array (
'machine' => self::$machine,
'date' => $dt->format (self::$date_format),
'level' => $level,
'message' => $message
);
}
/**
* Write a raw message to the log using a function or the default
* file logging.
*/
private static function write ($struct) {
$handler = self::handler ();
if (! $handler instanceof \Closure) {
$handler = \Analog\Handler\File::init ($handler);
}
return $handler ($struct);
}
/**
* This is the main function you will call to log messages.
* Defaults to severity level Analog::ERROR, which can be
* changed via the `$default_level` property.
* Usage:
*
* Analog::log ('Debug info', Analog::DEBUG);
*/
public static function log ($message, $level = null) {
$level = ($level !== null) ? $level : self::$default_level;
return self::write (self::get_struct ($message, $level));
}
/**
* Shortcut method for Analog::log($info, Analog::URGENT)
* Usage:
*
* Analog::urgent ('Debug info');
*/
public static function urgent ($message) {
return self::write (self::get_struct ($message, self::URGENT));
}
/**
* Shortcut method for Analog::log($info, Analog::ALERT)
* Usage:
*
* Analog::alert ('Debug info');
*/
public static function alert ($message) {
return self::write (self::get_struct ($message, self::ALERT));
}
/**
* Shortcut method for Analog::log($info, Analog::ERROR)
* Usage:
*
* Analog::error ('Debug info');
*/
public static function error ($message) {
return self::write (self::get_struct ($message, self::ERROR));
}
/**
* Shortcut method for Analog::log($info, Analog::WARNING)
* Usage:
*
* Analog::warning ('Debug info');
*/
public static function warning ($message) {
return self::write (self::get_struct ($message, self::WARNING));
}
/**
* Shortcut method for Analog::log($info, Analog::NOTICE)
* Usage:
*
* Analog::notice ('Debug info');
*/
public static function notice ($message) {
return self::write (self::get_struct ($message, self::NOTICE));
}
/**
* Shortcut method for Analog::log($info, Analog::INFO)
* Usage:
*
* Analog::info ('Debug info');
*/
public static function info ($message) {
return self::write (self::get_struct ($message, self::INFO));
}
/**
* Shortcut method for Analog::log($info, Analog::DEBUG)
* Usage:
*
* Analog::debug ('Debug info');
*/
public static function debug ($message) {
return self::write (self::get_struct ($message, self::DEBUG));
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Analog\Handler;
/**
* Send the log message to an Amon monitoring server (http://amon.cx/).
*
* Usage:
*
* // First include the Amon classes
* require 'amon.php';
*
* // Initialize the Analog Amon handler
* Analog::handler (Analog\Handler\Amon::init (
* 'http://127.0.0.1', // server address
* 2464, // port number
* 'abc123def456' // application key
* ));
*/
class Amon {
public static function init ($host = 'http://127.0.0.1', $port = 2464, $key = false) {
\Amon::config (array (
'host' => $host,
'port' => $port,
'application_key' => $key
));
$tags = array (
0 => 'urgent',
1 => 'alert',
2 => 'critical',
3 => 'error',
4 => 'warning',
5 => 'notice',
6 => 'info',
7 => 'debug'
);
return function ($info) use ($tags) {
\Amon::log ($info, array ($tags[$info['level']]));
};
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Analog\Handler;
/**
* Buffers messages to be sent as a batch to another handler at the end
* of the request. Currently only works with the Mail handler.
*
* Usage:
*
* Analog::handler (Analog\Handler\Buffer::init (
* Analog\Handler\Mail::init ($to, $subject, $from)
* ));
*
* // will all be buffered into one email
* Analog::log ('Message one', Analog::DEBUG);
* Analog::log ('Message two', Analog::WARNING);
* Analog::log ('Message three', Analog::ERROR);
*
* Note: Uses Analog::$format to format the messages as they're appended
* to the buffer.
*/
class Buffer {
/**
* This builds a log string of all messages logged.
*/
public static $buffer = '';
/**
* This contains the handler to send to on close.
*/
private static $handler;
/**
* A copy of our destructor object that will call close() on our behalf,
* since static classes can't have their own __destruct() methods.
*/
private static $destructor;
/**
* Accepts another handler function to be used on close().
*/
public static function init ($handler) {
self::$handler = $handler;
self::$destructor = new \Analog\Handler\Buffer\Destructor ();
return function ($info) {
Buffer::$buffer .= vsprintf (\Analog\Analog::$format, $info);
};
}
/**
* Passes the buffered log to the final $handler.
*/
public static function close () {
$handler = self::$handler;
return $handler (self::$buffer, true);
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Analog\Handler\Buffer;
/**
* A destructor object to call close() for us at the end of the request.
*/
class Destructor {
public function __destruct () {
\Analog\Handler\Buffer::close ();
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Analog\Handler;
require_once __DIR__ . '/../../ChromePhp.php';
/**
* Log to the [Chrome Logger](http://craig.is/writing/chrome-logger).
* Based on the [ChromePhp library](https://github.com/ccampbell/chromephp).
*
* Usage:
*
* Analog::handler (Analog\Handler\ChromeLogger::init ());
*
* // send a debug message
* Analog::debug ($an_object);
*
* // send an ordinary message
* Analog::info ('An error message');
*/
class ChromeLogger {
public static function init () {
return function ($info) {
switch ($info['level']) {
case \Analog\Analog::DEBUG:
\ChromePhp::log ($info['message']);
break;
case \Analog\Analog::INFO:
case \Analog\Analog::NOTICE:
\ChromePhp::info ($info['message']);
break;
case \Analog\Analog::WARNING:
\ChromePhp::warn ($info['message']);
break;
case \Analog\Analog::ERROR:
case \Analog\Analog::CRITICAL:
case \Analog\Analog::ALERT:
case \Analog\Analog::URGENT:
\ChromePhp::error ($info['message']);
break;
}
};
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Analog\Handler;
/**
* Append to the specified log file. Does the same thing as the default
* handling.
*
* Usage:
*
* $log_file = 'log.txt';
* Analog::handler (Analog\Handler\File::init ($log_file));
*
* Analog::log ('Log me');
*
* Note: Uses Analog::$format for the appending format.
*/
class File {
public static function init ($file) {
return function ($info, $buffered = false) use ($file) {
$f = fopen ($file, 'a+');
if (! $f) {
throw new \LogicException ('Could not open file for writing');
}
if (! flock ($f, LOCK_EX)) {
throw new \RuntimeException ('Could not lock file');
}
fwrite ($f, ($buffered)
? $info
: vsprintf (\Analog\Analog::$format, $info));
flock ($f, LOCK_UN);
fclose ($f);
};
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Analog\Handler;
/**
* Log via FirePHP using the Wildfire protocol (http://www.firephp.org/).
* Based loosely on the Monolog FirePHP handler.
*
* Usage:
*
* Analog::handler (Analog\Handler\FirePHP::init ());
*
* // send a debug message with file and line number
* Analog::log (array ('Log me', __FILE__, __LINE__), Analog::DEBUG);
*
* // send an ordinary message
* Analog::log ('An error message');
*/
class FirePHP {
/**
* Translation list for log levels.
*/
private static $log_levels = array (
\Analog\Analog::DEBUG => 'LOG',
\Analog\Analog::INFO => 'INFO',
\Analog\Analog::NOTICE => 'INFO',
\Analog\Analog::WARNING => 'WARN',
\Analog\Analog::ERROR => 'ERROR',
\Analog\Analog::CRITICAL => 'ERROR',
\Analog\Analog::ALERT => 'ERROR',
\Analog\Analog::URGENT => 'ERROR'
);
/**
* Message index increases by 1 each time a message is sent.
*/
private static $message_index = 1;
/**
* Formats a log header to be sent.
*/
public static function format_header ($info) {
if (is_array ($info['message'])) {
$extra = array (
'Type' => self::$log_levels[$info['level']],
'File' => $info['message'][1],
'Line' => $info['message'][2]
);
$info['message'] = $info['message'][0];
} else {
$extra = array ('Type' => self::$log_levels[$info['level']]);
}
$json = json_encode (array ($extra, $info['message']));
return sprintf ('X-Wf-1-1-1-%d: %s|%s|', self::$message_index++, strlen ($json), $json);
}
/**
* Sends the initial headers if FirePHP is available then returns a
* closure that handles sending log messages.
*/
public static function init () {
if (! isset ($_SERVER['HTTP_USER_AGENT'])
|| preg_match ('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])
|| isset ($_SERVER['HTTP_X_FIREPHP_VERSION'])) {
header ('X-Wf-Protocol-1: http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
header ('X-Wf-1-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3');
header ('X-Wf-1-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
}
return function ($info) {
header (FirePHP::format_header ($info));
};
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Analog\Handler;
/**
* Send the log message to a Graylog2 server (http://graylog2.org/).
*
* Usage:
*
* // First include the GELF classes from
* // https://github.com/Graylog2/gelf-php
* require 'GELFMessage.php';
* require 'GELFMessagePublisher.php';
*
* // Initialize the Analog GELF handler
* Analog::handler (Analog\Handler\GELF::init (
* '172.16.22.30'
* ));
*
* // Send a message with file and line number
* Analog::log (array ('Log me', __FILE__, __LINE__), Analog::DEBUG);
*
* // Send an ordinary message
* Analog::log ('An error message');
*/
class GELF {
public static function init ($host = '127.0.0.1', $port = \GELFMessagePublisher::GRAYLOG2_DEFAULT_PORT) {
$publisher = new \GELFMessagePublisher ($host, $port);
return function ($info) use ($publisher) {
$message = new \GELFMessage ();
$message->setHost ($info['machine']);
$message->setLevel ($info['level']);
if (is_array ($info['message'])) {
$message->setShortMessage ($info['message'][0]);
$message->setFullMessage ($info['message'][0]);
$message->setFile ($info['message'][1]);
$message->setLine ($info['message'][2]);
} else {
$message->setShortMessage ($info['message']);
$message->setFullMessage ($info['message']);
}
$publisher->publish ($message);
};
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Analog\Handler;
/**
* Ignores anything sent to it so you can disable logging.
*
* Usage:
*
* Analog::handler (Analog\Handler\Ignore::init ());
*
* Analog::log ('Log me');
*/
class Ignore {
public static function init () {
return function ($info) {
// do nothing
};
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Analog\Handler;
/**
* Buffers messages to be sent as a batch to another handler only when a
* message of a certain level threshold has been received. This means for
* example that you can trigger a handler only if an error has occurred.
* Currently only works with the Mail handler.
*
* Inspired by the Monolog FingersCrossedHandler.
*
* Usage:
*
* Analog::handler (Analog\Handler\LevelBuffer::init (
* Analog\Handler\Mail::init ($to, $subject, $from),
* Analog::ERROR
* ));
*
* // will all be buffered until something ERROR or above is logged
* Analog::log ('Message one', Analog::DEBUG);
* Analog::log ('Message two', Analog::WARNING);
* Analog::log ('Message three', Analog::URGENT);
*
* Note: Uses Analog::$format to format the messages as they're appended
* to the buffer.
*/
class LevelBuffer {
/**
* This builds a log string of all messages logged.
*/
public static $buffer = '';
/**
* This contains the handler to send to on close.
*/
private static $handler;
/**
* Accepts another handler function to be used on close().
* $until_level defaults to CRITICAL.
*/
public static function init ($handler, $until_level = 2) {
self::$handler = $handler;
return function ($info) use ($until_level) {
LevelBuffer::$buffer .= vsprintf (\Analog\Analog::$format, $info);
if ($info['level'] <= $until_level) {
// flush and reset the buffer
LevelBuffer::flush ();
LevelBuffer::$buffer = '';
}
};
}
/**
* Passes the buffered log to the final $handler.
*/
public static function flush () {
$handler = self::$handler;
return $handler (self::$buffer, true);
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Analog\Handler;
/**
* Translates log level codes to their names
*
*
* Usage:
*
* // The log level (3rd value) must be formatted as a string
* Analog::$format = "%s - %s - %s - %s\n";
*
* Analog::handler (Analog\Handler\LevelName::init (
* Analog\Handler\File::init ($file)
* ));
*/
class LevelName {
/**
* Translation list for log levels.
*/
private static $log_levels = array (
\Analog\Analog::DEBUG => 'DEBUG',
\Analog\Analog::INFO => 'INFO',
\Analog\Analog::NOTICE => 'NOTICE',
\Analog\Analog::WARNING => 'WARNING',
\Analog\Analog::ERROR => 'ERROR',
\Analog\Analog::CRITICAL => 'CRITICAL',
\Analog\Analog::ALERT => 'ALERT',
\Analog\Analog::URGENT => 'URGENT'
);
/**
* This contains the handler to send to
*/
public static $handler;
public static function init ($handler) {
self::$handler = $handler;
return function ($info) {
if (isset(self::$log_levels[$info['level']])) {
$info['level'] = self::$log_levels[$info['level']];
}
$handler = LevelName::$handler;
$handler ($info);
};
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Analog\Handler;
/**
* Send the log message to the specified email address.
*
* Usage:
*
* Analog::handler (Analog\Handler\Mail::init (
* 'you@example.com', // to
* 'Subject line', // subject
* 'no-reply@example.com' // from
* ));
*/
class Mail {
public static function init ($to, $subject, $from) {
return function ($info, $buffered = false) use ($to, $subject, $from) {
if($info=="") return; // do not send empty mail.
$headers = sprintf ("From: %s\r\nContent-type: text/plain; charset=utf-8\r\n", $from);
$body = ($buffered)
? "Logged:\n" . $info
: vsprintf ("Machine: %s\nDate: %s\nLevel: %d\nMessage: %s", $info);
mail ($to, $subject, wordwrap ($body, 70), $headers);
};
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Analog\Handler;
/**
* Send the log message to the specified collection in a
* MongoDB database.
*
* Usage:
*
* Analog::handler (Analog\Handler\Mongo::init (
* 'localhost:27017', // connection string
* 'mydb', // database name
* 'log' // collection name
* ));
*
* Alternately, if you have an existing Mongo connection,
* you can simply initialize it with that:
*
* $conn = new MongoClient ('localhost:27017'); // mongo driver
* $conn = new MongoDB\Driver\Manager('localhost:27017'); // mongodb driver
* Analog::handler (Analog\Handler\Mongo::init (
* $conn, // Mongo object
* 'mydb', // database name
* 'log' // collection name
* ));
*/
class Mongo {
public static function init ($server, $database, $collection) {
if ($server instanceof \MongoDB\Driver\Manager) {
$driver = 'mongodb';
$manager = $server;
} elseif ($server instanceof \MongoClient) {
$db = $server->{$database};
} else {
if (class_exists('\MongoDB\Driver\Manager')) {
$driver = 'mongodb';
$manager = new \MongoDB\Driver\Manager("mongodb://$server");
} else {
$conn = new \MongoClient ("mongodb://$server");
$db = $conn->{$database};
}
}
if ($driver == 'mongodb') {
return function ($info) use ($manager, $database, $collection) {
$bulk = new \MongoDB\Driver\BulkWrite;
$bulk->insert($info);
$dbAndColl = $database.'.'.$collection;
$manager->executeBulkWrite($dbAndColl, $bulk);
};
} else {
return function ($info) use ($db, $collection) {
$db->{$collection}->insert ($info);
};
}
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Analog\Handler;
/**
* Sends messages to one or more of the other handlers based on its
* log level.
*
* Usage:
*
* Analog::handler( Analog\Handler\Multi::init( array(
* // anything error or worse goes to this
* Analog::ERROR => array(
* Analog\Handler\Mail::init( $to, $subject, $from ),
* Analog\Handler\Stderr::init()
* ),
*
* // Warnings are sent here
* Analog::WARNING => Analog\Handler\File::init( 'logs/warnings.log' ),
*
* // Debug and info messages sent here
* Analog::DEBUG => Analog\Handler\Ignore::init() // do nothing
* ) ) );
*
* // will be ignored
* Analog::log ('Ignore me', Analog::DEBUG);
*
* // will be written to logs/warnings.log
* Analog::log ('Log me', Analog::WARNING);
*
* // will trigger an email notice
* Analog::log ('Uh oh...', Analog::ERROR);
*/
class Multi {
public static function init ($handlers) {
return function ($info) use ($handlers) {
$level = is_numeric ($info['level']) ? $info['level'] : 3;
while ($level <= 7) {
if ( isset ( $handlers[ $level ] ) ) {
if ( ! is_array( $handlers[ $level ] ) ) {
$handlers[ $level ] = array( $handlers[ $level ] );
}
foreach ( $handlers[ $level ] as $handler ) {
$handler( $info );
}
return;
}
$level++;
}
};
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Analog\Handler;
/**
* Note: Deprecated because Null is a reserved word in PHP7.
* Please use Analog\Handler\Ignore instead.
*
* Ignores anything sent to it so you can disable logging.
*
* Usage:
*
* Analog::handler (Analog\Handler\Null::init ());
*
* Analog::log ('Log me');
*/
class Null {
public static function init () {
return function ($info) {
// do nothing
};
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Analog\Handler;
/**
* Post the log info to the specified address.
*
* Usage:
*
* $address = 'http://my-log-server/log-me';
* Analog::handler (Analog\Handler\Post::init ($address));
*
* The server will receive an HTTP POST request with four
* parameters:
*
* - machine
* - date
* - level
* - message
*
* Note: Requires cURL.
*/
class Post {
public static function init ($address) {
return function ($info) use ($address) {
if (! extension_loaded ('curl')) {
throw new \LogicException ('CURL extension not loaded.');
}
$ch = curl_init ();
curl_setopt ($ch, CURLOPT_URL, $address);
curl_setopt ($ch, CURLOPT_MAXREDIRS, 3);
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_VERBOSE, 0);
curl_setopt ($ch, CURLOPT_HEADER, 0);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_POSTFIELDS, $info);
curl_exec ($ch);
curl_close ($ch);
};
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Analog\Handler;
/**
* Post the log info to the specified Slack channel through Slack's Slackbot.
*
* Usage:
*
* $team = 'team-subdomain';
* $token = 'slackbot token';
* $channel = 'slack-channel';
* Analog::handler (Analog\Handler\Slackbot::init ($team, $token, $channel));
*
* Note: Requires cURL.
*/
class Slackbot {
public static function init ($team, $token, $channel) {
return function ($info) use ($team, $token, $channel) {
if (! extension_loaded ('curl')) {
throw new \LogicException ('CURL extension not loaded.');
}
$url = sprintf (
'https://%s.slack.com/services/hooks/slackbot?token=%s&channel=%s',
$team,
$token,
$channel
);
$msg = sprintf (
'%s (%d): %s',
$info['machine'],
$info['level'],
$info['message']
);
$ch = curl_init ();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_POSTFIELDS, $msg);
curl_exec ($ch);
curl_close ($ch);
};
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Analog\Handler;
/**
* Send the output to STDERR.
*
* Usage:
*
* Analog::handler (Analog\Handler\Stderr::init ());
*
* Analog::log ('Log me');
*
* Note: Uses Analog::$format for the appending format.
*/
class Stderr {
public static function init () {
return function ($info, $buffered = false) {
file_put_contents ('php://stderr', ($buffered)
? $info
: vsprintf (\Analog\Analog::$format, $info));
};
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Analog\Handler;
/**
* Send the log message to the syslog service. This was borrowed largely
* from the Monolog syslog handler.
*
* Usage:
*
* Analog::handler (Analog\Handler\Syslog::init ('ident', 'facility'));
*/
class Syslog {
public static $levels = array (
\Analog\Analog::DEBUG => LOG_DEBUG,
\Analog\Analog::INFO => LOG_INFO,
\Analog\Analog::NOTICE => LOG_NOTICE,
\Analog\Analog::WARNING => LOG_WARNING,
\Analog\Analog::ERROR => LOG_ERR,
\Analog\Analog::CRITICAL => LOG_CRIT,
\Analog\Analog::ALERT => LOG_ALERT,
\Analog\Analog::URGENT => LOG_EMERG
);
public static $facilities = array (
'auth' => LOG_AUTH,
'authpriv' => LOG_AUTHPRIV,
'cron' => LOG_CRON,
'daemon' => LOG_DAEMON,
'kern' => LOG_KERN,
'lpr' => LOG_LPR,
'mail' => LOG_MAIL,
'news' => LOG_NEWS,
'syslog' => LOG_SYSLOG,
'user' => LOG_USER,
'uucp' => LOG_UUCP
);
public static function init ($ident, $facility) {
if (! defined ('PHP_WINDOWS_VERSION_BUILD')) {
self::$facilities['local0'] = LOG_LOCAL0;
self::$facilities['local1'] = LOG_LOCAL1;
self::$facilities['local2'] = LOG_LOCAL2;
self::$facilities['local3'] = LOG_LOCAL3;
self::$facilities['local4'] = LOG_LOCAL4;
self::$facilities['local5'] = LOG_LOCAL5;
self::$facilities['local6'] = LOG_LOCAL6;
self::$facilities['local7'] = LOG_LOCAL7;
}
if (array_key_exists (strtolower ($facility), self::$facilities)) {
$facility = self::$facilities[strtolower ($facility)];
} elseif (! in_array ($facility, array_values (self::$facilities), true)) {
throw new \UnexpectedValueException ('Unknown facility value "' . $facility . '"');
}
return function ($info) use ($ident, $facility) {
if (! openlog ($ident, LOG_PID, $facility)) {
throw new \LogicException ('Can\'t open syslog for ident "' . $ident . '" and facility "' . $facility . '"');
}
syslog (Syslog::$levels[$info['level']], vsprintf ('%1$s: %4$s', $info));
closelog ();
};
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Analog\Handler;
/**
* Only writes log messages above a certain threshold
*
*
* Usage:
*
* Analog::handler (Analog\Handler\Threshold::init (
* Analog\Handler\File::init ($file),
* Analog::ERROR
* ));
*
* // Only message three will be logged
* Analog::log ('Message one', Analog::DEBUG);
* Analog::log ('Message two', Analog::WARNING);
* Analog::log ('Message three', Analog::URGENT);
*
* Note: Uses Analog::$format to format the messages as they're appended
* to the buffer.
*/
class Threshold {
/**
* This contains the handler to send to on close.
*/
public static $handler;
/**
* Accepts another handler function to be used on close().
* $until_level defaults to ERROR.
*/
public static function init ($handler, $until_level = 3) {
self::$handler = $handler;
return function ($info) use ($until_level) {
if ($info['level'] <= $until_level) {
$handler = Threshold::$handler;
$handler ($info);
}
};
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Analog\Handler;
/**
* Append the log info to a variable passed in as a reference.
*
* Usage:
*
* $my_log = '';
* Analog::handler (Analog\Handler\Variable::init ($my_log));
*
* Analog::log ('Log me');
* echo $my_log;
*
* Note: Uses Analog::$format for the appending format.
*/
class Variable {
public static function init (&$log) {
return function ($info, $buffered = false) use (&$log) {
$log .= ($buffered)
? $info
: vsprintf (\Analog\Analog::$format, $info);
};
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Analog\Handler;
/**
* Send the log message to the specified email address using WordPress wp_mail.
*
* You can also specify a template in your theme to style how the email looks like.
*
* Usage:
*
* Analog::handler (Analog\Handler\WPMail::init (
* 'you@example.com', // to
* 'Subject line', // subject
* 'no-reply@example.com', // from
* 'log-email-template.php' // email template in theme
* ));
*/
class WPMail {
public static function init ($to, $subject, $from, $template='') {
return function ($info, $buffered = false) use ($to, $subject, $from, $template) {
$body = ($buffered)
? "Logged:\n" . $info
: vsprintf ("Machine: %s\nDate: %s\nLevel: %d\nMessage: %s", $info);
$log_template = locate_template( $template );
if ( ! empty( $log_template ) ) {
ob_start();
include_once $log_template;
$body = ob_get_clean();
} else {
$body = wordwrap( $body, 70 );
}
add_filter( 'wp_mail_content_type', array( __CLASS__, 'set_email_content_type' ) );
wp_mail( $to, $subject, $body );
remove_filter( 'wp_mail_content_type', array( __CLASS__, 'set_email_content_type' ) );
};
}
public static function set_email_content_type() {
return 'text/html';
}
}

View File

@@ -0,0 +1,220 @@
<?php
namespace Analog;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\Log\InvalidArgumentException;
/**
* Analog - PHP 5.3+ logging class
*
* Copyright (c) 2012 Johnny Broadway
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Implements the PSR-3 standard as a wrapper to Analog. For more information,
* see:
*
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
*
* Usage:
*
* <?php
*
* require_once ('vendor/autoload.php');
*
* $log = new Analog\Logger ();
*
* $log->notice ('Things are really happening right now.');
*
* ?>
*
* @package Analog
* @author Johnny Broadway
*/
class Logger implements LoggerInterface {
/**
* Converts from PSR-3 log levels to Analog log levels.
*/
public function convert_log_level ($level, $reverse = false) {
if ($reverse) {
switch ($level) {
case Analog::URGENT:
return LogLevel::EMERGENCY;
case Analog::ALERT:
return LogLevel::ALERT;
case Analog::CRITICAL:
return LogLevel::CRITICAL;
case Analog::ERROR:
return LogLevel::ERROR;
case Analog::WARNING:
return LogLevel::WARNING;
case Analog::NOTICE:
return LogLevel::NOTICE;
case Analog::INFO:
return LogLevel::INFO;
case Analog::DEBUG:
return LogLevel::DEBUG;
}
throw new InvalidArgumentException ('Level "' . $level . '" is not defined.');
} else {
switch ($level) {
case LogLevel::EMERGENCY:
return Analog::URGENT;
case LogLevel::ALERT:
return Analog::ALERT;
case LogLevel::CRITICAL:
return Analog::CRITICAL;
case LogLevel::ERROR:
return Analog::ERROR;
case LogLevel::WARNING:
return Analog::WARNING;
case LogLevel::NOTICE:
return Analog::NOTICE;
case LogLevel::INFO:
return Analog::INFO;
case LogLevel::DEBUG:
return Analog::DEBUG;
}
throw new InvalidArgumentException ('Level "' . $level . '" is not defined.');
}
}
/**
* Interpolates context values into the message placeholders.
*/
private function interpolate ($message, array $context = array ()) {
if (is_array ($message)) {
return $message;
}
// build a replacement array with braces around the context keys
$replace = array ();
foreach ($context as $key => $val) {
if (is_object ($val) && get_class ($val) === 'DateTime') {
$val = $val->format ('Y-m-d H:i:s');
} elseif (is_object ($val)) {
$val = json_encode ($val);
} elseif (is_array ($val)) {
$val = json_encode ($val);
} elseif (is_resource ($val)) {
$val = (string) $val;
}
$replace['{' . $key . '}'] = $val;
}
// interpolate replacement values into the the message and return
return strtr ($message, $replace);
}
/**
* Sets the Analog log handler.
*/
public function handler ($handler) {
Analog::handler ($handler);
}
/**
* Sets the log message format.
*/
public function format ($format) {
Analog::$format = $format;
}
/**
* System is unusable.
*/
public function emergency ($message, array $context = array ()) {
$this->_log (Analog::URGENT, $message, $context);
}
/**
* Action must be taken immediately.
*/
public function alert ($message, array $context = array ()) {
$this->_log (Analog::ALERT, $message, $context);
}
/**
* Critical conditions.
*/
public function critical ($message, array $context = array ()) {
$this->_log (Analog::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*/
public function error ($message, array $context = array ()) {
$this->_log (Analog::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*/
public function warning ($message, array $context = array ()) {
$this->_log (Analog::WARNING, $message, $context);
}
/**
* Normal but significant events.
*/
public function notice ($message, array $context = array ()) {
$this->_log (Analog::NOTICE, $message, $context);
}
/**
* Interesting events.
*/
public function info ($message, array $context = array ()) {
$this->_log (Analog::INFO, $message, $context);
}
/**
* Detailed debug information.
*/
public function debug ($message, array $context = array ()) {
$this->_log (Analog::DEBUG, $message, $context);
}
/**
* Logs with an arbitrary level.
*/
public function log ($level, $message, array $context = array ()) {
$this->_log (
$this->convert_log_level ($level),
$message,
$context
);
}
/**
* Perform the logging to Analog after the log level has been converted.
*/
private function _log ($level, $message, $context) {
Analog::log (
$this->interpolate ($message, $context),
$level
);
}
}

View File

@@ -0,0 +1,423 @@
<?php
/**
* Copyright 2010-2013 Craig Campbell
*
* 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.
*/
/**
* Server Side Chrome PHP debugger class
*
* @package ChromePhp
* @author Craig Campbell <iamcraigcampbell@gmail.com>
*/
class ChromePhp
{
/**
* @var string
*/
const VERSION = '4.0.0';
/**
* @var string
*/
const HEADER_NAME = 'X-ChromeLogger-Data';
/**
* @var string
*/
const BACKTRACE_LEVEL = 'backtrace_level';
/**
* @var string
*/
const LOG = 'log';
/**
* @var string
*/
const WARN = 'warn';
/**
* @var string
*/
const ERROR = 'error';
/**
* @var string
*/
const GROUP = 'group';
/**
* @var string
*/
const INFO = 'info';
/**
* @var string
*/
const GROUP_END = 'groupEnd';
/**
* @var string
*/
const GROUP_COLLAPSED = 'groupCollapsed';
/**
* @var string
*/
protected $_php_version;
/**
* @var int
*/
protected $_timestamp;
/**
* @var array
*/
protected $_json = array(
'version' => self::VERSION,
'columns' => array('log', 'backtrace', 'type'),
'rows' => array()
);
/**
* @var array
*/
protected $_backtraces = array();
/**
* @var bool
*/
protected $_error_triggered = false;
/**
* @var array
*/
protected $_settings = array(
self::BACKTRACE_LEVEL => 1
);
/**
* @var ChromePhp
*/
protected static $_instance;
/**
* Prevent recursion when working with objects referring to each other
*
* @var array
*/
protected $_processed = array();
/**
* constructor
*/
private function __construct()
{
$this->_php_version = phpversion();
$this->_timestamp = $this->_php_version >= 5.1 ? $_SERVER['REQUEST_TIME'] : time();
$this->_json['request_uri'] = $_SERVER['REQUEST_URI'];
}
/**
* gets instance of this class
*
* @return ChromePhp
*/
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* logs a variable to the console
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function log()
{
return self::_log('', func_get_args());
}
/**
* logs a warning to the console
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function warn()
{
return self::_log(self::WARN, func_get_args());
}
/**
* logs an error to the console
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function error()
{
return self::_log(self::ERROR, func_get_args());
}
/**
* sends a group log
*
* @param string value
*/
public static function group()
{
return self::_log(self::GROUP, func_get_args());
}
/**
* sends an info log
*
* @param mixed $data,... unlimited OPTIONAL number of additional logs [...]
* @return void
*/
public static function info()
{
return self::_log(self::INFO, func_get_args());
}
/**
* sends a collapsed group log
*
* @param string value
*/
public static function groupCollapsed()
{
return self::_log(self::GROUP_COLLAPSED, func_get_args());
}
/**
* ends a group log
*
* @param string value
*/
public static function groupEnd()
{
return self::_log(self::GROUP_END, func_get_args());
}
/**
* internal logging call
*
* @param string $type
* @return void
*/
protected static function _log($type, array $args)
{
// nothing passed in, don't do anything
if (count($args) == 0 && $type != self::GROUP_END) {
return;
}
$logger = self::getInstance();
$logger->_processed = array();
$logs = array();
foreach ($args as $arg) {
$logs[] = $logger->_convert($arg);
}
$backtrace = debug_backtrace(false);
$level = $logger->getSetting(self::BACKTRACE_LEVEL);
$backtrace_message = 'unknown';
if (isset($backtrace[$level]['file']) && isset($backtrace[$level]['line'])) {
$backtrace_message = $backtrace[$level]['file'] . ' : ' . $backtrace[$level]['line'];
}
$logger->_addRow($logs, $backtrace_message, $type);
}
/**
* converts an object to a better format for logging
*
* @param Object
* @return array
*/
protected function _convert($object)
{
// if this isn't an object then just return it
if (!is_object($object)) {
return $object;
}
//Mark this object as processed so we don't convert it twice and it
//Also avoid recursion when objects refer to each other
$this->_processed[] = $object;
$object_as_array = array();
// first add the class name
$object_as_array['___class_name'] = get_class($object);
// loop through object vars
$object_vars = get_object_vars($object);
foreach ($object_vars as $key => $value) {
// same instance as parent object
if ($value === $object || in_array($value, $this->_processed, true)) {
$value = 'recursion - parent object [' . get_class($value) . ']';
}
$object_as_array[$key] = $this->_convert($value);
}
$reflection = new ReflectionClass($object);
// loop through the properties and add those
foreach ($reflection->getProperties() as $property) {
// if one of these properties was already added above then ignore it
if (array_key_exists($property->getName(), $object_vars)) {
continue;
}
$type = $this->_getPropertyKey($property);
if ($this->_php_version >= 5.3) {
$property->setAccessible(true);
}
try {
$value = $property->getValue($object);
} catch (ReflectionException $e) {
$value = 'only PHP 5.3 can access private/protected properties';
}
// same instance as parent object
if ($value === $object || in_array($value, $this->_processed, true)) {
$value = 'recursion - parent object [' . get_class($value) . ']';
}
$object_as_array[$type] = $this->_convert($value);
}
return $object_as_array;
}
/**
* takes a reflection property and returns a nicely formatted key of the property name
*
* @param ReflectionProperty
* @return string
*/
protected function _getPropertyKey(ReflectionProperty $property)
{
$static = $property->isStatic() ? ' static' : '';
if ($property->isPublic()) {
return 'public' . $static . ' ' . $property->getName();
}
if ($property->isProtected()) {
return 'protected' . $static . ' ' . $property->getName();
}
if ($property->isPrivate()) {
return 'private' . $static . ' ' . $property->getName();
}
}
/**
* adds a value to the data array
*
* @var mixed
* @return void
*/
protected function _addRow(array $logs, $backtrace, $type)
{
// if this is logged on the same line for example in a loop, set it to null to save space
if (in_array($backtrace, $this->_backtraces)) {
$backtrace = null;
}
// for group, groupEnd, and groupCollapsed
// take out the backtrace since it is not useful
if ($type == self::GROUP || $type == self::GROUP_END || $type == self::GROUP_COLLAPSED) {
$backtrace = null;
}
if ($backtrace !== null) {
$this->_backtraces[] = $backtrace;
}
$row = array($logs, $backtrace, $type);
$this->_json['rows'][] = $row;
$this->_writeHeader($this->_json);
}
protected function _writeHeader($data)
{
header(self::HEADER_NAME . ': ' . $this->_encode($data));
}
/**
* encodes the data to be sent along with the request
*
* @param array $data
* @return string
*/
protected function _encode($data)
{
return base64_encode(utf8_encode(json_encode($data)));
}
/**
* adds a setting
*
* @param string key
* @param mixed value
* @return void
*/
public function addSetting($key, $value)
{
$this->_settings[$key] = $value;
}
/**
* add ability to set multiple settings in one call
*
* @param array $settings
* @return void
*/
public function addSettings(array $settings)
{
foreach ($settings as $key => $value) {
$this->addSetting($key, $value);
}
}
/**
* gets a setting
*
* @param string key
* @return mixed
*/
public function getSetting($key)
{
if (!isset($this->_settings[$key])) {
return null;
}
return $this->_settings[$key];
}
}

7
web/vendor/autoload.php vendored Normal file
View File

@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd953cdae79eaf5c13d0a0a197a7206e6::getLoader();

View File

@@ -0,0 +1,91 @@
<?php
$finder = PhpCsFixer\Finder::create()
->notPath('vendor')
->in(__DIR__)
->name('*.php')
->ignoreDotFiles(true)
->ignoreVCS(true);
;
$config = PhpCsFixer\Config::create()
->setFinder($finder)
->setRiskyAllowed(true)
->setRules([
'@PSR1' => true,
'@PSR2' => true,
'align_multiline_comment' => true,
'array_syntax' => ['syntax' => 'short'],
'blank_line_after_opening_tag' => true,
'blank_line_before_return' => true,
'blank_line_before_statement' => true,
'cast_spaces' => true,
'class_attributes_separation' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
'comment_to_phpdoc' => true,
'compact_nullable_typehint' => true,
'explicit_indirect_variable' => true,
'explicit_string_variable' => true,
'fully_qualified_strict_types' => true,
'function_typehint_space' => true,
'hash_to_slash_comment' => true,
'heredoc_to_nowdoc' => true,
'include' => true,
'lowercase_cast' => true,
'method_chaining_indentation' => true,
'multiline_comment_opening_closing' => true,
'native_function_casing' => true,
'new_with_braces' => true,
'no_alias_functions' => true,
'no_alternative_syntax' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_phpdoc' => true,
'no_extra_blank_lines' => ['tokens' => ['break', 'continue', 'throw', 'use']],
'no_extra_consecutive_blank_lines' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_multiline_whitespace_around_double_arrow' => true,
'no_multiline_whitespace_before_semicolons' => true,
'no_short_bool_cast' => true,
'no_short_echo_tag' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_superfluous_elseif' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_unneeded_control_parentheses' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_final_method' => true,
'no_unreachable_default_argument_value' => true,
'no_unused_imports' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
'object_operator_without_whitespace' => true,
'ordered_class_elements' => true,
'ordered_imports' => true,
'phpdoc_indent' => true,
'phpdoc_order' => true,
'phpdoc_scalar' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'psr4' => true,
'self_accessor' => true,
'semicolon_after_instruction' => true,
'short_scalar_cast' => true,
'simplified_null_return' => true,
'single_blank_line_before_namespace' => true,
'single_quote' => true,
'space_after_semicolon' => true,
'standardize_not_equals' => true,
'string_line_ending' => true,
'ternary_operator_spaces' => true,
'trailing_comma_in_multiline_array' => true,
'unary_operator_spaces' => true,
'whitespace_after_comma_in_array' => true,
])
;
return $config;

View File

@@ -0,0 +1,28 @@
Copyright (c) 2010-2016, Benjamin Eberlei <kontakt@beberlei.de> and individual
contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of DoctrineExtensions nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,32 @@
RED := $(shell tput -Txterm setaf 1)
GREEN := $(shell tput -Txterm setaf 2)
YELLOW := $(shell tput -Txterm setaf 3)
BLUE := $(shell tput -Txterm setaf 4)
MAGENTA := $(shell tput -Txterm setaf 5)
CYAN := $(shell tput -Txterm setaf 6)
WHITE := $(shell tput -Txterm setaf 7)
RESET := $(shell tput -Txterm sgr0)
HELP = \
%help; \
while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([\w-]+)\s*:.*\#\#(?:@([\w-]+))?\s(.*)$$/ }; \
print "usage: make [target]\n\n"; \
for (sort keys %help) { \
print "${WHITE}$$_:${RESET}\n"; \
for (@{$$help{$$_}}) { \
$$sep = " " x (32 - length $$_->[0]); \
print " ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \
}; \
print "\n"; }
help: ##@tap Show this help
@perl -e '$(HELP)' $(MAKEFILE_LIST)
fix: ##@tap Fix with PHP CS Fixer
vendor/bin/php-cs-fixer fix
lint: ##@tap Lint with PHP CS Fixer (dry-run)
vendor/bin/php-cs-fixer fix --dry-run --diff --diff-format udiff --show-progress=none --verbose
test: ##@tap Test with PHPUnit
vendor/bin/phpunit

View File

@@ -0,0 +1,113 @@
doctrine:
orm:
dql:
datetime_functions:
convert_tz: DoctrineExtensions\Query\Mysql\ConvertTz
date: DoctrineExtensions\Query\Mysql\Date
date_format: DoctrineExtensions\Query\Mysql\DateFormat
dateadd: DoctrineExtensions\Query\Mysql\DateAdd
datesub: DoctrineExtensions\Query\Mysql\DateSub
datediff: DoctrineExtensions\Query\Mysql\DateDiff
day: DoctrineExtensions\Query\Mysql\Day
dayname: DoctrineExtensions\Query\Mysql\DayName
dayofweek: DoctrineExtensions\Query\Mysql\DayOfWeek
dayofyear: DoctrineExtensions\Query\Mysql\DayOfYear
div: DoctrineExtensions\Query\Mysql\Div
from_unixtime: DoctrineExtensions\Query\Mysql\FromUnixtime
hour: DoctrineExtensions\Query\Mysql\Hour
last_day: DoctrineExtensions\Query\Mysql\LastDay
minute: DoctrineExtensions\Query\Mysql\Minute
now: DoctrineExtensions\Query\Mysql\Now
month: DoctrineExtensions\Query\Mysql\Month
monthname: DoctrineExtensions\Query\Mysql\MonthName
period_diff: DoctrineExtensions\Query\Mysql\PeriodDiff
second: DoctrineExtensions\Query\Mysql\Second
sectotime: DoctrineExtensions\Query\Mysql\SecToTime
strtodate: DoctrineExtensions\Query\Mysql\StrToDate
time: DoctrineExtensions\Query\Mysql\Time
timediff: DoctrineExtensions\Query\Mysql\TimeDiff
timestampadd: DoctrineExtensions\Query\Mysql\TimestampAdd
timestampdiff: DoctrineExtensions\Query\Mysql\TimestampDiff
timetosec: DoctrineExtensions\Query\Mysql\TimeToSec
week: DoctrineExtensions\Query\Mysql\Week
weekday: DoctrineExtensions\Query\Mysql\WeekDay
year: DoctrineExtensions\Query\Mysql\Year
yearmonth: DoctrineExtensions\Query\Mysql\YearMonth
yearweek: DoctrineExtensions\Query\Mysql\YearWeek
unix_timestamp: DoctrineExtensions\Query\Mysql\UnixTimestamp
utc_timestamp: DoctrineExtensions\Query\Mysql\UtcTimestamp
extract: DoctrineExtensions\Query\Mysql\Extract
numeric_functions:
acos: DoctrineExtensions\Query\Mysql\Acos
asin: DoctrineExtensions\Query\Mysql\Asin
atan2: DoctrineExtensions\Query\Mysql\Atan2
atan: DoctrineExtensions\Query\Mysql\Atan
bit_count: DoctrineExtensions\Query\Mysql\BitCount
bit_xor: DoctrineExtensions\Query\Mysql\BitXor
ceil: DoctrineExtensions\Query\Mysql\Ceil
cos: DoctrineExtensions\Query\Mysql\Cos
cot: DoctrineExtensions\Query\Mysql\Cot
degrees: DoctrineExtensions\Query\Mysql\Degrees
exp: DoctrineExtensions\Query\Mysql\Exp
floor: DoctrineExtensions\Query\Mysql\Floor
log: DoctrineExtensions\Query\Mysql\Log
log10: DoctrineExtensions\Query\Mysql\Log10
log2: DoctrineExtensions\Query\Mysql\Log2
pi: DoctrineExtensions\Query\Mysql\Pi
power: DoctrineExtensions\Query\Mysql\Power
quarter: DoctrineExtensions\Query\Mysql\Quarter
radians: DoctrineExtensions\Query\Mysql\Radians
rand: DoctrineExtensions\Query\Mysql\Rand
round: DoctrineExtensions\Query\Mysql\Round
stddev: DoctrineExtensions\Query\Mysql\StdDev
sin: DoctrineExtensions\Query\Mysql\Sin
std: DoctrineExtensions\Query\Mysql\Std
tan: DoctrineExtensions\Query\Mysql\Tan
variance: DoctrineExtensions\Query\Mysql\Variance
string_functions:
aes_decrypt: DoctrineExtensions\Query\Mysql\AesDecrypt
aes_encrypt: DoctrineExtensions\Query\Mysql\AesEncrypt
any_value: DoctrineExtensions\Query\Mysql\AnyValue
ascii: DoctrineExtensions\Query\Mysql\Ascii
binary: DoctrineExtensions\Query\Mysql\Binary
cast: DoctrineExtensions\Query\Mysql\Cast
char_length: DoctrineExtensions\Query\Mysql\CharLength
collate: DoctrineExtensions\Query\Mysql\Collate
concat_ws: DoctrineExtensions\Query\Mysql\ConcatWs
countif: DoctrineExtensions\Query\Mysql\CountIf
crc32: DoctrineExtensions\Query\Mysql\Crc32
degrees: DoctrineExtensions\Query\Mysql\Degrees
field: DoctrineExtensions\Query\Mysql\Field
find_in_set: DoctrineExtensions\Query\Mysql\FindInSet
greatest: DoctrineExtensions\Query\Mysql\Greatest
group_concat: DoctrineExtensions\Query\Mysql\GroupConcat
hex: DoctrineExtensions\Query\Mysql\Hex
ifelse: DoctrineExtensions\Query\Mysql\IfElse
ifnull: DoctrineExtensions\Query\Mysql\IfNull
inet_aton: DoctrineExtensions\Query\Mysql\InetAton
inet_ntoa: DoctrineExtensions\Query\Mysql\InetNtoa
inet6_aton: DoctrineExtensions\Query\Mysql\Inet6Aton
inet6_ntoa: DoctrineExtensions\Query\Mysql\Inet6Ntoa
instr: DoctrineExtensions\Query\Mysql\Instr
is_ipv4: DoctrineExtensions\Query\Mysql\IsIpv4
is_ipv4_compat: DoctrineExtensions\Query\Mysql\IsIpv4Compat
is_ipv4_mapped: DoctrineExtensions\Query\Mysql\IsIpv4Mapped
is_ipv6: DoctrineExtensions\Query\Mysql\IsIpv6
least: DoctrineExtensions\Query\Mysql\Least
lpad: DoctrineExtensions\Query\Mysql\Lpad
match: DoctrineExtensions\Query\Mysql\MatchAgainst
md5: DoctrineExtensions\Query\Mysql\Md5
nullif: DoctrineExtensions\Query\Mysql\NullIf
radians: DoctrineExtensions\Query\Mysql\Radians
regexp: DoctrineExtensions\Query\Mysql\Regexp
replace: DoctrineExtensions\Query\Mysql\Replace
rpad: DoctrineExtensions\Query\Mysql\Rpad
sha1: DoctrineExtensions\Query\Mysql\Sha1
sha2: DoctrineExtensions\Query\Mysql\Sha2
soundex: DoctrineExtensions\Query\Mysql\Soundex
str_to_date: DoctrineExtensions\Query\Mysql\StrToDate
substring_index: DoctrineExtensions\Query\Mysql\SubstringIndex
unhex: DoctrineExtensions\Query\Mysql\Unhex
uuid_short: DoctrineExtensions\Query\Mysql\UuidShort

View File

@@ -0,0 +1,14 @@
doctrine:
orm:
dql:
datetime_functions:
day: DoctrineExtensions\Query\Oracle\Day
month: DoctrineExtensions\Query\Oracle\Month
year: DoctrineExtensions\Query\Oracle\Year
to_char: DoctrineExtensions\Query\Oracle\ToChar
trunc: DoctrineExtensions\Query\Oracle\Trunc
string_functions:
nvl: DoctrineExtensions\Query\Oracle\Nvl
listagg: DoctrineExtensions\Query\Oracle\Listagg
to_date: DoctrineExtensions\Query\Oracle\ToDate

View File

@@ -0,0 +1,10 @@
doctrine:
orm:
dql:
datetime_functions:
date_format: DoctrineExtensions\Query\Postgresql\DateFormat
at_time_zone: DoctrineExtensions\Query\Postgresql\AtTimeZoneFunction
string_functions:
str_to_date: DoctrineExtensions\Query\Postgresql\StrToDate
count_filter: DoctrineExtensions\Query\Postgresql\CountFilterFunction
string_agg: DoctrineExtensions\Query\Postgresql\StringAgg

View File

@@ -0,0 +1,51 @@
doctrine:
orm:
dql:
datetime_functions:
date: DoctrineExtensions\Query\Sqlite\Date
date_format: DoctrineExtensions\Query\Sqlite\DateFormat
#dateadd: DoctrineExtensions\Query\Sqlite\DateAdd
#datediff: DoctrineExtensions\Query\Sqlite\DateDiff
day: DoctrineExtensions\Query\Sqlite\Day
dayname: DoctrineExtensions\Query\Sqlite\DayName
hour: DoctrineExtensions\Query\Sqlite\Hour
minute: DoctrineExtensions\Query\Sqlite\Minute
#month: DoctrineExtensions\Query\Sqlite\Month
#monthname: DoctrineExtensions\Query\Sqlite\MonthName
second: DoctrineExtensions\Query\Sqlite\Second
month: DoctrineExtensions\Query\Sqlite\Month
strftime: DoctrineExtensions\Query\Sqlite\StrfTime
#strtodate: DoctrineExtensions\Query\Sqlite\StrToDate
#time: DoctrineExtensions\Query\Sqlite\Time
#timestampadd: DoctrineExtensions\Query\Sqlite\TimestampAdd
#timestampdiff: DoctrineExtensions\Query\Sqlite\TimestampDiff
week: DoctrineExtensions\Query\Sqlite\Week
weekday: DoctrineExtensions\Query\Sqlite\WeekDay
year: DoctrineExtensions\Query\Sqlite\Year
string_functions:
# binary: DoctrineExtensions\Query\Sqlite\Binary
# char_length: DoctrineExtensions\Query\Sqlite\CharLength
concat_ws: DoctrineExtensions\Query\Sqlite\ConcatWs
# countif: DoctrineExtensions\Query\Sqlite\CountIf
# crc32: DoctrineExtensions\Query\Sqlite\Crc32
# degrees: DoctrineExtensions\Query\Sqlite\Degrees
# field: DoctrineExtensions\Query\Sqlite\Field
# find_in_set: DoctrineExtensions\Query\Sqlite\FindInSet
# group_concat: DoctrineExtensions\Query\Sqlite\GroupConcat
ifelse: DoctrineExtensions\Query\Sqlite\IfElse
ifnull: DoctrineExtensions\Query\Sqlite\IfNull
# match: DoctrineExtensions\Query\Sqlite\MatchAgainst
# md5: DoctrineExtensions\Query\Sqlite\Md5
# nullif: DoctrineExtensions\Query\Sqlite\NullIf
# radians: DoctrineExtensions\Query\Sqlite\Radians
# regexp: DoctrineExtensions\Query\Sqlite\Regexp
replace: DoctrineExtensions\Query\Sqlite\Replace
# sha1: DoctrineExtensions\Query\Sqlite\Sha1
# sha2: DoctrineExtensions\Query\Sqlite\Sha2
# soundex: DoctrineExtensions\Query\Sqlite\Soundex
# uuid_short: DoctrineExtensions\Query\Sqlite\UuidShort
numeric_functions:
round: DoctrineExtensions\Query\Sqlite\Round

View File

@@ -0,0 +1,28 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Acos extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'ACOS(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class AesDecrypt extends FunctionNode
{
public $field = '';
public $key = '';
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->StringExpression();
$parser->match(Lexer::T_COMMA);
$this->key = $parser->StringExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf(
'AES_DECRYPT(%s, %s)',
$this->field->dispatch($sqlWalker),
$this->key->dispatch($sqlWalker)
);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class AesEncrypt extends FunctionNode
{
public $field = '';
public $key = '';
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->StringExpression();
$parser->match(Lexer::T_COMMA);
$this->key = $parser->StringExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf(
'AES_ENCRYPT(%s, %s)',
$this->field->dispatch($sqlWalker),
$this->key->dispatch($sqlWalker)
);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class AnyValue extends FunctionNode
{
public $value;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->value = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf(
'ANY_VALUE(%s)',
$this->value->dispatch($sqlWalker)
);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Ascii extends FunctionNode
{
private $string;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'ASCII('.$sqlWalker->walkArithmeticPrimary($this->string).')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->string = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Asin extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'ASIN(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\QueryException;
class Atan extends FunctionNode
{
public $arithmeticExpression;
public $optionalSecondExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$secondArgument = '';
if ($this->optionalSecondExpression) {
$secondArgument = $sqlWalker->walkSimpleArithmeticExpression(
$this->optionalSecondExpression
);
}
return 'ATAN(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
) . (($secondArgument) ? ', ' . $secondArgument : '')
. ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
try {
$parser->match(Lexer::T_COMMA);
$this->optionalSecondExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
} catch (QueryException $e) {
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Atan2 extends FunctionNode
{
public $firstExpression;
public $secondExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$firstArgument = $sqlWalker->walkSimpleArithmeticExpression(
$this->firstExpression
);
$secondArgument = $sqlWalker->walkSimpleArithmeticExpression(
$this->secondExpression
);
return 'ATAN2(' . $firstArgument . ', ' . $secondArgument . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$this->secondExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Sarjono Mukti Aji <me@simukti.net>
*/
class Binary extends FunctionNode
{
private $stringPrimary;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'BINARY('.$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary).')';
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class BitCount extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'BIT_COUNT(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
)
. ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* "BIT_XOR" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
*/
class BitXor extends FunctionNode
{
public $firstArithmetic;
public $secondArithmetic;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return $this->firstArithmetic->dispatch($sqlWalker)
. ' ^ '
. $this->secondArithmetic->dispatch($sqlWalker);
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstArithmetic = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->secondArithmetic = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Literal;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\SqlWalker;
/**
* "CAST" "(" "$fieldIdentifierExpression" "AS" "$castingTypeExpression" ")"
*
* @example
* SELECT CAST(foo.bar AS SIGNED) FROM dual;
*
* @link https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/cookbook/dql-user-defined-functions.html#conclusion
* @link https://dev.mysql.com/doc/refman/5.6/en/cast-functions.html#function_cast
*/
class Cast extends FunctionNode
{
/** @var Node */
protected $fieldIdentifierExpression;
/** @var string */
protected $castingTypeExpression;
/**
* @param Parser $parser
*
* @throws QueryException
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->fieldIdentifierExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_AS);
$parser->match(Lexer::T_IDENTIFIER);
$type = $parser->getLexer()->token['value'];
if ($parser->getLexer()->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
$parser->match(Lexer::T_OPEN_PARENTHESIS);
/** @var Literal $parameter */
$parameter = $parser->Literal();
$parameters = [$parameter->value];
if ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
while ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$parameter = $parser->Literal();
$parameters[] = $parameter->value;
}
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$type .= '('.implode(', ', $parameters).')';
}
$this->castingTypeExpression = $type;
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* @param SqlWalker $sqlWalker
*
* @return string
*/
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
'CAST(%s AS %s)',
$sqlWalker->walkSimpleArithmeticExpression($this->fieldIdentifierExpression),
$this->castingTypeExpression
);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Ceil extends FunctionNode
{
private $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'CEIL(' . $sqlWalker->walkSimpleArithmeticExpression($this->arithmeticExpression) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Metod <metod@simpel.si>
*/
class CharLength extends FunctionNode
{
private $expr;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'CHAR_LENGTH('.$sqlWalker->walkArithmeticPrimary($this->expr1).')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* "COLLATE"
* override the default collation
* More info:
* https://dev.mysql.com/doc/refman/5.7/en/charset-collate.html
*
* @category DoctrineExtensions
* @package DoctrineExtensions\Query\Mysql
* @author Peter Tanath <peter.tanath@gmail.com>
* @license MIT License
*/
class Collate extends FunctionNode
{
/**
* @var null
*/
public $stringPrimary = null;
/**
* @var null
*/
public $collation = null;
/**
* @param \Doctrine\ORM\Query\Parser $parser
*/
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(Lexer::T_IDENTIFIER);
$lexer = $parser->getLexer();
$this->collation = $lexer->token['value'];
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* @param \Doctrine\ORM\Query\SqlWalker $sqlWalker
* @return string
*/
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf('%s COLLATE %s', $sqlWalker->walkStringPrimary($this->stringPrimary), $this->collation);
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Andrew Mackrodt <andrew@ajmm.org>
*/
class ConcatWs extends FunctionNode
{
private $values = [];
private $notEmpty = false;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
// Add the concat separator to the values array.
$this->values[] = $parser->ArithmeticExpression();
// Add the rest of the strings to the values array. CONCAT_WS must
// be used with at least 2 strings not including the separator.
$lexer = $parser->getLexer();
while (count($this->values) < 3 || $lexer->lookahead['type'] == Lexer::T_COMMA) {
$parser->match(Lexer::T_COMMA);
$peek = $lexer->glimpse();
$this->values[] = $peek['value'] == '('
? $parser->FunctionDeclaration()
: $parser->ArithmeticExpression();
}
while ($lexer->lookahead['type'] == Lexer::T_IDENTIFIER) {
switch (strtolower($lexer->lookahead['value'])) {
case 'notempty':
$parser->match(Lexer::T_IDENTIFIER);
$this->notEmpty = true;
break;
default: // Identifier not recognized (causes exception).
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
break;
}
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
// Create an array to hold the query elements.
$queryBuilder = ['CONCAT_WS('];
// Iterate over the captured expressions and add them to the query.
for ($i = 0; $i < count($this->values); $i++) {
if ($i > 0) {
$queryBuilder[] = ', ';
}
// Dispatch the walker on the current node.
$nodeSql = $sqlWalker->walkArithmeticPrimary($this->values[$i]);
if ($this->notEmpty) {
// Exclude empty strings from the concatenation.
$nodeSql = sprintf("NULLIF(%s, '')", $nodeSql);
}
$queryBuilder[] = $nodeSql;
}
// Close the query.
$queryBuilder[] = ')';
// Return the joined query.
return implode('', $queryBuilder);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Converts timezones.
*
* Allows Doctrine 2 Query Language to execute a MySQL CONVERT_TZ function.
*
* @link http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_convert-tz
*/
class ConvertTz extends FunctionNode
{
protected $dateExpression;
protected $fromTz;
protected $toTz;
/**
* {@inheritdoc}
*/
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
'CONVERT_TZ(%s, %s, %s)',
$sqlWalker->walkArithmeticExpression($this->dateExpression),
$sqlWalker->walkStringPrimary($this->fromTz),
$sqlWalker->walkStringPrimary($this->toTz)
);
}
/**
* {@inheritdoc}
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->dateExpression = $parser->ArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$this->fromTz = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->toTz = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Cos extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'COS(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Cot extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'COT(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Andrew Mackrodt <andrew@ajmm.org>
*/
class CountIf extends FunctionNode
{
private $expr1;
private $expr2;
private $inverse = false;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->ArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$this->expr2 = $parser->ArithmeticExpression();
$lexer = $parser->getLexer();
while ($lexer->lookahead['type'] == Lexer::T_IDENTIFIER) {
switch (strtolower($lexer->lookahead['value'])) {
case 'inverse':
$parser->match(Lexer::T_IDENTIFIER);
$this->inverse = true;
break;
default: // Identifier not recognized (causes exception).
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
break;
}
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf(
'COUNT(CASE %s WHEN %s THEN %s END)',
$sqlWalker->walkArithmeticPrimary($this->expr1),
$sqlWalker->walkArithmeticPrimary($this->expr2),
!$this->inverse ? '1 ELSE NULL' : 'NULL ELSE 1'
);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Igor Timoshenko <igor.timoshenko@i.ua>
*/
class Crc32 extends FunctionNode
{
public $stringPrimary;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'CRC32(' .
$sqlWalker->walkStringPrimary($this->stringPrimary) .
')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Steve Lacey <steve@stevelacey.net>
*/
class Date extends FunctionNode
{
public $date;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DATE(' . $sqlWalker->walkArithmeticPrimary($this->date) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->date = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\QueryException;
class DateAdd extends FunctionNode
{
public $firstDateExpression = null;
public $intervalExpression = null;
public $unit = null;
protected static $allowedUnits = [
'MICROSECOND',
'SECOND',
'MINUTE',
'HOUR',
'DAY',
'WEEK',
'MONTH',
'QUARTER',
'YEAR',
'SECOND_MICROSECOND',
'MINUTE_MICROSECOND',
'MINUTE_SECOND',
'HOUR_MICROSECOND',
'HOUR_SECOND',
'HOUR_MINUTE',
'DAY_MICROSECOND',
'DAY_SECOND',
'DAY_MINUTE',
'DAY_HOUR',
'YEAR_MONTH',
];
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstDateExpression = $parser->ArithmeticFactor();
$parser->match(Lexer::T_COMMA);
$this->intervalExpression = $parser->ArithmeticFactor();
$parser->match(Lexer::T_COMMA);
$this->unit = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$unit = strtoupper(is_string($this->unit) ? $this->unit : $this->unit->value);
if (!in_array($unit, self::$allowedUnits)) {
throw QueryException::semanticalError('DATE_ADD() does not support unit "' . $unit . '".');
}
return 'DATE_ADD(' .
$sqlWalker->walkArithmeticTerm($this->firstDateExpression) . ', INTERVAL ' .
$sqlWalker->walkArithmeticTerm($this->intervalExpression) . ' ' . $unit .
')';
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class DateDiff extends FunctionNode
{
public $firstDateExpression = null;
public $secondDateExpression = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstDateExpression = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->secondDateExpression = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DATEDIFF(' .
$sqlWalker->walkArithmeticTerm($this->firstDateExpression) . ', ' .
$sqlWalker->walkArithmeticTerm($this->secondDateExpression) .
')';
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Steve Lacey <steve@stevelacey.net>
*/
class DateFormat extends FunctionNode
{
public $dateExpression = null;
public $patternExpression = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->dateExpression = $parser->ArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$this->patternExpression = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DATE_FORMAT(' .
$this->dateExpression->dispatch($sqlWalker) . ', ' .
$this->patternExpression->dispatch($sqlWalker) .
')';
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\QueryException;
/**
* Class DateSub
* @package DoctrineExtensions\Query\Mysql
*
* @author Vas N <phpvas@gmail.com>
*/
class DateSub extends DateAdd
{
/**
* @param \Doctrine\ORM\Query\SqlWalker $sqlWalker
* @throws QueryException
* @return string
*/
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$unit = strtoupper(is_string($this->unit) ? $this->unit : $this->unit->value);
if (!in_array($unit, self::$allowedUnits)) {
throw QueryException::semanticalError('DATE_SUB() does not support unit "' . $unit . '".');
}
return 'DATE_SUB(' .
$this->firstDateExpression->dispatch($sqlWalker) . ', INTERVAL ' .
$this->intervalExpression->dispatch($sqlWalker) . ' ' . $unit .
')';
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Rafael Kassner <kassner@gmail.com>
* @author Sarjono Mukti Aji <me@simukti.net>
*/
class Day extends FunctionNode
{
public $date;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DAY(' . $sqlWalker->walkArithmeticPrimary($this->date) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->date = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Steve Lacey <steve@stevelacey.net>
*/
class DayName extends FunctionNode
{
public $date;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DAYNAME(' . $sqlWalker->walkArithmeticPrimary($this->date) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->date = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class DayOfWeek extends FunctionNode
{
public $date;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DAYOFWEEK(' . $sqlWalker->walkArithmeticPrimary($this->date) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->date = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class DayOfYear extends FunctionNode
{
/**
* @var \Doctrine\ORM\Query\AST\Node
*/
public $date;
/**
* @inheritdoc
*/
public function getSql(SqlWalker $sqlWalker)
{
return 'DAYOFYEAR(' . $sqlWalker->walkArithmeticPrimary($this->date) . ')';
}
/**
* @inheritdoc
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->date = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Degrees extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DEGREES(' .
$sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
) .
')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Performs an integer division. This is a MySQL operator, implemented as a Doctrine function.
*
* @see http://dev.mysql.com/doc/refman/en/arithmetic-functions.html#operator_div
*/
class Div extends FunctionNode
{
/**
* @var \Doctrine\ORM\Query\AST\Node
*/
private $dividend;
/**
* @var \Doctrine\ORM\Query\AST\Node
*/
private $divisor;
/**
* @inheritdoc
*/
public function getSql(SqlWalker $sqlWalker)
{
return
$sqlWalker->walkArithmeticPrimary($this->dividend) . ' DIV ' .
$sqlWalker->walkArithmeticPrimary($this->divisor);
}
/**
* @inheritdoc
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->dividend = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->divisor = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Exp extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'EXP(' . $sqlWalker->walkSimpleArithmeticExpression(
$this->arithmeticExpression
) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\QueryException;
/**
* @author Ahwalian Masykur <ahwalian@gmail.com>
*/
class Extract extends DateAdd
{
public $date = null;
public $unit = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(Lexer::T_IDENTIFIER);
$lexer = $parser->getLexer();
$this->unit = $lexer->token['value'];
$parser->match(Lexer::T_IDENTIFIER);
$this->date = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$unit = strtoupper($this->unit);
if (!in_array($unit, self::$allowedUnits)) {
throw QueryException::semanticalError('EXTRACT() does not support unit "' . $unit . '".');
}
return 'EXTRACT(' . $unit . ' FROM '. $this->date->dispatch($sqlWalker) . ')';
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Jeremy Hicks <jeremy.hicks@gmail.com>
*/
class Field extends FunctionNode
{
private $field = null;
private $values = [];
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
// Do the field.
$this->field = $parser->ArithmeticPrimary();
// Add the strings to the values array. FIELD must
// be used with at least 1 string not including the field.
$lexer = $parser->getLexer();
while (count($this->values) < 1 ||
$lexer->lookahead['type'] != Lexer::T_CLOSE_PARENTHESIS) {
$parser->match(Lexer::T_COMMA);
$this->values[] = $parser->ArithmeticPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$query = 'FIELD(';
$query .= $this->field->dispatch($sqlWalker);
$query .= ', ';
for ($i = 0; $i < count($this->values); $i++) {
if ($i > 0) {
$query .= ', ';
}
$query .= $this->values[$i]->dispatch($sqlWalker);
}
$query .= ')';
return $query;
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class FindInSet extends FunctionNode
{
public $needle = null;
public $haystack = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->needle = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$this->haystack = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'FIND_IN_SET(' .
$this->needle->dispatch($sqlWalker) . ', ' .
$this->haystack->dispatch($sqlWalker) .
')';
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Floor extends FunctionNode
{
private $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'FLOOR(' . $sqlWalker->walkSimpleArithmeticExpression($this->arithmeticExpression) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Nima S <nimasdj@yahoo.com>
*/
class FromUnixtime extends FunctionNode
{
public $time;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'FROM_UNIXTIME(' . $sqlWalker->walkArithmeticPrimary($this->time) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->time = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Class Greatest
* @package DoctrineExtensions\Query\Mysql
*
* @author Vas N <phpvas@gmail.com>
* @author Guven Atbakan <guven@atbakan.com>
*/
class Greatest extends FunctionNode
{
private $field = null;
private $values = [];
/**
* @param Parser $parser
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->ArithmeticExpression();
$lexer = $parser->getLexer();
while (count($this->values) < 1 ||
$lexer->lookahead['type'] != Lexer::T_CLOSE_PARENTHESIS) {
$parser->match(Lexer::T_COMMA);
$this->values[] = $parser->ArithmeticExpression();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* @param SqlWalker $sqlWalker
* @return string
*/
public function getSql(SqlWalker $sqlWalker)
{
$query = 'GREATEST(';
$query .= $this->field->dispatch($sqlWalker);
$query .= ', ';
for ($i = 0; $i < count($this->values); $i++) {
if ($i > 0) {
$query .= ', ';
}
$query .= $this->values[$i]->dispatch($sqlWalker);
}
$query .= ')';
return $query;
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class GroupConcat extends FunctionNode
{
public $isDistinct = false;
public $pathExp = null;
public $separator = null;
public $orderBy = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$lexer = $parser->getLexer();
if ($lexer->isNextToken(Lexer::T_DISTINCT)) {
$parser->match(Lexer::T_DISTINCT);
$this->isDistinct = true;
}
// first Path Expression is mandatory
$this->pathExp = [];
if ($lexer->isNextToken(Lexer::T_IDENTIFIER)) {
$this->pathExp[] = $parser->StringExpression();
} else {
$this->pathExp[] = $parser->SingleValuedPathExpression();
}
while ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->pathExp[] = $parser->StringPrimary();
}
if ($lexer->isNextToken(Lexer::T_ORDER)) {
$this->orderBy = $parser->OrderByClause();
}
if ($lexer->isNextToken(Lexer::T_IDENTIFIER)) {
if (strtolower($lexer->lookahead['value']) !== 'separator') {
$parser->syntaxError('separator');
}
$parser->match(Lexer::T_IDENTIFIER);
$this->separator = $parser->StringPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
$result = 'GROUP_CONCAT(' . ($this->isDistinct ? 'DISTINCT ' : '');
$fields = [];
foreach ($this->pathExp as $pathExp) {
$fields[] = $pathExp->dispatch($sqlWalker);
}
$result .= sprintf('%s', implode(', ', $fields));
if ($this->orderBy) {
$result .= ' '.$sqlWalker->walkOrderByClause($this->orderBy);
}
if ($this->separator) {
$result .= ' SEPARATOR '.$sqlWalker->walkStringPrimary($this->separator);
}
$result .= ')';
return $result;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Hex extends FunctionNode
{
public $arithmeticExpression;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'HEX(' . $sqlWalker->walkSimpleArithmeticExpression($this->arithmeticExpression) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->arithmeticExpression = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Dawid Nowak <macdada@mmg.pl>
*/
class Hour extends FunctionNode
{
public $date;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'HOUR('.$sqlWalker->walkArithmeticPrimary($this->date).')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->date = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Andrew Mackrodt <andrew@ajmm.org>
*/
class IfElse extends FunctionNode
{
private $expr = [];
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expr[] = $parser->ConditionalExpression();
for ($i = 0; $i < 2; $i++) {
$parser->match(Lexer::T_COMMA);
$this->expr[] = $parser->ArithmeticExpression();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf(
'IF(%s, %s, %s)',
$sqlWalker->walkConditionalExpression($this->expr[0]),
$sqlWalker->walkArithmeticPrimary($this->expr[1]),
$sqlWalker->walkArithmeticPrimary($this->expr[2])
);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace DoctrineExtensions\Query\Mysql;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* @author Andrew Mackrodt <andrew@ajmm.org>
*/
class IfNull extends FunctionNode
{
private $expr1;
private $expr2;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->ArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$this->expr2 = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'IFNULL('
.$sqlWalker->walkArithmeticPrimary($this->expr1). ', '
.$sqlWalker->walkArithmeticPrimary($this->expr2).')';
}
}

Some files were not shown because too many files have changed in this diff Show More