Skip to content
This repository was archived by the owner on Jul 11, 2023. It is now read-only.

Commit 444bd29

Browse files
PHP resources cannot be serialized so default in this case to empty string.
Extract tha data serialization into trait so it can be potentially reused. This bumps the minimum supported PHP version to 5.4
1 parent 2144335 commit 444bd29

5 files changed

Lines changed: 186 additions & 73 deletions

File tree

EventListener/ErrorLogSubscriber.php

Lines changed: 51 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,114 +3,100 @@
33
namespace Oh\FormErrorLogBundle\EventListener;
44

55
use Oh\FormErrorLogBundle\Logger\ErrorLogInterface;
6-
use Symfony\Component\Form\FormEvent;
6+
use Oh\FormErrorLogBundle\Logger\SerializeData;
77
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
8+
use Symfony\Component\Form\FormEvent;
89
use Symfony\Component\Form\FormEvents;
910
use Symfony\Component\HttpFoundation\RequestStack;
1011

1112
class ErrorLogSubscriber implements EventSubscriberInterface
1213
{
14+
use SerializeData;
15+
1316
/**
1417
* Whatever you want to use as the logger
15-
* @var Oh\FormErrorLogBundle\Logger\ErrorLogInterface
18+
* @var ErrorLogInterface
1619
*/
1720
private $logger;
18-
21+
1922
/**
2023
* This is to log the request variables if the form data can't be logged
21-
* @var Symfony\Component\HttpFoundation\Request
24+
* @var Symfony\Component\HttpFoundation\Request
2225
*/
2326
private $request;
2427

28+
/**
29+
* @param ErrorLogInterface $logger
30+
* @param RequestStack $request
31+
*/
2532
public function __construct(ErrorLogInterface $logger, RequestStack $request)
2633
{
2734
$this->logger = $logger;
2835
$this->request = $request->getMasterRequest();
2936
}
3037

38+
/**
39+
* @return array
40+
*/
3141
public static function getSubscribedEvents()
3242
{
33-
return array(FormEvents::POST_SUBMIT => 'postSubmit');
43+
return [
44+
FormEvents::POST_SUBMIT => 'postSubmit',
45+
];
3446
}
3547

3648
/**
37-
*
3849
* @param \Symfony\Component\Form\FormEvent $event
39-
* @return null
4050
*/
4151
public function postSubmit(FormEvent $event)
4252
{
4353
$form = $event->getForm();
44-
54+
4555
$errors = $this->getErrorMessages($form);
46-
47-
if(empty($errors)) {
48-
return null;
56+
57+
if (empty($errors)) {
58+
return;
4959
}
50-
60+
5161
$formName = $form->getName();
5262

53-
foreach($errors as $key => $error) {
63+
foreach ($errors as $key => $error) {
5464
$uri = $this->request->getUri();
5565
$this->logger->log($formName, $key, $error['messages'], $error['value'], $uri);
5666
}
57-
58-
return null;
5967
}
60-
61-
private function getErrorMessages(\Symfony\Component\Form\Form $form) {
62-
63-
$errors = array();
64-
68+
69+
/**
70+
* @param \Symfony\Component\Form\Form $form
71+
* @return array
72+
*/
73+
private function getErrorMessages(\Symfony\Component\Form\Form $form)
74+
{
75+
$errors = [];
76+
6577
/* Get the errors from this FormType */
6678
foreach ($form->getErrors() as $key => $error) {
6779
$data = $form->getData();
68-
69-
/* If it's a bound object then we need to log it somehow */
70-
if(is_object($data))
71-
{
72-
// JsonSerializable is for php 5.4
73-
if(class_exists('\JsonSerializable', false) && $data instanceof \JsonSerializable) {
74-
$data = json_encode($data);
75-
}
76-
// otherwise we could just see if that method exists
77-
elseif(method_exists($data, 'jsonSerialize'))
78-
{
79-
$data = json_encode($data->jsonSerialize());
80-
}
81-
// some people create a toArray() method
82-
elseif(method_exists($data, 'toArray') && is_array($array = $data->toArray()))
83-
{
84-
// JSON_PRETTY_PRINT is > PHP 5.4
85-
if(defined('JSON_PRETTY_PRINT')) {
86-
$data = json_encode($array, JSON_PRETTY_PRINT);
87-
}else {
88-
$data = json_encode($array);
89-
}
90-
91-
}
92-
// lets try to serialize
93-
// this could be risky if the object is too large or not implemented correctly
94-
elseif(method_exists($data, '__sleep') || $data instanceof Serializable) {
95-
$data = @serialize($data);
96-
}
97-
// lets see if we can get the form data from the request
98-
elseif($this->request->request->has($form->getName())) {
99-
// lets log it
100-
$data = 'POST DATA: '.json_encode($this->request->request->get($form->getName()));
101-
}
102-
// it looks like the object isnt loggable
103-
else {
104-
$data = '';
105-
}
80+
81+
$serializedData = $this->serializeData($data);
82+
if (empty($serializedData)) {
83+
$formData = $this->request->request->has($form->getName())
84+
? $this->request->request->get($form->getName())
85+
: null;
86+
$serializedData = 'POST DATA: '.json_encode($formData);
10687
}
107-
$errors[$key] = array('messages'=>$error->getMessage(), 'value'=>$data);
88+
89+
$errors[$key] = [
90+
'messages' => $error->getMessage(),
91+
'value' => $serializedData,
92+
];
10893
}
94+
10995
if ($form->count() > 0) {
11096
foreach ($form->all() as $child) {
11197
if (!$child->isValid()) {
11298
$childErrors = $this->getErrorMessages($child);
113-
$messages = $values = array();
99+
$messages = $values = [];
114100
foreach($childErrors as $childError) {
115101
$messages[] = $childError['messages'];
116102
$values[] = $childError['value'];
@@ -120,11 +106,14 @@ private function getErrorMessages(\Symfony\Component\Form\Form $form) {
120106
$messages = implode(' | ', $messages);
121107
$values = implode(' | ', $values);
122108

123-
$errors[$child->getName()] = array('messages'=>$messages, 'value'=>$values);
109+
$errors[$child->getName()] = [
110+
'messages' => $messages,
111+
'value' => $values,
112+
];
124113
}
125114
}
126115
}
127-
116+
128117
return $errors;
129118
}
130119
}

Logger/DatabaseLogger.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,26 @@
1111

1212
class DatabaseLogger implements ErrorLogInterface
1313
{
14+
use SerializeData;
15+
16+
/**
17+
* @var EntityManagerInterface
18+
*/
1419
private $em;
1520

21+
/**
22+
* @var string
23+
*/
1624
private $entityClass;
1725

26+
/**
27+
* @var EventDispatcherInterface
28+
*/
1829
private $eventDispatcher;
1930

2031
/**
2132
* @param EntityManagerInterface $em
22-
* @param $entityClass
33+
* @param string $entityClass
2334
* @param EventDispatcherInterface $eventDispatcher
2435
*/
2536
public function __construct(EntityManagerInterface $em, $entityClass, EventDispatcherInterface $eventDispatcher)
@@ -29,6 +40,14 @@ public function __construct(EntityManagerInterface $em, $entityClass, EventDispa
2940
$this->eventDispatcher = $eventDispatcher;
3041
}
3142

43+
/**
44+
* @param string $formName
45+
* @param string $key
46+
* @param string $error
47+
* @param string $value
48+
* @param string $uri
49+
* @throws InvalidArgumentException
50+
*/
3251
public function log($formName, $key, $error, $value = '', $uri = '')
3352
{
3453
if ($this->entityClass === 'Oh\FormErrorLogBundle\Entity\FormErrorLogEntityInterface') {
@@ -41,7 +60,7 @@ public function log($formName, $key, $error, $value = '', $uri = '')
4160
$entity->setFormName($formName);
4261
$entity->setField($key);
4362
$entity->setError($error);
44-
$entity->setValue(serialize($value));
63+
$entity->setValue($value);
4564
// for BC
4665
if (method_exists($entity, 'setUri')) {
4766
$entity->setUri($uri);

Logger/Logger.php

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ class Logger implements ErrorLogInterface
1212
*/
1313
private $logger;
1414

15+
/**
16+
* @param MonologLogger $logger
17+
*/
1518
public function __construct(MonologLogger $logger)
1619
{
1720
$this->logger = $logger;
@@ -22,16 +25,20 @@ public function __construct(MonologLogger $logger)
2225
* @param string $key
2326
* @param string $error
2427
* @param string $value
25-
* @return void
28+
* @param string $uri
2629
*/
2730
public function log($formName, $key, $error, $value = '', $uri = '')
2831
{
29-
$this->logger->notice(strtr('%0 - Error in form "%1" in position "%2": "%3" with serialized value "%4"', array(
30-
'%0' => $uri,
31-
'%1' => $formName,
32-
'%2' => $key,
33-
'%3' => $error,
34-
'%4' => serialize($value),
35-
)));
32+
$logMessage = strtr(
33+
'%0 - Error in form "%1" in position "%2": "%3" with serialized value "%4"',
34+
[
35+
'%0' => $uri,
36+
'%1' => $formName,
37+
'%2' => $key,
38+
'%3' => $error,
39+
'%4' => $value,
40+
]
41+
);
42+
$this->logger->notice($logMessage);
3643
}
3744
}

Logger/SerializeData.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
namespace Oh\FormErrorLogBundle\Logger;
4+
5+
trait SerializeData
6+
{
7+
private function serialize($data)
8+
{
9+
if (is_object($data)) {
10+
return $this->serializeObject($data);
11+
} elseif (is_resource($data)) {
12+
return $this->serializeResource($data);
13+
} elseif (is_array($data)) {
14+
return $this->serializeArray($data);
15+
} else {
16+
return $this->serializeNonObject($data);
17+
}
18+
}
19+
20+
private function serializeObject($object)
21+
{
22+
$data = '';
23+
24+
// JsonSerializable is for php 5.4
25+
if (class_exists('\JsonSerializable', false) && $object instanceof \JsonSerializable) {
26+
$data = json_encode($object);
27+
28+
// otherwise we could just see if that method exists
29+
} elseif (method_exists($object, 'jsonSerialize')) {
30+
$data = json_encode($object->jsonSerialize());
31+
32+
// some people create a toArray() method
33+
} elseif (method_exists($object, 'toArray') && is_array($array = $object->toArray())) {
34+
// JSON_PRETTY_PRINT is > PHP 5.4
35+
if (defined('JSON_PRETTY_PRINT')) {
36+
$data = json_encode($array, JSON_PRETTY_PRINT);
37+
} else {
38+
$data = json_encode($array);
39+
}
40+
41+
// lets try to serialize
42+
// this could be risky if the object is too large or not implemented correctly
43+
} elseif (method_exists($object, '__sleep') || $object instanceof Serializable) {
44+
$data = @serialize($object);
45+
}
46+
47+
return $data;
48+
}
49+
50+
/**
51+
* @param resource $resource
52+
* @return string
53+
*/
54+
private function serializeResource($resource)
55+
{
56+
// we cann't serialize PHP resources
57+
return '';
58+
}
59+
60+
/**
61+
* @param array $array
62+
* @return string
63+
*/
64+
private function serializeArray($array)
65+
{
66+
foreach ($array as &$value) {
67+
if (is_object($value)) {
68+
$value = $this->serializeObject($value);
69+
} elseif (is_resource($value)) {
70+
$value = $this->serializeResource($value);
71+
}
72+
}
73+
74+
return $this->serializeNonObject($array);
75+
}
76+
77+
/**
78+
* @param int|string|array|null $nonObject
79+
* @return string
80+
*/
81+
private function serializeNonObject($nonObject)
82+
{
83+
$data = '';
84+
try {
85+
$data = serialize($nonObject);
86+
} catch (\Throwable $t) {
87+
// do nothing, will catch in PHP >= 7.0
88+
} catch (\Exception $e) {
89+
// do nothing, will catch in PHP <= 5.6
90+
} finally {
91+
return $data;
92+
}
93+
}
94+
}

composer.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212
{
1313
"name": "Ollie Harridge",
1414
"email": "code@oll.ie"
15+
},
16+
{
17+
"name": "Lendable Developers",
18+
"email": "dev@lendable.co.uk"
1519
}
1620
],
1721
"require": {
18-
"php": ">=5.3.2",
22+
"php": ">=5.4",
1923
"symfony/symfony": "^2|^3"
2024
},
2125
"autoload": {

0 commit comments

Comments
 (0)