wkhtmltopdf   F
last analyzed

Complexity

Total Complexity 66

Size/Duplication

Total Lines 171
Duplicated Lines 12.87 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 22
loc 171
rs 3.12
c 0
b 0
f 0
ccs 0
cts 140
cp 0
wmc 66
lcom 1
cbo 1

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 5 17 3
B generateFromURL() 17 45 10
A setCookieList() 0 7 3
A setCookie() 0 3 1
A setCover() 0 3 1
A setHeaderList() 0 7 3
A setHeader() 0 3 1
A setOptionList() 0 7 3
D setOption() 0 59 41

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like wkhtmltopdf often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use wkhtmltopdf, and based on these observations, apply Extract Interface, too.

1
<?php
2
	class wkhtmltopdf {
3
		protected $config;
4
		protected $headers;
5
		protected $cookies;
6
		protected $options;
7
		protected $cover;
8
9
10
		public function __construct( $config = array() ) {
11
			if (!$config['cmd']) {
12
				$config['cmd'] = '/usr/bin/xvfb-run -a /usr/local/bin/wkhtmltopdf --disable-local-file-access ';
13
			}
14
15 View Code Duplication
			if (!$config['temp']) {
16
				$context = pobject::getContext();
17
				$me = $context["arCurrentObject"];
18
				$config['temp'] = $me->store->get_config( "files" ) . "temp/";
19
			}
20
21
			$this->config = $config;
22
			$this->options = array();
23
			$this->cookies = array();
24
			$this->headers = array();
25
			$this->cover = false;
26
		}
27
28
29
		public function generateFromURL( $url ) {
30
			if ( !preg_match( '|^https?://|', $url ) ) {
31
				return ar_error::raiseError( "wkhtmltopdf: '$url' is not a valid URL", 201 );
32
			}
33
34
			$url = escapeshellarg( $url );
35
			$tempFile = tempnam( $this->config['temp'], 'pdf' );
36
			if ( !$tempFile ) {
37
				return ar_error::raiseError( "wkhtmltopdf: could not create a temporary file", 202 );
38
			}
39
40
			$execString = $this->config['cmd'];
41 View Code Duplication
			foreach ($this->options as $name => $value) {
42
				if ( is_bool( $value ) ) {
43
					$execString .= " --$name";
44
				} else {
45
					$execString .= " --$name " . escapeshellarg( $value );
46
				}
47
			}
48
49 View Code Duplication
			foreach ($this->cookies as $name => $value) {
50
				$execString .= " --cookie " . escapeshellarg( $name ) . " " . escapeshellarg( $value );
51
			}
52
53 View Code Duplication
			foreach ($this->headers as $name => $value) {
54
				$execString .= " --custom-header " . escapeshellarg( $name ) . " " . escapeshellarg( $value );
55
			}
56
57
			if ($this->cover) {
58
				$execString .= " cover " . escapeshellarg( $this->cover );
59
			}
60
61
			$execString .= " $url $tempFile";
62
			$execOutput = array();
63
			$execResult = 0;
64
65
			exec( $execString, $execOutput, $execResult );
66 View Code Duplication
			if ( $execResult != 0 && $execResult != 2 ) { // code 2 is for 404's encountered
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $execResult of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
67
				@unlink( $tempFile );
68
				return ar_error::raiseError( "wkhtmltopdf: error ($execResult) while trying to generate PDF: " . implode( "\n", (array) $execOutput ), 203 );
69
			}
70
71
			readfile( $tempFile );
72
			unlink( $tempFile );
73
		}
74
75
		public function setCookieList( $cookieList = array() ) {
76
			if ( is_array($cookieList) ) {
77
				foreach( $cookieList as $name => $value) {
78
					$this->setOption( $name, $value );
79
				}
80
			}
81
		}
82
83
		public function setCookie($name, $value = null) {
84
			$this->cookies[ $name ] = $value;
85
		}
86
87
		public function setCover($url) {
88
			$this->cover = $url;
89
		}
90
91
		public function setHeaderList( $headerList = array() ) {
92
			if ( is_array($headerList) ) {
93
				foreach( $headerList as $name => $value) {
94
					$this->setHeader( $name, $value );
95
				}
96
			}
97
		}
98
99
100
		public function setHeader($name, $value = null) {
101
			$this->headers[ $name ] = $value;
102
		}
103
104
105
		public function setOptionList( $optionList = array() ) {
106
			if ( is_array($optionList) ) {
107
				foreach( $optionList as $name => $value) {
108
					$this->setOption( $name, $value );
109
				}
110
			}
111
		}
112
113
		public function setOption($name, $value = null) {
114
			if ($value === null) {
115
				unset( $this->options[ $name ] );
116
				return true;
117
			}
118
			switch ($name) {
119
				case 'collate':
120
				case 'grayscale':
121
				case 'ignore-load-errors':
122
				case 'lowquality':
123
				case 'no-background':
124
				case 'print-media-type':
125
					$this->options[ $name ] = true;
126
				break;
127
				case 'copies':
128
				case 'dpi':
129
				case 'minimum-font-size':
130
				case 'page-offset':
131
					$this->options[ $name ] = (int) $value;
132
				break;
133
				case 'margin-bottom':
134
				case 'margin-top':
135
				case 'margin-left':
136
				case 'margin-right':
137
				case 'footer-center':
138
				case 'footer-font-name':
139
				case 'footer-font-size':
140
				case 'footer-html':
141
				case 'footer-line':
142
				case 'footer-right':
143
				case 'footer-left':
144
				case 'footer-spacing':
145
				case 'header-center':
146
				case 'header-font-name':
147
				case 'header-font-size':
148
				case 'header-html':
149
				case 'header-line':
150
				case 'header-right':
151
				case 'header-left':
152
				case 'header-spacing':
153
154
				case 'encoding':
155
				case 'orientation':
156
				case 'page-height':
157
				case 'page-size':
158
				case 'page-width':
159
				case 'username':
160
				case 'password':
161
				case 'title':
162
					$this->options[ $name ] = (string) $value;
163
				break;
164
				case 'zoom':
165
					$this->options[ $name ] = (float) $value;
166
				break;
167
				default:
168
					return false;
169
			}
170
			return true;
171
		}
172
	}
173
174
175
	class pinp_wkhtmltopdf {
176
		private $instance;
177
178
		public function __construct( $options = array() ) {
179
			$this->instance = new wkhtmltopdf();
180
			$this->instance->setOptionList( $options );
181
		}
182
183
		public function _generateFromURL( $url ) {
184
			return $this->instance->generateFromURL( $url );
185
		}
186
187
		public static function _get( $options = array() ) {
188
			return new pinp_wkhtmltopdf( $options );
189
		}
190
		public function _setCover( $url ) {
191
			return $this->instance->setCover( $url );
192
		}
193
	}
194