Completed
Push — master ( 43dc73...0c99ca )
by Roberto
08:10 queued 05:22
created

DefaultPrinter   D

Complexity

Total Complexity 100

Size/Duplication

Total Lines 1057
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 77.6%

Importance

Changes 12
Bugs 0 Features 0
Metric Value
wmc 100
c 12
b 0
f 0
lcom 1
cbo 3
dl 0
loc 1057
rs 4.4242
ccs 284
cts 366
cp 0.776

39 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 2
A defaultModel() 0 13 4
A defaultRegionPage() 0 14 4
A defaultCodePage() 0 15 4
A defaultFont() 0 18 4
A initialize() 0 17 1
setPrintMode() 0 1 ?
A setCodePage() 0 5 1
A setRegionPage() 0 6 1
A setFont() 0 6 1
A setBold() 0 9 2
A setUnderlined() 0 9 2
A setItalic() 0 4 1
A setAlign() 0 18 4
A setReverseColors() 0 9 2
A setExpanded() 0 16 1
A setCondensed() 0 5 1
A setRotate90() 0 9 2
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
C barcode() 0 50 8
B barcodeQRCode() 0 38 6
C getBuffer() 0 35 7
A send() 0 13 4
B putImage() 0 19 5
A close() 0 4 1
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 Posprint\Printers\Barcodes\Barcode1DAnalysis;
31
use RuntimeException;
32
use InvalidArgumentException;
33
34
abstract class DefaultPrinter implements PrinterInterface
35
{
36
    //set standards
37
    const NUL = "\x0"; //Nulo
38
    const EOT = "\x4"; //EOT fim da transmissão
39
    const ENQ = "\x5"; //ENQ colocar na fila Pedido de status 1
40
    const HT = "\x9"; //tabulação horizontal
41
    const VT = "\xb"; //tabulação vertical
42
    const LF = "\x0a"; //Inicia a impressão e avança uma linha
43
    const FF = "\x0c"; //avança pagina
44
    const CR = "\x0d"; //retorno de carro
45
    const DLE = "\x10"; //Data Link Escape
46
    const CAN = "\x18"; //CAN Cancela linha enviada
47
    const BEL = "\x07"; //BEL sinal sonoro
48
    const ESC = "\x1b"; //escape
49
    const FS = "\x1c"; //FS
50
    const GS = "\x1d"; //GS
51
    const SO = "\x0e"; //SO Inicia modo expandido
52
    const DC1 = "\x11"; //DC1 Inicia modo enfatizado
53
    const DC2 = "\x12"; //DC2 Cancela modo condensado
54
    const DC3 = "\x13"; //DC3 Cancela modo enfatizado
55
    const DC4 = "\x14"; //DC4 Controle de dispositivo 4 Inicia modo normal
56
    const SI = "\x0f"; //Seleciona modo condensado
57
    const EM = "\x19"; //Avança 4 linhas
58
    const DEL = "\x7f"; //Cancela último caracter
59
    const SYN = "\x16"; //Sincronismo
60
    const NOTRANS = false; //not translate characters codepage
61
    const TRANS = true; //perform a character convertion to codepage
62
63
    //Cut types
64
    const CUT_FULL = 65;
65
    const CUT_PARTIAL = 66;
66
    
67
    //Image sizing options
68
    const IMG_DEFAULT = 0;
69
    const IMG_DOUBLE_WIDTH = 1;
70
    const IMG_DOUBLE_HEIGHT = 2;
71
72
    /**
73
     * List all available region pages.
74
     *
75
     * @var array
76
     */
77
    protected $aRegion = array(
78
        'USA',
79
        'FRANCE',
80
        'GERMANY',
81
        'UK',
82
        'DENMARK',
83
        'SWEDEN',
84
        'ITALY',
85
        'SPAIN',
86
        'JAPAN',
87
        'NORWAY',
88
        'DENMARK2',
89
        'SPAIN2',
90
        'LATIN',
91
        'KOREA',
92
        'SLOVENIA',
93
        'CHINA',
94
        'VIETNAM',
95
        'ARABIA'
96
    );
97
98
    /**
99
     * List all available code pages.
100
     *
101
     * @var array
102
     */
103
    protected $aCodePage = array(
104
        'CP437' => array('conv' => '437', 'table' => '0', 'desc' => 'PC437: USA, Standard Europe'),
105
        'CP850' => array('conv' => '850', 'table' => '2', 'desc' => 'PC850: Multilingual'),
106
        'CP860' => array('conv' => '860', 'table' => '3', 'desc' => 'PC860: Portuguese'),
107
        'CP863' => array('conv' => '863', 'table' => '4', 'desc' => 'PC863: Canadian-French'),
108
        'CP865' => array('conv' => '865', 'table' => '5', 'desc' => 'PC865: Nordic'),
109
        'CP851' => array('conv' => '851', 'table' => '11', 'desc' => 'PC851: Greek'),
110
        'CP853' => array('conv' => '853', 'table' => '12', 'desc' => 'PC853: Turkish'),
111
        'CP857' => array('conv' => '857', 'table' => '13', 'desc' => 'PC857: Turkish'),
112
        'CP737' => array('conv' => '737', 'table' => '14', 'desc' => 'PC737: Greek'),
113
        'ISO8859-7' => array('conv' => 'ISO8859-7', 'table' => '15', 'desc' => 'ISO8859-7: Greek'),
114
        'CP866' => array('conv' => '866', 'table' => '17', 'desc' => 'PC866: Cyrillic #2'),
115
        'CP852' => array('conv' => '852', 'table' => '18', 'desc' => 'PC852: Latin2'),
116
        'CP858' => array('conv' => '858', 'table' => '19', 'desc' => 'PC858: Euro'),
117
        'CP720' => array('conv' => '720', 'table' => '32', 'desc' => 'PC720: Arabic'),
118
        'CP855' => array('conv' => '855', 'table' => '34', 'desc' => 'PC855: Cyrillic'),
119
        'CP861' => array('conv' => '861', 'table' => '35', 'desc' => 'PC861: Icelandic'),
120
        'CP862' => array('conv' => '862', 'table' => '36', 'desc' => 'PC862: Hebrew'),
121
        'CP864' => array('conv' => '864', 'table' => '37', 'desc' => 'PC864: Arabic'),
122
        'CP869' => array('conv' => '869', 'table' => '38', 'desc' => 'PC869: Greek'),
123
        'ISO8859-2' => array('conv' => 'ISO8859-2', 'table' => '39', 'desc' => 'ISO8859-2: Latin2'),
124
        'ISO8859-15' => array('conv' => 'ISO8859-15', 'table' => '40', 'desc' => 'ISO8859-15: Latin9'),
125
        'WINDOWS-1250' => array('conv' => 'WINDOWS-1250', 'table' => '45', 'desc' => 'WPC1250: Latin2'),
126
        'WINDOWS-1251' => array('conv' => 'WINDOWS-1251', 'table' => '46', 'desc' => 'WPC1251: Cyrillic'),
127
        'WINDOWS-1252' => array('conv' => 'WINDOWS-1252', 'table' => '47', 'desc' => 'WPC1253: Greek'),
128
        'WINDOWS-1254' => array('conv' => 'WINDOWS-1254', 'table' => '48', 'desc' => 'WPC1254: Turkish'),
129
        'WINDOWS-1255' => array('conv' => 'WINDOWS-1255', 'table' => '49', 'desc' => 'WPC1255: Hebrew'),
130
        'WINDOWS-1256' => array('conv' => 'WINDOWS-1256', 'table' => '50', 'desc' => 'WPC1256: Arabic'),
131
        'WINDOWS-1257' => array('conv' => 'WINDOWS-1257', 'table' => '51', 'desc' => 'WPC1257: Baltic Rim'),
132
        'WINDOWS-1258' => array('conv' => 'WINDOWS-1258', 'table' => '52', 'desc' => 'WPC1258: Vietnamese'),
133
    );
134
    
135
    /**
136
     * Seleted code page
137
     * Defined in printer class.
138
     *
139
     * @var string
140
     */
141
    protected $codepage = 'CP437';
142
    /**
143
     * Number of codpage in printer memory.
144
     *
145
     * @var int
146
     */
147
    protected $charsetTableNum = 0;
148
    /**
149
     * Selected Region character page
150
     * Defined in printer class.
151
     *
152
     * @var string
153
     */
154
    protected $region = 'LATIN';
155
    /**
156
     * List all avaiable fonts
157
     *
158
     * @var array
159
     */
160
    protected $aFont = array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 97 => 'SA', 98 => 'SB');
161
    /**
162
     * Selected internal font.
163
     *
164
     * @var string
165
     */
166
    protected $font = 'A';
167
    /**
168
     * Resolution in dpi.
169
     *
170
     * @var int
171
     */
172
    public $dpi = 203; //dots per inch
173
    /**
174
     * Resolution in dpmm.
175
     *
176
     * @var int
177
     */
178
    public $dpmm = 8; //dots per mm
179
    /**
180
     * Maximum width paper.
181
     *
182
     * @var int
183
     */
184
    public $widthMaxmm = 80;//mm
185
    /**
186
     * Selected Width paper.
187
     *
188
     * @var int
189
     */
190
    public $widthPaper = 80;//mm
191
    /**
192
     * Maximum width for printed area.
193
     *
194
     * @var int
195
     */
196
    public $widthPrint = 72;//mm
197
    /**
198
     * Maximum width for printed area in dots.
199
     *
200
     * @var int
201
     */
202
    public $widthMaxdots = 576;//dots
203
    /**
204
     * Maximum number of characters per line.
205
     *
206
     * @var int
207
     */
208
    public $maxchars = 48;//max characters per line
209
210
    //protected property standards
211
    /**
212
     * Connector to printer.
213
     *
214
     * @var ConnectosInterface
215
     */
216
    protected $connector = null;
217
    /**
218
     * Seleted printer mode.
219
     *
220
     * @var string
221
     */
222
    protected $printerMode = 'normal';
223
    /**
224
     * Selected bold mode.
225
     *
226
     * @var bool
227
     */
228
    protected $boldMode = false;
229
    /**
230
     * Selected italic mode.
231
     *
232
     * @var bool
233
     */
234
    protected $italicMode = false;
235
    /**
236
     * Selected condenced mode.
237
     *
238
     * @var bool
239
     */
240
    protected $condensedMode = false;
241
    /**
242
     * Selected expanded mode.
243
     * @var bool
244
     */
245
    protected $expandedMode = false;
246
    /**
247
     * Seleted double higth mode.
248
     * @var bool
249
     */
250
    protected $doubleHeigth = false;
251
    /**
252
     * Selected reverse colors mode.
253
     *
254
     * @var bool
255
     */
256
    protected $reverseColors = false;
257
    /**
258
     * Selected under lined mode.
259
     *
260
     * @var bool
261
     */
262
    protected $underlineMode = false;
263
    /**
264
     * Selected rotate 90 degrees mode
265
     *
266
     * @var bool
267
     */
268
    protected $rotateMode = false;
269
    /**
270
     * Buffer class.
271
     *
272
     * @var Connectors\Buffer
273
     */
274
    protected $buffer = null;
275 27
    /**
276
     * Acceptable barcodes list
277 27
     * @var array
278
     */
279
    protected $barcode1Dlist = [
280 27
        'UPC_A' => 65,
281 27
        'UPC_E' => 66,
282
        'EAN13' => 67,
283
        'EAN8' => 68,
284
        'CODE39' => 69,
285
        'I25' => 70,
286
        'CODABAR' => 71,
287
        'CODE93' => 72,
288
        'CODE128' => 73,
289
        'GS1128' => 74,
290
        'GS1DATABAROMINI' => 75,
291
        'GS1DATABARTRUNC' => 76,
292
        'GS1DATABARLIMIT' => 77,
293 2
        'GS1DATABAREXPAN' => 78
294
    ];
295 2
    /**
296 2
     * List of supported models
297 2
     * @var array
298 1
     */
299
    protected $modelList = [
300 2
        'T20'
301 2
    ];
302 2
    /**
303 2
     * Selected model
304 2
     * @var string
305 2
     */
306
    protected $printerModel = 'T20';
307
308
    /**
309
     * Class constructor
310
     * Instantiates the data buffer.
311
     *
312
     * @param ConnectorInterface $conn
313
     */
314
    public function __construct(ConnectorInterface $conn = null)
315
    {
316
        if (!is_null($conn)) {
317
            $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...
318 21
        }
319
        $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...
320 21
    }
321 21
    
322 21
    /**
323 1
     * Return default printer model
324
     * @param string $model
325 21
     * @return string|array
326 3
     */
327 3
    public function defaultModel($model = 'T20')
328 3
    {
329 3
        if (!is_null($model)) {
330 21
            $model = strtoupper(trim($model));
331 21
            if ($model == 'ALL') {
332
                return $this->modelList;
333
            }
334
        }
335
        if (array_key_exists($model, $this->modelList)) {
336
            $this->printerModel = $model;
337
        }
338
        return $model;
339 2
    }
340
    
341 2
    /**
342 2
     * Returns a default region for codepage
343 2
     * if param $region is null will return actual default region from class
344
     * if param $region is 'all' will return a array with all avaiable regions
345
     * if param $region is a string will set the region parameter of class and returns it.
346
     * NOTE: This command do not set the printer, only class parameters
347
     *
348
     * @param  string $region
349
     * @return string|array
350
     */
351 1
    public function defaultRegionPage($region = null)
352
    {
353 1
        if (!is_null($region)) {
354 1
            $region = strtoupper(trim($region));
355 1
            if ($region == 'ALL') {
356 1
                return $this->aRegion;
357
            }
358
            $reg = array_search($region, $this->aRegion, true);
359
            if ($reg !== false) {
360
                $this->region = $region;
361
            }
362
        }
363
        return $this->region;
364
    }
365
366
    /**
367
     * Returns a default codepage
368
     * if param $codepage is null will return actual default codepage from class
369
     * if param $codepage is 'all' will return a array with all avaiable codepages
370
     * if param $codepage is a string will set the codepage parameter of class and returns it.
371
     * NOTE: This command do not set the printer, only class parameters
372
     *
373
     * @param  string $codepage
374
     * @return string|array
375
     */
376 3
    public function defaultCodePage($codepage = null)
377
    {
378 3
        if (!is_null($codepage)) {
379 3
            $codepage = strtoupper(trim($codepage));
380 3
            if ($codepage == 'ALL') {
381
                return array_keys($this->aCodePage);
382 1
            }
383
            if (array_key_exists($codepage, $this->aCodePage)) {
384
                $this->codepage = $codepage;
385 2
                $table = $this->aCodePage[$codepage];
386 2
                $this->charsetTableNum = $table['table'];
387 2
            }
388 2
        }
389 2
        return $this->codepage;
390 2
    }
391 2
392 2
    /**
393
     * Returns the default printer font
394
     * A - Font A (12 x 24)
395
     * B - Font B (9 x 17)
396
     * C - Font C
397
     * D - Font D
398
     * E - Font E
399
     * Special A
400
     * Special B
401 1
     * Default Font A.
402
     * if param $font is null will return actual default font from class
403 1
     * if param $font is 'all' will return a array with all avaiable printer fonts
404 1
     * if param $font is a string will set the font parameter of class and returns it.
405 1
     * NOTE: This command do not set the printer, only class parameters
406 1
     *
407
     * @param  string $font
408
     * @return array|string
409
     */
410
    public function defaultFont($font = null)
411 1
    {
412
        if (!is_null($font)) {
413 1
            $font = strtoupper(trim($font));
414 1
            if ($font == 'ALL') {
415 1
                //return array
416 1
                return $this->aFont;
417 1
            }
418 1
            //set $this->font
419
            $fonts = array_flip($this->aFont);
420 1
            $keys = array_keys($fonts);
421 1
            $reg = array_search($font, $keys, true);
422
            if ($reg !== false) {
423
                $this->font = $font;
424
            }
425
        }
426 1
        return $this->font;
427
    }
428 1
429 1
    /**
430 1
     * initialize printer
431 1
     * Clears the data in the print buffer and resets the printer modes to
432 1
     * the modes that were in effect when the power was turned on.
433 1
     */
434
    public function initialize()
435 1
    {
436 1
        $this->rotateMode = false;
437
        $this->boldMode = false;
438
        $this->italicMode = false;
439
        $this->underlineMode = false;
440
        $this->printerMode = 'normal';
441
        $this->defaultModel();
442
        $this->defaultCodePage();
443
        $this->defaultRegionPage();
444
        $this->defaultFont();
445
        $this->buffer->write(self::ESC.'@');
446
        $this->setPrintMode();
447
        $this->setFont();
448
        $this->setCodePage();
449
        $this->setRegionPage();
450
    }
451
452
    /**
453
     * Set the printer mode.
454 1
     */
455
    abstract public function setPrintMode($mode = null);
456 1
    
457
    /**
458
     * Set a codepage table in printer.
459 1
     *
460
     * @param string $codepage
461 1
     */
462 1
    public function setCodePage($codepage = null)
463 1
    {
464 1
        $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...
465
        $this->buffer->write(self::ESC.'t'.chr($this->charsetTableNum));
466
    }
467 1
468 1
    /**
469 1
     * Set a region page.
470 1
     * The numeric key of array $this->aRegion is the command parameter.
471 1
     *
472
     * @param string $region
473
     */
474
    public function setRegionPage($region = null)
475
    {
476
        $region = $this->defaultRegionPage($region);
477 1
        $mode = array_keys($this->aRegion, $region, true);
478
        $this->buffer->write(self::ESC.'R'.chr($mode[0]));
479 1
    }
480 1
    
481 1
    /**
482 1
     * Set a printer font
483 1
     * If send a valid font name will set the printer otherelse a default font is selected
484 1
     *
485
     * @param string $font
486 1
     */
487 1
    public function setFont($font = null)
488
    {
489
        $font = $this->defaultFont($font);
490
        $mode = array_keys($this->aFont, $font, true);
491
        $this->buffer->write(self::ESC.'M'.chr($mode[0]));
492
    }
493
494 1
    /**
495
     * Set emphasys mode on or off.
496 1
     */
497
    public function setBold()
498 1
    {
499 1
        $mode = 1;
500 1
        if ($this->boldMode) {
501 1
            $mode = 0;
502 1
        }
503 1
        $this->boldMode = ! $this->boldMode;
504 1
        $this->buffer->write(self::ESC . 'E' . chr($mode));
505 1
    }
506 1
507 1
    /**
508 1
     * Set underline mode on or off.
509 1
     */
510
    public function setUnderlined()
511
    {
512
        $mode = 1;
513
        if ($this->underlineMode) {
514
            $mode = 0;
515
        }
516
        $this->underlineMode = ! $this->underlineMode;
517
        $this->buffer->write(self::ESC . '-' . chr($mode));
518
    }
519
    
520
    /**
521
     * Set italic mode on or off
522
     *
523
     * @return bool
524
     */
525
    public function setItalic()
526
    {
527
        //dont exists in this printer
528
    }
529 1
    
530
    /**
531 1
     * Aligns all data in one line to the selected layout in standard mode.
532 1
     * L - left  C - center  R - rigth
533 1
     *
534 1
     * @param string $align
535 1
     */
536 1
    public function setAlign($align = null)
537
    {
538 1
        if (is_null($align)) {
539 1
            $align = 'L';
540
        }
541
        $value = strtoupper($align);
542
        switch ($value) {
543
            case 'C':
544
                $mode = 1;
545
                break;
546 21
            case 'R':
547
                $mode = 2;
548 21
                break;
549 21
            default:
550 21
                $mode = 0;
551 21
        }
552 21
        $this->buffer->write(self::ESC . 'a' . chr($mode));
553 21
    }
554 21
    
555 21
    /**
556
     * Turns white/black reverse print On or Off for characters.
557
     * n = odd: On, n = even: Off.
558
     */
559
    public function setReverseColors()
560
    {
561
        $mode = 0;
562
        $this->reverseColors = ! $this->reverseColors;
563
        if ($this->reverseColors) {
564 1
            $mode = 1;
565
        }
566 1
        $this->buffer->write(self::GS.'B'.chr($mode));
567 1
    }
568 1
    
569
    /**
570
     * Set expanded mode.
571
     *
572
     * @param int $size multiplies normal size 1 - 8
573
     */
574
    public function setExpanded($size = null)
575
    {
576
        $size = self::validateInteger($size, 1, 8, 1);
577
        $aSize = [
578 1
            [0, 0],
579
            [16, 1],
580 1
            [32, 2],
581 1
            [48, 3],
582 1
            [64, 4],
583 1
            [80, 5],
584
            [96, 6],
585
            [112, 7]
586
        ];
587
        $mode = $aSize[$size-1][0] + $aSize[$size-1][1];
588
        $this->buffer->write(self::ESC.'!'.chr($mode));
589
    }
590
591 1
    /**
592
     * Set condensed mode.
593 1
     */
594 1
    public function setCondensed()
595 1
    {
596
        $this->setExpanded(1);
597
        $this->setFont('B');
598
    }
599
    
600
    /**
601
     * Set rotate 90 degrees.
602
     */
603
    public function setRotate90()
604
    {
605
        $this->rotateMode = !$this->rotateMode;
606 1
        $mode = 0;
607
        if ($this->rotateMode) {
608 1
            $mode = 1;
609 1
        }
610 1
        $this->buffer->write(self::ESC.'V'.chr($mode));
611 1
    }
612 1
    
613
    /**
614 1
     * Send message or command to buffer
615
     * when sending commands is not required to convert characters,
616 1
     * so the variable may translate by false.
617
     *
618
     * @param string $text
619 1
     */
620 1
    public function text($text = '')
621
    {
622
        $text = $this->translate($text);
623
        $this->buffer->write($text);
624
    }
625
626
    /**
627
     * Set horizontal and vertical motion units
628 1
     * $horizontal => character spacing 1/x"
629
     * $vertical => line spacing 1/y".
630 1
     *
631 1
     * @param int $horizontal
632 1
     * @param int $vertical
633 1
     */
634
    public function setSpacing($horizontal = 30, $vertical = 30)
635 1
    {
636 1
        $horizontal = self::validateInteger($horizontal, 0, 255, 30);
637
        $vertical = self::validateInteger($vertical, 0, 255, 30);
638
        $this->buffer->write(self::GS.'P'.chr($horizontal).chr($vertical));
639
    }
640
641
    /**
642
     * Set right-side character spacing
643
     * 0 ≤ n ≤ 255 => 1/x".
644 1
     *
645
     * @param int $value
646 1
     */
647 1
    public function setCharSpacing($value = 3)
648 1
    {
649
        $value = self::validateInteger($value, 0, 255, 0);
650
        $this->buffer->write(self::ESC.' '.chr($value));
651
    }
652
653
    /**
654
     * Line spacing
655
     * The default is set to zero and 30/180 "
656
     * any different number of zero will generate multiples of.
657
     * n  1/180-inch vertical motion
658 1
     * normal paragraph 30/180" => 4.23 mm
659
     *
660 1
     * @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...
661 1
     */
662 1
    public function setParagraph($value = 0)
663 1
    {
664 1
        $value = self::validateInteger($value, 0, 255, 0);
665
        $paragraph = ceil($value);
666
        if ($paragraph == 0) {
667
            $this->buffer->write(self::ESC.'2');
668
            return;
669
        }
670
        if ($paragraph < 25) {
671
            $paragraph = 25;
672 1
        } elseif ($paragraph > 255) {
673
            $paragraph = 255;
674 1
        }
675 1
        $this->buffer->write(self::ESC.'3'.chr($paragraph));
676 1
    }
677 1
678 1
    /**
679
     * Prints data and feeds paper n lines
680 1
     * ESC d n Prints data and feeds paper n lines.
681 1
     *
682
     * @param integer $lines
683
     */
684
    public function lineFeed($lines = 1)
685
    {
686
        $lines = self::validateInteger($lines, 0, 255, 1);
687
        if ($lines == 1) {
688
            $this->buffer->write(self::LF);
689
            return;
690
        }
691
        $this->buffer->write(self::ESC.'d'.chr($lines));
692
    }
693
694
    /**
695
     * Prints data and feeds paper n dots
696
     * ESC J n Prints data and feeds paper n dots.
697
     *
698
     * @param int $dots
699
     */
700
    public function dotFeed($dots = 1)
701
    {
702
        $dots = self::validateInteger($dots, 0, 80, 0);
703
        $this->buffer->write(self::ESC.'J'.chr($dots));
704
    }
705
706
    /**
707
     * Generate a pulse, for opening a cash drawer if one is connected.
708
     * The default settings should open an Epson drawer.
709
     *
710
     * @param int $pin    0 or 1, for pin 2 or pin 5 kick-out connector respectively.
711
     * @param int $on_ms  pulse ON time, in milliseconds.
712
     * @param int $off_ms pulse OFF time, in milliseconds.
713
     */
714
    public function pulse($pin = 0, $on_ms = 120, $off_ms = 240)
715
    {
716
        $pin = self::validateInteger($pin, 0, 1, 0);
717
        $on_ms = self::validateInteger($on_ms, 1, 511, 120);
718
        $off_ms = self::validateInteger($off_ms, 1, 511, 240);
719
        $this->buffer->write(self::ESC.'p'.chr($pin + 48).chr($on_ms / 2).chr($off_ms / 2));
720
    }
721 1
722
    /**
723
     * Cut the paper.
724
     *
725
     * @param int $mode  FULL or PARTIAL. If not specified, FULL will be used.
726
     * @param int $lines Number of lines to feed after cut
727
     */
728
    public function cut($mode = 'PARTIAL', $lines = 3)
729
    {
730 1
        $lines = self::validateInteger($lines, 1, 10, 3);
731
        if ($mode == 'FULL') {
732
            $mode = self::CUT_FULL;
733 1
        } else {
734
            $mode = self::CUT_PARTIAL;
735
        }
736 1
        $this->buffer->write(self::GS.'V'.chr($mode).chr($lines));
737
    }
738
739 1
    /**
740
     * Implements barcodes 1D
741 1
     * GS k m n d1...dn
742 1
     * Prints bar code. n specifies the data length.
743 1
     *   m    bar code system             number of d (=k)
744 1
     *  "A"     UPC-A                       11 or 12
745
     *  "B"     UPC-E                       6, 7, 8, 11 or 12
746
     *  "C"     JAN13 / EAN13               12 or 13
747 1
     *  "D"     JAN8 / EAN8                 7 or 8
748 1
     *  "E"     CODE39                      1 or more
749
     *  "F"     ITF                         even
750
     *  "G"     CODABAR (NW-7)              2 or more
751 1
     *  "H"     CODE93                      1–255
752 1
     *  "I"     CODE128                     2–255
753 1
     *  "J"     GS1-128                     2–255
754
     *  "K"     GS1 DataBar Omnidirectional 13
755 1
     *  "L"     GS1 DataBar Truncated       13
756
     *  "M"     GS1 DataBar Limited         13
757 1
     *  "N"     GS1 DataBar Expanded        2–255.
758
     *
759 1
     *  GS h n Sets bar code height to n dots.
760
     *  GS w n Sets bar width of bar code. n = 2–6 (thin–thick)
761 1
     *  GS H n Selects print position of HRI characters.
762
     *           n = 0, "0": Not printed
763 1
     *           n = 1, "1": Above the bar code
764 1
     *           n = 2, "2": Below the bar code
765
     *           n = 3, "3": Both above and below the bar code
766
     *  GS f n Selects font for the HRI characters.
767
     *           n = 0, "0": Font A,
768
     *           n = 1, "1": Font B
769
     *
770
     * @param string $data
771
     * @param int    $type        Default CODE128
772
     * @param int    $height
773
     * @param int    $lineWidth
774 1
     * @param string $txtPosition
775
     * @param string $txtFont
776
     */
777 1
    public function barcode(
778 1
        $data = '123456',
779
        $type = 'CODE128',
780
        $height = 162,
781
        $lineWidth = 2,
782 1
        $txtPosition = 'none',
783
        $txtFont = ''
784 1
    ) {
785
        switch ($txtPosition) {
786 1
            case 'Above':
787
                $tPos = 1;
788 1
                break;
789
            case 'Below':
790
                $tPos = 2;
791 1
                break;
792 1
            case 'Both':
793 1
                $tPos = 3;
794
                break;
795
            default:
796
                //none
797
                $tPos = 0;
798
        }
799
        $font = 0;
800
        if ($txtFont === 'B') {
801
            $font = 1;
802
        }
803 1
        if (! $data = Barcodes\Barcode1DAnalysis::validate($data, $type)) {
804
            throw new \InvalidArgumentException('Data or barcode type is incorrect.');
805 1
        }
806 1
        if (! array_key_exists($type, $this->barcode1Dlist)) {
807 1
            throw new \InvalidArgumentException('This barcode type is not listed.');
808 1
        }
809
        $id = $this->barcode1Dlist[$type];
810 1
        if (is_null($id)) {
811 1
            return;
812
        }
813
        $height = self::validateInteger($height, 1, 255, 4);
814
        $lineWidth = self::validateInteger($lineWidth, 1, 6, 2);
815
        $nlen = strlen($data);
816
        //set barcode height
817
        $this->buffer->write(self::GS.'h'.chr($height));
818
        //set barcode bar width
819
        $this->buffer->write(self::GS.'w'.chr($lineWidth));
820
        //Selects print position of HRI characters.
821
        $this->buffer->write(self::GS.'H'.chr($tPos));
822
        //Selects font for the HRI characters.
823
        $this->buffer->write(self::GS.'f'.chr($font));
824
        //Print barcode
825
        $this->buffer->write(self::GS.'k'.chr($id).chr($nlen).$data);
826
    }
827 20
    
828
    /**
829
     * Imprime o QR Code
830 20
     *
831
     * @param string $data   Dados a serem inseridos no QRCode
832
     * @param string $level  Nivel de correção L,M,Q ou H
833
     * @param int    $modelo modelo de QRCode 1, 2 ou 0 Micro
834 20
     * @param int    $wmod   largura da barra 3 ~ 16
835
     */
836 20
    public function barcodeQRCode($data = '', $level = 'L', $modelo = 2, $wmod = 4)
837 20
    {
838
        //set model of QRCode
839
        $n1 = 50;
840
        if ($modelo == 1) {
841
            $n1 = 49;
842
        }
843
        //select QR model
844
        $this->buffer->write(self::GS."(k".chr(4).chr(0).chr(49).chr(65).chr($n1).chr(0));
845
        //set module bar width
846
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(67).chr($wmod));
847
        //set error correction level
848
        $level = strtoupper($level);
849
        switch ($level) {
850
            case 'L':
851
                $n = 48;
852
                break;
853
            case 'M':
854
                $n = 49;
855
                break;
856
            case 'Q':
857
                $n = 50;
858
                break;
859
            case 'H':
860 20
                $n = 51;
861
                break;
862
            default:
863
                $n = 49;
864
        }
865
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(69).chr($n));
866
        //set data for QR Code assuming print only alphanumeric data
867
        $len = strlen($data) + 3;
868
        $pH = ($len / 256);
869
        $pL = $len % 256;
870
        $this->buffer->write(self::GS."(k".chr($pL).chr($pH).chr(49).chr(80).chr(48).$data);
871
        //Print QR Code
872
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(81).chr(48));
873
    }
874
875
    /**
876
     * Return all data buffer.
877
     *
878
     * @param string $type specifies the return format
879
     */
880
    public function getBuffer($type = '')
881
    {
882
        switch ($type) {
883
            case 'binA':
884
                //returns a binary array of buffer
885
                $resp = $this->buffer->getDataBinary(true);
886
                break;
887
            case 'binS':
888 1
                //returns a binary string of buffer
889
                $resp = $this->buffer->getDataBinary(false);
890
                break;
891 1
            case 'b64A':
892 1
                //returns a base64 encoded array of buffer
893 1
                $resp = $this->buffer->getDataBase64(true);
894 1
                break;
895 1
            case 'b64S':
896 1
                //returns a base64 encoded string of buffer
897 1
                $resp = $this->buffer->getDataBase64(false);
898 1
                break;
899 1
            case 'json':
900 1
                //returns a json encoded of array buffer
901 1
                $resp = $this->buffer->getDataJson();
902 1
                break;
903 1
            case 'readA':
904 1
                //returns a human readable format of array buffer
905 1
                //only for debug reasons
906 1
                $resp = $this->buffer->getDataReadable(true);
907
                break;
908
            default:
909 1
                //returns a human readable format of string buffer
910 1
                //only for debug reasons
911 1
                $resp = $this->buffer->getDataReadable(false);
912 1
        }
913
        return $resp;
914
    }
915
916
    /**
917
     * Send commands from buffer to connector printer.
918 1
     */
919
    public function send(ConnectorInterface $conn = null)
920
    {
921
        if (!is_null($conn)) {
922
            $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...
923
        }
924
        if (is_null($this->connector)) {
925
            return $this->getBuffer();
926
        }
927
        $aCmds = $this->getBuffer('binA');
928
        foreach ($aCmds as $cmd) {
929
            $this->connector->write($cmd);
930 1
        }
931
    }
932
933 1
    /**
934 1
     * Insert a image.
935
     *
936
     * @param  string $filename Path to image file
937
     * @param  float  $width
938
     * @param  float  $height
939 1
     * @param  int    $size     0-normal 1-Double Width 2-Double Heigth
940 1
     * @throws RuntimeException
941 1
     */
942 1
    public function putImage($filename = '', $width = null, $height = null, $size = 0)
943 1
    {
944 1
        try {
945 1
            $img = new Graphics($filename, $width, $height);
946 1
        } catch (RuntimeException $e) {
947 1
            throw new RuntimeException($e->getMessage());
948 1
        } catch (InvalidArgumentException $e) {
949
            throw new RuntimeException($e->getMessage());
950
        }
951
        $size = self::validateInteger($size, 0, 3, 0);
952
        $imgHeader = self::dataHeader(array($img->getWidth(), $img->getHeight()), true);
953
        $tone = '0';
954
        $colors = '1';
955
        $xm = (($size & self::IMG_DOUBLE_WIDTH) == self::IMG_DOUBLE_WIDTH) ? chr(2) : chr(1);
956
        $ym = (($size & self::IMG_DOUBLE_HEIGHT) == self::IMG_DOUBLE_HEIGHT) ? chr(2) : chr(1);
957 1
        $header = $tone.$xm.$ym.$colors.$imgHeader;
958
        $this->sendGraphicsData('0', 'p', $header.$img->getRasterImage());
959 1
        $this->sendGraphicsData('0', '2');
960 1
    }
961 1
962
    /**
963
     * Close and clean buffer
964
     * All data will be lost.
965
     */
966
    public function close()
967
    {
968
        $this->buffer->close();
969
    }
970 1
    
971
    /**
972 1
     * Wrapper for GS ( L, to calculate and send correct data length.
973 1
     *
974 1
     * @param string $m    Modifier/variant for function. Usually '0'.
975 1
     * @param string $fn   Function number to use, as character.
976 1
     * @param string $data Data to send.
977 1
     */
978 1
    protected function sendGraphicsData($m, $fn, $data = '')
979
    {
980
        $header = $this->intLowHigh(strlen($data) + 2, 2);
981
        $this->buffer->write(self::GS.'(L'.$header.$m.$fn.$data);
982
    }
983
984
    /**
985
     * Generate two characters for a number:
986
     * In lower and higher parts, or more parts as needed.
987
     *
988
     * @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...
989 1
     * @param int $length The number of bytes to output (1 - 4).
990
     */
991 1
    protected static function intLowHigh($input, $length)
992 1
    {
993 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...
994 1
        $outp = '';
995 1
        for ($i = 0; $i < $length; ++$i) {
996
            $outp .= chr($input % 256);
997
            $input = (int) ($input / 256);
998
        }
999 1
        return $outp;
1000 1
    }
1001
1002
    /**
1003
     * Convert widths and heights to characters.
1004
     * Used before sending graphics to set the size.
1005
     *
1006
     * @param  array $inputs
1007
     * @param  bool  $long   True to use 4 bytes, false to use 2
1008
     * @return string
1009
     */
1010
    protected static function dataHeader(array $inputs, $long = true)
1011
    {
1012
        $outp = array();
1013
        foreach ($inputs as $input) {
1014
            if ($long) {
1015
                $outp[] = self::intLowHigh($input, 2);
1016
            } else {
1017
                $input = self::validateInteger($input, 0, 255, 0);
1018
                $outp[] = chr($input);
1019
            }
1020
        }
1021
        return implode('', $outp);
1022
    }
1023
1024
    /**
1025
     * Verify if the argument given is not a boolean.
1026
     *
1027
     * @param  bool $test    the input to test
1028 10
     * @param  bool $default the default value
1029
     * @return bool
1030 10
     */
1031 1
    protected static function validateBoolean($test, $default)
1032
    {
1033 10
        if (!($test === true || $test === false)) {
1034
            return $default;
1035
        }
1036
        return $test;
1037
    }
1038
1039
    /**
1040
     * Verify if the argument given is not an integer within the specified range.
1041
     * will return default instead
1042
     *
1043
     * @param  int $test    the input to test
1044
     * @param  int $min     the minimum allowable value (inclusive)
1045
     * @param  int $max     the maximum allowable value (inclusive)
1046
     * @param  int $default the default value
1047
     * @return int
1048
     */
1049
    protected static function validateInteger($test, $min, $max, $default)
1050
    {
1051
        if (!is_integer($test) || $test < $min || $test > $max) {
1052
            return $default;
1053
        }
1054
        return $test;
1055
    }
1056
1057
    /**
1058 1
     * Verify if the argument given can't be cast to a string.
1059
     *
1060 1
     * @param  string $test    the input to test
1061 1
     * @param  string $default the default value
1062 1
     * @return string
1063 1
     */
1064 1
    protected static function validateString($test, $default)
1065 1
    {
1066 1
        if (is_object($test) && !method_exists($test, '__toString')) {
1067 1
            return $default;
1068
        }
1069
        return $test;
1070
    }
1071
    
1072
    /**
1073
     * Translate the text from UTF-8 for the specified codepage
1074
     * this translation uses "iconv" and admits texts ONLY in UTF-8.
1075
     *
1076
     * @param  string $text
1077
     * @return string
1078
     */
1079
    protected function translate($text = '')
1080
    {
1081
        $indCode = $this->defaultCodePage();
1082
        if (!empty($indCode)) {
1083
            $codep = $this->aCodePage[$indCode];
1084
            if (!empty($codep)) {
1085
                $text = iconv('UTF-8', $codep['conv'], $text);
1086
            }
1087
        }
1088
        return $text;
1089
    }
1090
}
1091