Completed
Push — master ( 5c5d67...fe7cae )
by Roberto
31:11 queued 28:45
created

DefaultPrinter   D

Complexity

Total Complexity 96

Size/Duplication

Total Lines 1037
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 77.6%

Importance

Changes 9
Bugs 0 Features 0
Metric Value
wmc 96
c 9
b 0
f 0
lcom 1
cbo 2
dl 0
loc 1037
ccs 284
cts 366
cp 0.776
rs 4.4311

39 Methods

Rating   Name   Duplication   Size   Complexity  
setPrintMode() 0 1 ?
A __construct() 0 7 2
A defaultRegionPage() 0 14 4
A defaultCodePage() 0 15 4
A setCodePage() 0 5 1
A setRegionPage() 0 6 1
A defaultFont() 0 18 4
A setFont() 0 6 1
A setBold() 0 11 2
A setUnderlined() 0 11 2
A setItalic() 0 4 1
A setAlign() 0 18 4
A setReverseColors() 0 11 2
A setExpanded() 0 16 1
A setCondensed() 0 5 1
A setRotate90() 0 11 2
A initialize() 0 10 1
A text() 0 5 1
A setSpacing() 0 6 1
A setCharSpacing() 0 5 1
A setParagraph() 0 15 4
A lineFeed() 0 9 2
A dotFeed() 0 5 1
A pulse() 0 7 1
A cut() 0 10 2
B barcode() 0 44 6
B barcodeQRCode() 0 38 6
A close() 0 4 1
C getBuffer() 0 35 7
A send() 0 13 4
B validateBarcodeData() 0 32 2
B putImage() 0 19 5
A sendGraphicsData() 0 5 1
A intLowHigh() 0 10 2
A dataHeader() 0 13 3
A validateBoolean() 0 7 3
A validateInteger() 0 7 4
A validateString() 0 7 3
A translate() 0 11 3

How to fix   Complexity   

Complex Class

Complex classes like DefaultPrinter 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 DefaultPrinter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Posprint\Printers;
4
5
/*
6
 * Default class for POS thermal printers.
7
 * 
8
 * From this class all other are extended.
9
 * In the child classes should be included all the commands that are different
10
 * from those in this class, especially those specific to particular brand and 
11
 * model of printer
12
 * 
13
 * NOTE: It was built around the commands of the Epson TM-T20,
14
 * so in theory the Epson class will be almost empty just extending this class.
15
 * 
16
 * CodePage default CP437
17
 * CountyPage default LATIN
18
 * 
19
 * @category   NFePHP
20
 * @package    Posprint
21
 * @copyright  Copyright (c) 2016
22
 * @license    http://www.gnu.org/licenses/lesser.html LGPL v3
23
 * @author     Roberto L. Machado <linux.rlm at gmail dot com>
24
 * @link       http://github.com/nfephp-org/posprint for the canonical source repository
25
 */
26
27
use Posprint\Connectors\ConnectorInterface;
28
use Posprint\Connectors\Buffer;
29
use Posprint\Graphics\Graphics;
30
use RuntimeException;
31
use InvalidArgumentException;
32
33
abstract class DefaultPrinter implements PrinterInterface
34
{
35
    //set standards
36
    const NUL = "\x0"; //Nulo
37
    const EOT = "\x4"; //EOT fim da transmissão
38
    const ENQ = "\x5"; //ENQ colocar na fila Pedido de status 1
39
    const HT = "\x9"; //tabulação horizontal
40
    const VT = "\xb"; //tabulação vertical
41
    const LF = "\x0a"; //Inicia a impressão e avança uma linha
42
    const FF = "\x0c"; //avança pagina
43
    const CR = "\x0d"; //retorno de carro
44
    const DLE = "\x10"; //Data Link Escape
45
    const CAN = "\x18"; //CAN Cancela linha enviada
46
    const BEL = "\x07"; //BEL sinal sonoro
47
    const ESC = "\x1b"; //escape
48
    const FS = "\x1c"; //FS
49
    const GS = "\x1d"; //GS
50
    const SO = "\x0e"; //SO Inicia modo expandido
51
    const DC1 = "\x11"; //DC1 Inicia modo enfatizado
52
    const DC2 = "\x12"; //DC2 Cancela modo condensado
53
    const DC3 = "\x13"; //DC3 Cancela modo enfatizado
54
    const DC4 = "\x14"; //DC4 Controle de dispositivo 4 Inicia modo normal
55
    const SI = "\x0f"; //Seleciona modo condensado
56
    const EM = "\x19"; //Avança 4 linhas
57
    const DEL = "\x7f"; //Cancela último caracter
58
    const SYN = "\x16"; //Sincronismo
59
    const NOTRANS = false; //not translate characters codepage
60
    const TRANS = true; //perform a character convertion to codepage
61
62
    //Cut types
63
    const CUT_FULL = 65;
64
    const CUT_PARTIAL = 66;
65
    
66
    //Image sizing options
67
    const IMG_DEFAULT = 0;
68
    const IMG_DOUBLE_WIDTH = 1;
69
    const IMG_DOUBLE_HEIGHT = 2;
70
71
    //1D barcode types
72
    const UPC_A = 'A';
73
    const UPC_E = 'B';
74
    const EAN13 = 'C';
75
    const EAN8 = 'D';
76
    const CODE39 = 'E';
77
    const ITF = 'F';
78
    const CODABAR = 'G';
79
    const CODE93 = 'H';
80
    const CODE128 = 'I';
81
    const GS1_128 = 'J';
82
    const GS1_DATABAR_OMINIDIRETIONAL = 'K';
83
    const GS1_DATABAR_TRUNCATED = 'L';
84
    const GS1_DATABAR_LIMITED = 'M';
85
    const GS1_DATABAR_EXPANDED = 'N';
86
87
    /**
88
     * List all available region pages.
89
     *
90
     * @var array
91
     */
92
    protected $aRegion = array(
93
        'USA',
94
        'FRANCE',
95
        'GERMANY',
96
        'UK',
97
        'DENMARK',
98
        'SWEDEN',
99
        'ITALY',
100
        'SPAIN',
101
        'JAPAN',
102
        'NORWAY',
103
        'DENMARK2',
104
        'SPAIN2',
105
        'LATIN',
106
        'KOREA',
107
        'SLOVENIA',
108
        'CHINA',
109
        'VIETNAM',
110
        'ARABIA',
111
    );
112
113
    /**
114
     * List all available code pages.
115
     *
116
     * @var array
117
     */
118
    protected $aCodePage = array(
119
        'CP437' => array('conv' => '437', 'table' => '0', 'desc' => 'PC437: USA, Standard Europe'),
120
        'CP850' => array('conv' => '850', 'table' => '2', 'desc' => 'PC850: Multilingual'),
121
        'CP860' => array('conv' => '860', 'table' => '3', 'desc' => 'PC860: Portuguese'),
122
        'CP863' => array('conv' => '863', 'table' => '4', 'desc' => 'PC863: Canadian-French'),
123
        'CP865' => array('conv' => '865', 'table' => '5', 'desc' => 'PC865: Nordic'),
124
        'CP851' => array('conv' => '851', 'table' => '11', 'desc' => 'PC851: Greek'),
125
        'CP853' => array('conv' => '853', 'table' => '12', 'desc' => 'PC853: Turkish'),
126
        'CP857' => array('conv' => '857', 'table' => '13', 'desc' => 'PC857: Turkish'),
127
        'CP737' => array('conv' => '737', 'table' => '14', 'desc' => 'PC737: Greek'),
128
        'ISO8859-7' => array('conv' => 'ISO8859-7', 'table' => '15', 'desc' => 'ISO8859-7: Greek'),
129
        'CP866' => array('conv' => '866', 'table' => '17', 'desc' => 'PC866: Cyrillic #2'),
130
        'CP852' => array('conv' => '852', 'table' => '18', 'desc' => 'PC852: Latin2'),
131
        'CP858' => array('conv' => '858', 'table' => '19', 'desc' => 'PC858: Euro'),
132
        'CP720' => array('conv' => '720', 'table' => '32', 'desc' => 'PC720: Arabic'),
133
        'CP855' => array('conv' => '855', 'table' => '34', 'desc' => 'PC855: Cyrillic'),
134
        'CP861' => array('conv' => '861', 'table' => '35', 'desc' => 'PC861: Icelandic'),
135
        'CP862' => array('conv' => '862', 'table' => '36', 'desc' => 'PC862: Hebrew'),
136
        'CP864' => array('conv' => '864', 'table' => '37', 'desc' => 'PC864: Arabic'),
137
        'CP869' => array('conv' => '869', 'table' => '38', 'desc' => 'PC869: Greek'),
138
        'ISO8859-2' => array('conv' => 'ISO8859-2', 'table' => '39', 'desc' => 'ISO8859-2: Latin2'),
139
        'ISO8859-15' => array('conv' => 'ISO8859-15', 'table' => '40', 'desc' => 'ISO8859-15: Latin9'),
140
        'WINDOWS-1250' => array('conv' => 'WINDOWS-1250', 'table' => '45', 'desc' => 'WPC1250: Latin2'),
141
        'WINDOWS-1251' => array('conv' => 'WINDOWS-1251', 'table' => '46', 'desc' => 'WPC1251: Cyrillic'),
142
        'WINDOWS-1252' => array('conv' => 'WINDOWS-1252', 'table' => '47', 'desc' => 'WPC1253: Greek'),
143
        'WINDOWS-1254' => array('conv' => 'WINDOWS-1254', 'table' => '48', 'desc' => 'WPC1254: Turkish'),
144
        'WINDOWS-1255' => array('conv' => 'WINDOWS-1255', 'table' => '49', 'desc' => 'WPC1255: Hebrew'),
145
        'WINDOWS-1256' => array('conv' => 'WINDOWS-1256', 'table' => '50', 'desc' => 'WPC1256: Arabic'),
146
        'WINDOWS-1257' => array('conv' => 'WINDOWS-1257', 'table' => '51', 'desc' => 'WPC1257: Baltic Rim'),
147
        'WINDOWS-1258' => array('conv' => 'WINDOWS-1258', 'table' => '52', 'desc' => 'WPC1258: Vietnamese'),
148
    );
149
    
150
    /**
151
     * Seleted code page
152
     * Defined in printer class.
153
     *
154
     * @var string
155
     */
156
    protected $codepage = 'CP437';
157
    /**
158
     * Number of codpage in printer memory.
159
     *
160
     * @var int
161
     */
162
    protected $charsetTableNum = 0;
163
    /**
164
     * Selected Region character page
165
     * Defined in printer class.
166
     *
167
     * @var string
168
     */
169
    protected $region = 'LATIN';
170
    /**
171
     * List all avaiable fonts
172
     *
173
     * @var array
174
     */
175
    protected $aFont = array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 97 => 'SA', 98 => 'SB');
176
    /**
177
     * Selected internal font.
178
     *
179
     * @var string
180
     */
181
    protected $font = 'A';
182
    /**
183
     * Resolution in dpi.
184
     *
185
     * @var int
186
     */
187
    public $dpi = 203; //dots per inch
188
    /**
189
     * Resolution in dpmm.
190
     *
191
     * @var int
192
     */
193
    public $dpmm = 8; //dots per mm
194
    /**
195
     * Maximum width paper.
196
     *
197
     * @var int
198
     */
199
    public $widthMaxmm = 80;//mm
200
    /**
201
     * Selected Width paper.
202
     *
203
     * @var int
204
     */
205
    public $widthPaper = 80;//mm
206
    /**
207
     * Maximum width for printed area.
208
     *
209
     * @var int
210
     */
211
    public $widthPrint = 72;//mm
212
    /**
213
     * Maximum width for printed area in dots.
214
     *
215
     * @var int
216
     */
217
    public $widthMaxdots = 576;//dots
218
    /**
219
     * Maximum number of characters per line.
220
     *
221
     * @var int
222
     */
223
    public $maxchars = 48;//max characters per line
224
225
    //protected property standards
226
    /**
227
     * Connector to printer.
228
     *
229
     * @var ConnectosInterface
230
     */
231
    protected $connector = null;
232
    /**
233
     * Seleted printer mode.
234
     *
235
     * @var string
236
     */
237
    protected $printerMode = 'normal';
238
    /**
239
     * Selected bold mode.
240
     *
241
     * @var bool
242
     */
243
    protected $boldMode = false;
244
    /**
245
     * Selected reverse colors mode.
246
     *
247
     * @var bool
248
     */
249
    protected $reverseColors = false;
250
    /**
251
     * Selected under lined mode.
252
     *
253
     * @var bool
254
     */
255
    protected $underlineMode = false;
256
    /**
257
     * Selected rotate 90 degrees mode
258
     *
259
     * @var bool
260
     */
261
    protected $rotateMode = false;
262
    /**
263
     * Buffer class.
264
     *
265
     * @var Connectors\Buffer
266
     */
267
    protected $buffer = null;
268
269
    /**
270
     * Class constructor
271
     * Instantiates the data buffer.
272
     *
273
     * @param ConnectorInterface $conn
274
     */
275 27
    public function __construct(ConnectorInterface $conn = null)
276
    {
277 27
        if (!is_null($conn)) {
278
            $this->connector = $conn;
0 ignored issues
show
Documentation Bug introduced by
It seems like $conn of type object<Posprint\Connectors\ConnectorInterface> is incompatible with the declared type object<Posprint\Printers\ConnectosInterface> of property $connector.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
279
        }
280 27
        $this->buffer = new Buffer();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Posprint\Connectors\Buffer() of type object<Posprint\Connectors\Buffer> is incompatible with the declared type object<Posprint\Printers\Connectors\Buffer> of property $buffer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
281 27
    }
282
283
    /**
284
     * Returns a default region for codepage
285
     * if param $region is null will return actual default region from class
286
     * if param $region is 'all' will return a array with all avaiable regions
287
     * if param $region is a string will set the region parameter of class and returns it.
288
     * NOTE: This command do not set the printer, only class parameters
289
     *
290
     * @param  string $region
291
     * @return string|array
292
     */
293 2
    public function defaultRegionPage($region = null)
294
    {
295 2
        if (!is_null($region)) {
296 2
            $region = strtoupper(trim($region));
297 2
            if ($region == 'ALL') {
298 1
                return $this->aRegion;
299
            }
300 2
            $reg = array_search($region, $this->aRegion, true);
301 2
            if ($reg !== false) {
302 2
                $this->region = $region;
303 2
            }
304 2
        }
305 2
        return $this->region;
306
    }
307
308
    /**
309
     * Returns a default codepage
310
     * if param $codepage is null will return actual default codepage from class
311
     * if param $codepage is 'all' will return a array with all avaiable codepages
312
     * if param $codepage is a string will set the codepage parameter of class and returns it.
313
     * NOTE: This command do not set the printer, only class parameters
314
     *
315
     * @param  string $codepage
316
     * @return string|array
317
     */
318 21
    public function defaultCodePage($codepage = null)
319
    {
320 21
        if (!is_null($codepage)) {
321 21
            $codepage = strtoupper(trim($codepage));
322 21
            if ($codepage == 'ALL') {
323 1
                return array_keys($this->aCodePage);
324
            }
325 21
            if (array_key_exists($codepage, $this->aCodePage)) {
326 3
                $this->codepage = $codepage;
327 3
                $table = $this->aCodePage[$codepage];
328 3
                $this->charsetTableNum = $table['table'];
329 3
            }
330 21
        }
331 21
        return $this->codepage;
332
    }
333
334
    /**
335
     * Set a codepage table in printer.
336
     *
337
     * @param string $codepage
338
     */
339 2
    public function setCodePage($codepage = null)
340
    {
341 2
        $codepage = $this->defaultCodePage($codepage);
0 ignored issues
show
Unused Code introduced by
$codepage is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
342 2
        $this->buffer->write(self::ESC.'t'.chr($this->charsetTableNum));
343 2
    }
344
345
    /**
346
     * Set a region page.
347
     * The numeric key of array $this->aRegion is the command parameter.
348
     *
349
     * @param string $region
350
     */
351 1
    public function setRegionPage($region = null)
352
    {
353 1
        $region = $this->defaultRegionPage($region);
354 1
        $mode = array_keys($this->aRegion, $region, true);
355 1
        $this->buffer->write(self::ESC.'R'.chr($mode[0]));
356 1
    }
357
    
358
    /**
359
     * Returns the default printer font
360
     * A - Font A (12 x 24)
361
     * B - Font B (9 x 17)
362
     * C - Font C
363
     * D - Font D
364
     * E - Font E
365
     * Special A
366
     * Special B
367
     * Default Font A.
368
     * if param $font is null will return actual default font from class
369
     * if param $font is 'all' will return a array with all avaiable printer fonts
370
     * if param $font is a string will set the font parameter of class and returns it.
371
     * NOTE: This command do not set the printer, only class parameters
372
     *
373
     * @param  string $font
374
     * @return array|string
375
     */
376 3
    public function defaultFont($font = null)
377
    {
378 3
        if (!is_null($font)) {
379 3
            $font = strtoupper(trim($font));
380 3
            if ($font == 'ALL') {
381
                //return array
382 1
                return $this->aFont;
383
            }
384
            //set $this->font
385 2
            $fonts = array_flip($this->aFont);
386 2
            $keys = array_keys($fonts);
387 2
            $reg = array_search($font, $keys, true);
388 2
            if ($reg !== false) {
389 2
                $this->font = $font;
390 2
            }
391 2
        }
392 2
        return $this->font;
393
    }
394
    
395
    /**
396
     * Set a printer font
397
     * If send a valid font name will set the printer otherelse a default font is selected
398
     *
399
     * @param string $font
400
     */
401 1
    public function setFont($font = null)
402
    {
403 1
        $font = $this->defaultFont($font);
404 1
        $mode = array_keys($this->aFont, $font, true);
405 1
        $this->buffer->write(self::ESC.'M'.chr($mode[0]));
406 1
    }
407
408
    /**
409
     * Set emphasys mode on or off.
410
     */
411 1
    public function setBold()
412
    {
413 1
        if ($this->boldMode) {
414 1
            $this->boldMode = false;
415 1
            $mode = 0;
416 1
        } else {
417 1
            $this->boldMode = true;
418 1
            $mode = 1;
419
        }
420 1
        $this->buffer->write(self::ESC . 'E' . chr($mode));
421 1
    }
422
423
    /**
424
     * Set underline mode on or off.
425
     */
426 1
    public function setUnderlined()
427
    {
428 1
        if ($this->underlineMode) {
429 1
            $this->underlineMode = false;
430 1
            $mode = 0;
431 1
        } else {
432 1
            $this->underlineMode = true;
433 1
            $mode = 1;
434
        }
435 1
        $this->buffer->write(self::ESC . '-' . chr($mode));
436 1
    }
437
    
438
    /**
439
     * Set italic mode on or off
440
     *
441
     * @return bool
442
     */
443
    public function setItalic()
444
    {
445
        return true;
446
    }
447
    
448
    /**
449
     * Aligns all data in one line to the selected layout in standard mode.
450
     * L - left  C - center  R - rigth
451
     *
452
     * @param string $align
453
     */
454 1
    public function setAlign($align = null)
455
    {
456 1
        if (is_null($align)) {
457
            $align = 'L';
458
        }
459 1
        $value = strtoupper($align);
460
        switch ($value) {
461 1
            case 'C':
462 1
                $mode = 1;
463 1
                break;
464 1
            case 'R':
465
                $mode = 2;
466
                break;
467 1
            default:
468 1
                $mode = 0;
469 1
        }
470 1
        $this->buffer->write(self::ESC . 'a' . chr($mode));
471 1
    }
472
    
473
    /**
474
     * Turns white/black reverse print On or Off for characters.
475
     * n = odd: On, n = even: Off.
476
     */
477 1
    public function setReverseColors()
478
    {
479 1
        if ($this->reverseColors) {
480 1
            $this->reverseColors = false;
481 1
            $mode = 0;
482 1
        } else {
483 1
            $this->reverseColors = true;
484 1
            $mode = 1;
485
        }
486 1
        $this->buffer->write(self::GS.'B'.chr($mode));
487 1
    }
488
    
489
    /**
490
     * Set expanded mode.
491
     *
492
     * @param int $size multiplies normal size 1 - 8
493
     */
494 1
    public function setExpanded($size = null)
495
    {
496 1
        $size = self::validateInteger($size, 1, 8, 1);
497
        $aSize = [
498 1
            [0, 0],
499 1
            [16, 1],
500 1
            [32, 2],
501 1
            [48, 3],
502 1
            [64, 4],
503 1
            [80, 5],
504 1
            [96, 6],
505 1
            [112, 7]
506 1
        ];
507 1
        $mode = $aSize[$size-1][0] + $aSize[$size-1][1];
508 1
        $this->buffer->write(self::ESC.'!'.chr($mode));
509 1
    }
510
511
    /**
512
     * Set condensed mode.
513
     */
514
    public function setCondensed()
515
    {
516
        $this->setExpanded(1);
517
        $this->setFont('B');
518
    }
519
    
520
521
    /**
522
     * Set the printer mode.
523
     */
524
    abstract public function setPrintMode($mode = null);
525
526
    /**
527
     * Set rotate 90 degrees.
528
     */
529 1
    public function setRotate90()
530
    {
531 1
        if ($this->rotateMode) {
532 1
            $this->rotateMode = false;
533 1
            $mode = 0;
534 1
        } else {
535 1
            $this->rotateMode = true;
536 1
            $mode = 1;
537
        }
538 1
        $this->buffer->write(self::ESC.'V'.chr($mode));
539 1
    }
540
    
541
    /**
542
     * initialize printer
543
     * Clears the data in the print buffer and resets the printer modes to
544
     * the modes that were in effect when the power was turned on.
545
     */
546 21
    public function initialize()
547
    {
548 21
        $this->buffer->write(self::ESC.'@');
549 21
        $this->rotateMode = false;
550 21
        $this->defaultCodePage('CP470');
551 21
        $this->underlineMode = false;
552 21
        $this->boldMode = false;
553 21
        $this->printerMode = 'normal';
554 21
        $this->font = 'A';
555 21
    }
556
    
557
    /**
558
     * Send message or command to buffer
559
     * when sending commands is not required to convert characters,
560
     * so the variable may translate by false.
561
     *
562
     * @param string $text
563
     */
564 1
    public function text($text = '')
565
    {
566 1
        $text = $this->translate($text);
567 1
        $this->buffer->write($text);
568 1
    }
569
570
    /**
571
     * Set horizontal and vertical motion units
572
     * $horizontal => character spacing 1/x"
573
     * $vertical => line spacing 1/y".
574
     *
575
     * @param int $horizontal
576
     * @param int $vertical
577
     */
578 1
    public function setSpacing($horizontal = 30, $vertical = 30)
579
    {
580 1
        $horizontal = self::validateInteger($horizontal, 0, 255, 30);
581 1
        $vertical = self::validateInteger($vertical, 0, 255, 30);
582 1
        $this->buffer->write(self::GS.'P'.chr($horizontal).chr($vertical));
583 1
    }
584
585
    /**
586
     * Set right-side character spacing
587
     * 0 ≤ n ≤ 255 => 1/x".
588
     *
589
     * @param int $value
590
     */
591 1
    public function setCharSpacing($value = 3)
592
    {
593 1
        $value = self::validateInteger($value, 0, 255, 0);
594 1
        $this->buffer->write(self::ESC.' '.chr($value));
595 1
    }
596
597
    /**
598
     * Line spacing
599
     * The default is set to zero and 30/180 "
600
     * any different number of zero will generate multiples of.
601
     * n  1/180-inch vertical motion
602
     * normal paragraph 30/180" => 4.23 mm
603
     *
604
     * @param int $paragraph
0 ignored issues
show
Bug introduced by
There is no parameter named $paragraph. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
605
     */
606 1
    public function setParagraph($value = 0)
607
    {
608 1
        $value = self::validateInteger($value, 0, 255, 0);
609 1
        $paragraph = ceil($value);
610 1
        if ($paragraph == 0) {
611 1
            $this->buffer->write(self::ESC.'2');
612 1
            return;
613
        }
614 1
        if ($paragraph < 25) {
615
            $paragraph = 25;
616 1
        } elseif ($paragraph > 255) {
617
            $paragraph = 255;
618
        }
619 1
        $this->buffer->write(self::ESC.'3'.chr($paragraph));
620 1
    }
621
622
    /**
623
     * Prints data and feeds paper n lines
624
     * ESC d n Prints data and feeds paper n lines.
625
     *
626
     * @param type $lines
627
     */
628 1
    public function lineFeed($lines = 1)
629
    {
630 1
        $lines = self::validateInteger($lines, 0, 255, 1);
631 1
        if ($lines == 1) {
632 1
            $this->buffer->write(self::LF);
633 1
            return;
634
        }
635 1
        $this->buffer->write(self::ESC.'d'.chr($lines));
636 1
    }
637
638
    /**
639
     * Prints data and feeds paper n dots
640
     * ESC J n Prints data and feeds paper n dots.
641
     *
642
     * @param int $dots
643
     */
644 1
    public function dotFeed($dots = 1)
645
    {
646 1
        $dots = self::validateInteger($dots, 0, 80, 0);
647 1
        $this->buffer->write(self::ESC.'J'.chr($dots));
648 1
    }
649
650
    /**
651
     * Generate a pulse, for opening a cash drawer if one is connected.
652
     * The default settings should open an Epson drawer.
653
     *
654
     * @param int $pin    0 or 1, for pin 2 or pin 5 kick-out connector respectively.
655
     * @param int $on_ms  pulse ON time, in milliseconds.
656
     * @param int $off_ms pulse OFF time, in milliseconds.
657
     */
658 1
    public function pulse($pin = 0, $on_ms = 120, $off_ms = 240)
659
    {
660 1
        $pin = self::validateInteger($pin, 0, 1, 0);
661 1
        $on_ms = self::validateInteger($on_ms, 1, 511, 120);
662 1
        $off_ms = self::validateInteger($off_ms, 1, 511, 240);
663 1
        $this->buffer->write(self::ESC.'p'.chr($pin + 48).chr($on_ms / 2).chr($off_ms / 2));
664 1
    }
665
666
    /**
667
     * Cut the paper.
668
     *
669
     * @param int $mode  FULL or PARTIAL. If not specified, FULL will be used.
670
     * @param int $lines Number of lines to feed after cut
671
     */
672 1
    public function cut($mode = 'PARTIAL', $lines = 3)
673
    {
674 1
        $lines = self::validateInteger($lines, 1, 10, 3);
675 1
        if ($mode == 'FULL') {
676 1
            $mode = self::CUT_FULL;
677 1
        } else {
678 1
            $mode = self::CUT_PARTIAL;
679
        }
680 1
        $this->buffer->write(self::GS.'V'.chr($mode).chr($lines));
681 1
    }
682
683
    /**
684
     * Implements barcodes 1D
685
     * GS k m n d1...dn
686
     * Prints bar code. n specifies the data length.
687
     *   m    bar code system             number of d (=k)
688
     *  "A"     UPC-A                       11 or 12
689
     *  "B"     UPC-E                       6, 7, 8, 11 or 12
690
     *  "C"     JAN13 / EAN13               12 or 13
691
     *  "D"     JAN8 / EAN8                 7 or 8
692
     *  "E"     CODE39                      1 or more
693
     *  "F"     ITF                         even
694
     *  "G"     CODABAR (NW-7)              2 or more
695
     *  "H"     CODE93                      1–255
696
     *  "I"     CODE128                     2–255
697
     *  "J"     GS1-128                     2–255
698
     *  "K"     GS1 DataBar Omnidirectional 13
699
     *  "L"     GS1 DataBar Truncated       13
700
     *  "M"     GS1 DataBar Limited         13
701
     *  "N"     GS1 DataBar Expanded        2–255.
702
     *
703
     *  GS h n Sets bar code height to n dots.
704
     *  GS w n Sets bar width of bar code. n = 2–6 (thin–thick)
705
     *  GS H n Selects print position of HRI characters.
706
     *           n = 0, "0": Not printed
707
     *           n = 1, "1": Above the bar code
708
     *           n = 2, "2": Below the bar code
709
     *           n = 3, "3": Both above and below the bar code
710
     *  GS f n Selects font for the HRI characters.
711
     *           n = 0, "0": Font A,
712
     *           n = 1, "1": Font B
713
     *
714
     * @param int    $type        Default CODE128
715
     * @param int    $height
716
     * @param int    $lineWidth
717
     * @param string $txtPosition
718
     * @param string $txtFont
719
     * @param string $data
720
     */
721 1
    public function barcode(
722
        $type = self::CODE128,
723
        $height = 162,
724
        $lineWidth = 2,
725
        $txtPosition = 'none',
726
        $txtFont = '',
727
        $data = '123456'
728
    ) {
729
        switch ($txtPosition) {
730 1
            case 'Above':
731
                $tPos = 1;
732
                break;
733 1
            case 'Below':
734
                $tPos = 2;
735
                break;
736 1
            case 'Both':
737
                $tPos = 3;
738
                break;
739 1
            default:
740
                //none
741 1
                $tPos = 0;
742 1
        }
743 1
        $font = 0;
744 1
        if ($txtFont === 'B') {
745
            $font = 1;
746
        }
747 1
        $id = 0;
748 1
        if (self::validateBarcodeData($type, $id, $data) === false) {
749
            return false;
750
        }
751 1
        $height = self::validateInteger($height, 1, 255, 4);
752 1
        $lineWidth = self::validateInteger($lineWidth, 1, 6, 2);
753 1
        $nlen = strlen($data);
754
        //set barcode height
755 1
        $this->buffer->write(self::GS.'h'.chr($height));
756
        //set barcode bar width
757 1
        $this->buffer->write(self::GS.'w'.chr($lineWidth));
758
        //Selects print position of HRI characters.
759 1
        $this->buffer->write(self::GS.'H'.chr($tPos));
760
        //Selects font for the HRI characters.
761 1
        $this->buffer->write(self::GS.'f'.chr($font));
762
        //Print barcode
763 1
        $this->buffer->write(self::GS.'k'.chr($id).chr($nlen).$data);
764 1
    }
765
    
766
    /**
767
     * Imprime o QR Code
768
     *
769
     * @param string $data   Dados a serem inseridos no QRCode
770
     * @param string $level  Nivel de correção L,M,Q ou H
771
     * @param int    $modelo modelo de QRCode 1, 2 ou 0 Micro
772
     * @param int    $wmod   largura da barra 3 ~ 16
773
     */
774 1
    public function barcodeQRCode($data = '', $level = 'L', $modelo = 2, $wmod = 4)
775
    {
776
        //set model of QRCode
777 1
        $n1 = 50;
778 1
        if ($modelo == 1) {
779
            $n1 = 49;
780
        }
781
        //select QR model
782 1
        $this->buffer->write(self::GS."(k".chr(4).chr(0).chr(49).chr(65).chr($n1).chr(0));
783
        //set module bar width
784 1
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(67).chr($wmod));
785
        //set error correction level
786 1
        $level = strtoupper($level);
787
        switch ($level) {
788 1
            case 'L':
789
                $n = 48;
790
                break;
791 1
            case 'M':
792 1
                $n = 49;
793 1
                break;
794
            case 'Q':
795
                $n = 50;
796
                break;
797
            case 'H':
798
                $n = 51;
799
                break;
800
            default:
801
                $n = 49;
802
        }
803 1
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(69).chr($n));
804
        //set data for QR Code assuming print only alphanumeric data
805 1
        $len = strlen($data) + 3;
806 1
        $pH = ($len / 256);
807 1
        $pL = $len % 256;
808 1
        $this->buffer->write(self::GS."(k".chr($pL).chr($pH).chr(49).chr(80).chr(48).$data);
809
        //Print QR Code
810 1
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(81).chr(48));
811 1
    }
812
813
    /**
814
     * Close and clean buffer
815
     * All data will be lost.
816
     */
817
    public function close()
818
    {
819
        $this->buffer->close();
820
    }
821
822
    /**
823
     * Return all data buffer.
824
     *
825
     * @param string $type specifies the return format
826
     */
827 20
    public function getBuffer($type = '')
828
    {
829
        switch ($type) {
830 20
            case 'binA':
831
                //returns a binary array of buffer
832
                $resp = $this->buffer->getDataBinary(true);
833
                break;
834 20
            case 'binS':
835
                //returns a binary string of buffer
836 20
                $resp = $this->buffer->getDataBinary(false);
837 20
                break;
838
            case 'b64A':
839
                //returns a base64 encoded array of buffer
840
                $resp = $this->buffer->getDataBase64(true);
841
                break;
842
            case 'b64S':
843
                //returns a base64 encoded string of buffer
844
                $resp = $this->buffer->getDataBase64(false);
845
                break;
846
            case 'json':
847
                //returns a json encoded of array buffer
848
                $resp = $this->buffer->getDataJson();
849
                break;
850
            case 'readA':
851
                //returns a human readable format of array buffer
852
                //only for debug reasons
853
                $resp = $this->buffer->getDataReadable(true);
854
                break;
855
            default:
856
                //returns a human readable format of string buffer
857
                //only for debug reasons
858
                $resp = $this->buffer->getDataReadable(false);
859
        }
860 20
        return $resp;
861
    }
862
863
    /**
864
     * Send commands from buffer to connector printer.
865
     */
866
    public function send(ConnectorInterface $conn = null)
867
    {
868
        if (!is_null($conn)) {
869
            $this->connector = $conn;
0 ignored issues
show
Documentation Bug introduced by
It seems like $conn of type object<Posprint\Connectors\ConnectorInterface> is incompatible with the declared type object<Posprint\Printers\ConnectosInterface> of property $connector.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
870
        }
871
        if (is_null($this->connector)) {
872
            return $this->getBuffer();
873
        }
874
        $aCmds = $this->getBuffer('binA');
875
        foreach ($aCmds as $cmd) {
876
            $this->connector->write($cmd);
877
        }
878
    }
879
880
    /**
881
     * Checks whether the barcode data is compatible with the chosen model
882
     *
883
     * @param  string $type
884
     * @param  int    $id
885
     * @param  string $data
886
     * @return string
887
     */
888 1
    protected static function validateBarcodeData($type, &$id, &$data)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
889
    {
890
        $aTypes = [
891 1
            'A' => ['id' => 65, 'desc' => 'UPC-A', 'len' => '11;12', 'type' => 'N'],
892 1
            'B' => ['id' => 66, 'desc' => 'UPC-E', 'len' => '6;7;8;11;12', 'type' => 'N'],
893 1
            'C' => ['id' => 67, 'desc' => 'EAN13', 'len' => '12;13', 'type' => 'N'],
894 1
            'D' => ['id' => 68, 'desc' => 'EAN8', 'len' => '7;8', 'type' => 'N'],
895 1
            'E' => ['id' => 69, 'desc' => 'CODE39', 'len' => '1-', 'type' => 'C'],
896 1
            'F' => ['id' => 70, 'desc' => 'ITF (i25)', 'len' => '1-even ', 'type' => 'N'],
897 1
            'G' => ['id' => 71, 'desc' => 'CODABAR', 'len' => '2-more', 'type' => 'C'],
898 1
            'H' => ['id' => 72, 'desc' => 'CODE93', 'len' => '1-255', 'type' => 'C'],
899 1
            'I' => ['id' => 73, 'desc' => 'CODE128', 'len' => '2-255', 'type' => 'C'],
900 1
            'J' => ['id' => 74, 'desc' => 'GS1-128', 'len' => '2-255', 'type' => 'C'],
901 1
            'K' => ['id' => 75, 'desc' => 'GS1 DataBar Omnidirectional', 'len' => '13', 'type' => 'N'],
902 1
            'L' => ['id' => 76, 'desc' => 'GS1 DataBar Truncated', 'len' => '13', 'type' => 'N'],
903 1
            'M' => ['id' => 77, 'desc' => 'GS1 DataBar Limited', 'len' => '13', 'type' => 'N'],
904 1
            'N' => ['id' => 78, 'desc' => 'GS1 DataBar Expanded', 'len' => '2-255', 'type' => 'C'],
905 1
        ];
906 1
        if (!array_key_exists($type, $aTypes)) {
907
            return false;
908
        }
909 1
        $bar = $aTypes[$type];
910 1
        $id = $bar['id'];
911 1
        $len = $bar['len'];
0 ignored issues
show
Unused Code introduced by
$len is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
912 1
        $dtype = $bar['type'];
0 ignored issues
show
Unused Code introduced by
$dtype is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
913
        //check data type if N only numeric is acceptable and all others chars must be removed
914
        //and if then field stay is empty, this is must be completed to an acceptable standard value
915
        
916
        //check for length of data, if the field length is different from the
917
        //acceptable values, it must be adjusted by removing or adding characters
918 1
        return true;
919
    }
920
921
    /**
922
     * Insert a image.
923
     *
924
     * @param  string $filename Path to image file
925
     * @param  float  $width
926
     * @param  float  $height
927
     * @param  int    $size     0-normal 1-Double Width 2-Double Heigth
928
     * @throws RuntimeException
929
     */
930 1
    public function putImage($filename = '', $width = null, $height = null, $size = 0)
931
    {
932
        try {
933 1
            $img = new Graphics($filename, $width, $height);
934 1
        } catch (RuntimeException $e) {
935
            throw new RuntimeException($e->getMessage());
936
        } catch (InvalidArgumentException $e) {
937
            throw new RuntimeException($e->getMessage());
938
        }
939 1
        $size = self::validateInteger($size, 0, 3, 0);
940 1
        $imgHeader = self::dataHeader(array($img->getWidth(), $img->getHeight()), true);
941 1
        $tone = '0';
942 1
        $colors = '1';
943 1
        $xm = (($size & self::IMG_DOUBLE_WIDTH) == self::IMG_DOUBLE_WIDTH) ? chr(2) : chr(1);
944 1
        $ym = (($size & self::IMG_DOUBLE_HEIGHT) == self::IMG_DOUBLE_HEIGHT) ? chr(2) : chr(1);
945 1
        $header = $tone.$xm.$ym.$colors.$imgHeader;
946 1
        $this->sendGraphicsData('0', 'p', $header.$img->getRasterImage());
947 1
        $this->sendGraphicsData('0', '2');
948 1
    }
949
950
    /**
951
     * Wrapper for GS ( L, to calculate and send correct data length.
952
     *
953
     * @param string $m    Modifier/variant for function. Usually '0'.
954
     * @param string $fn   Function number to use, as character.
955
     * @param string $data Data to send.
956
     */
957 1
    protected function sendGraphicsData($m, $fn, $data = '')
958
    {
959 1
        $header = $this->intLowHigh(strlen($data) + 2, 2);
960 1
        $this->buffer->write(self::GS.'(L'.$header.$m.$fn.$data);
961 1
    }
962
963
    /**
964
     * Generate two characters for a number:
965
     * In lower and higher parts, or more parts as needed.
966
     *
967
     * @param int $int    Input number
0 ignored issues
show
Bug introduced by
There is no parameter named $int. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
968
     * @param int $length The number of bytes to output (1 - 4).
969
     */
970 1
    protected static function intLowHigh($input, $length)
971
    {
972 1
        $maxInput = (256 << ($length * 8) - 1);
0 ignored issues
show
Unused Code introduced by
$maxInput is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
973 1
        $outp = '';
974 1
        for ($i = 0; $i < $length; ++$i) {
975 1
            $outp .= chr($input % 256);
976 1
            $input = (int) ($input / 256);
977 1
        }
978 1
        return $outp;
979
    }
980
981
    /**
982
     * Convert widths and heights to characters.
983
     * Used before sending graphics to set the size.
984
     *
985
     * @param  array $inputs
986
     * @param  bool  $long   True to use 4 bytes, false to use 2
987
     * @return string
988
     */
989 1
    protected static function dataHeader(array $inputs, $long = true)
990
    {
991 1
        $outp = array();
992 1
        foreach ($inputs as $input) {
993 1
            if ($long) {
994 1
                $outp[] = self::intLowHigh($input, 2);
995 1
            } else {
996
                $input = self::validateInteger($input, 0, 255, 0);
997
                $outp[] = chr($input);
998
            }
999 1
        }
1000 1
        return implode('', $outp);
1001
    }
1002
1003
    /**
1004
     * Verify if the argument given is not a boolean.
1005
     *
1006
     * @param  bool $test    the input to test
1007
     * @param  bool $default the default value
1008
     * @return bool
1009
     */
1010
    protected static function validateBoolean($test, $default)
1011
    {
1012
        if (!($test === true || $test === false)) {
1013
            return $default;
1014
        }
1015
        return $test;
1016
    }
1017
1018
    /**
1019
     * Verify if the argument given is not an integer within the specified range.
1020
     * will return default instead
1021
     *
1022
     * @param  int $test    the input to test
1023
     * @param  int $min     the minimum allowable value (inclusive)
1024
     * @param  int $max     the maximum allowable value (inclusive)
1025
     * @param  int $default the default value
1026
     * @return int
1027
     */
1028 10
    protected static function validateInteger($test, $min, $max, $default)
1029
    {
1030 10
        if (!is_integer($test) || $test < $min || $test > $max) {
1031 1
            return $default;
1032
        }
1033 10
        return $test;
1034
    }
1035
1036
    /**
1037
     * Verify if the argument given can't be cast to a string.
1038
     *
1039
     * @param  string $test    the input to test
1040
     * @param  string $default the default value
1041
     * @return string
1042
     */
1043
    protected static function validateString($test, $default)
1044
    {
1045
        if (is_object($test) && !method_exists($test, '__toString')) {
1046
            return $default;
1047
        }
1048
        return $test;
1049
    }
1050
    
1051
    /**
1052
     * Translate the text from UTF-8 for the specified codepage
1053
     * this translation uses "iconv" and admits texts ONLY in UTF-8.
1054
     *
1055
     * @param  string $text
1056
     * @return string
1057
     */
1058 1
    protected function translate($text = '')
1059
    {
1060 1
        $indCode = $this->defaultCodePage();
1061 1
        if (!empty($indCode)) {
1062 1
            $codep = $this->aCodePage[$indCode];
1063 1
            if (!empty($codep)) {
1064 1
                $text = iconv('UTF-8', $codep['conv'], $text);
1065 1
            }
1066 1
        }
1067 1
        return $text;
1068
    }
1069
}
1070