vendor/endroid/qr-code/src/Builder/Builder.php line 246

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Endroid\QrCode\Builder;
  4. use Endroid\QrCode\Color\ColorInterface;
  5. use Endroid\QrCode\Encoding\EncodingInterface;
  6. use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelInterface;
  7. use Endroid\QrCode\Exception\ValidationException;
  8. use Endroid\QrCode\Label\Alignment\LabelAlignmentInterface;
  9. use Endroid\QrCode\Label\Font\FontInterface;
  10. use Endroid\QrCode\Label\Label;
  11. use Endroid\QrCode\Label\LabelInterface;
  12. use Endroid\QrCode\Label\Margin\MarginInterface;
  13. use Endroid\QrCode\Logo\Logo;
  14. use Endroid\QrCode\Logo\LogoInterface;
  15. use Endroid\QrCode\QrCode;
  16. use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeInterface;
  17. use Endroid\QrCode\Writer\PngWriter;
  18. use Endroid\QrCode\Writer\Result\ResultInterface;
  19. use Endroid\QrCode\Writer\ValidatingWriterInterface;
  20. use Endroid\QrCode\Writer\WriterInterface;
  21. class Builder implements BuilderInterface
  22. {
  23. /**
  24. * @var array<string, mixed>{
  25. * data: string,
  26. * writer: WriterInterface,
  27. * writerOptions: array,
  28. * qrCodeClass: class-string,
  29. * logoClass: class-string,
  30. * labelClass: class-string,
  31. * validateResult: bool,
  32. * size?: int,
  33. * encoding?: EncodingInterface,
  34. * errorCorrectionLevel?: ErrorCorrectionLevelInterface,
  35. * roundBlockSizeMode?: RoundBlockSizeModeInterface,
  36. * margin?: int,
  37. * backgroundColor?: ColorInterface,
  38. * foregroundColor?: ColorInterface,
  39. * labelText?: string,
  40. * labelFont?: FontInterface,
  41. * labelAlignment?: LabelAlignmentInterface,
  42. * labelMargin?: MarginInterface,
  43. * labelTextColor?: ColorInterface,
  44. * logoPath?: string,
  45. * logoResizeToWidth?: int,
  46. * logoResizeToHeight?: int,
  47. * logoPunchoutBackground?: bool
  48. * }
  49. */
  50. private array $options;
  51. public function __construct()
  52. {
  53. $this->options = [
  54. 'data' => '',
  55. 'writer' => new PngWriter(),
  56. 'writerOptions' => [],
  57. 'qrCodeClass' => QrCode::class,
  58. 'logoClass' => Logo::class,
  59. 'labelClass' => Label::class,
  60. 'validateResult' => false,
  61. ];
  62. }
  63. public static function create(): BuilderInterface
  64. {
  65. return new self();
  66. }
  67. public function writer(WriterInterface $writer): BuilderInterface
  68. {
  69. $this->options['writer'] = $writer;
  70. return $this;
  71. }
  72. /** @param array<string, mixed> $writerOptions */
  73. public function writerOptions(array $writerOptions): BuilderInterface
  74. {
  75. $this->options['writerOptions'] = $writerOptions;
  76. return $this;
  77. }
  78. public function data(string $data): BuilderInterface
  79. {
  80. $this->options['data'] = $data;
  81. return $this;
  82. }
  83. public function encoding(EncodingInterface $encoding): BuilderInterface
  84. {
  85. $this->options['encoding'] = $encoding;
  86. return $this;
  87. }
  88. public function errorCorrectionLevel(ErrorCorrectionLevelInterface $errorCorrectionLevel): BuilderInterface
  89. {
  90. $this->options['errorCorrectionLevel'] = $errorCorrectionLevel;
  91. return $this;
  92. }
  93. public function size(int $size): BuilderInterface
  94. {
  95. $this->options['size'] = $size;
  96. return $this;
  97. }
  98. public function margin(int $margin): BuilderInterface
  99. {
  100. $this->options['margin'] = $margin;
  101. return $this;
  102. }
  103. public function roundBlockSizeMode(RoundBlockSizeModeInterface $roundBlockSizeMode): BuilderInterface
  104. {
  105. $this->options['roundBlockSizeMode'] = $roundBlockSizeMode;
  106. return $this;
  107. }
  108. public function foregroundColor(ColorInterface $foregroundColor): BuilderInterface
  109. {
  110. $this->options['foregroundColor'] = $foregroundColor;
  111. return $this;
  112. }
  113. public function backgroundColor(ColorInterface $backgroundColor): BuilderInterface
  114. {
  115. $this->options['backgroundColor'] = $backgroundColor;
  116. return $this;
  117. }
  118. public function logoPath(string $logoPath): BuilderInterface
  119. {
  120. $this->options['logoPath'] = $logoPath;
  121. return $this;
  122. }
  123. public function logoResizeToWidth(int $logoResizeToWidth): BuilderInterface
  124. {
  125. $this->options['logoResizeToWidth'] = $logoResizeToWidth;
  126. return $this;
  127. }
  128. public function logoResizeToHeight(int $logoResizeToHeight): BuilderInterface
  129. {
  130. $this->options['logoResizeToHeight'] = $logoResizeToHeight;
  131. return $this;
  132. }
  133. public function logoPunchoutBackground(bool $logoPunchoutBackground): BuilderInterface
  134. {
  135. $this->options['logoPunchoutBackground'] = $logoPunchoutBackground;
  136. return $this;
  137. }
  138. public function labelText(string $labelText): BuilderInterface
  139. {
  140. $this->options['labelText'] = $labelText;
  141. return $this;
  142. }
  143. public function labelFont(FontInterface $labelFont): BuilderInterface
  144. {
  145. $this->options['labelFont'] = $labelFont;
  146. return $this;
  147. }
  148. public function labelAlignment(LabelAlignmentInterface $labelAlignment): BuilderInterface
  149. {
  150. $this->options['labelAlignment'] = $labelAlignment;
  151. return $this;
  152. }
  153. public function labelMargin(MarginInterface $labelMargin): BuilderInterface
  154. {
  155. $this->options['labelMargin'] = $labelMargin;
  156. return $this;
  157. }
  158. public function labelTextColor(ColorInterface $labelTextColor): BuilderInterface
  159. {
  160. $this->options['labelTextColor'] = $labelTextColor;
  161. return $this;
  162. }
  163. public function validateResult(bool $validateResult): BuilderInterface
  164. {
  165. $this->options['validateResult'] = $validateResult;
  166. return $this;
  167. }
  168. public function build(): ResultInterface
  169. {
  170. $writer = $this->options['writer'];
  171. if ($this->options['validateResult'] && !$writer instanceof ValidatingWriterInterface) {
  172. throw ValidationException::createForUnsupportedWriter(strval(get_class($writer)));
  173. }
  174. /** @var QrCode $qrCode */
  175. $qrCode = $this->buildObject($this->options['qrCodeClass']);
  176. /** @var LogoInterface|null $logo */
  177. $logo = $this->buildObject($this->options['logoClass'], 'logo');
  178. /** @var LabelInterface|null $label */
  179. $label = $this->buildObject($this->options['labelClass'], 'label');
  180. $result = $writer->write($qrCode, $logo, $label, $this->options['writerOptions']);
  181. if ($this->options['validateResult'] && $writer instanceof ValidatingWriterInterface) {
  182. $writer->validateResult($result, $qrCode->getData());
  183. }
  184. return $result;
  185. }
  186. /**
  187. * @param class-string $class
  188. *
  189. * @return mixed
  190. */
  191. private function buildObject(string $class, string $optionsPrefix = null)
  192. {
  193. /** @var \ReflectionClass<object> $reflectionClass */
  194. $reflectionClass = new \ReflectionClass($class);
  195. $arguments = [];
  196. $hasBuilderOptions = false;
  197. $missingRequiredArguments = [];
  198. /** @var \ReflectionMethod $constructor */
  199. $constructor = $reflectionClass->getConstructor();
  200. $constructorParameters = $constructor->getParameters();
  201. foreach ($constructorParameters as $parameter) {
  202. $optionName = null === $optionsPrefix ? $parameter->getName() : $optionsPrefix.ucfirst($parameter->getName());
  203. if (isset($this->options[$optionName])) {
  204. $hasBuilderOptions = true;
  205. $arguments[] = $this->options[$optionName];
  206. } elseif ($parameter->isDefaultValueAvailable()) {
  207. $arguments[] = $parameter->getDefaultValue();
  208. } else {
  209. $missingRequiredArguments[] = $optionName;
  210. }
  211. }
  212. if (!$hasBuilderOptions) {
  213. return null;
  214. }
  215. if (count($missingRequiredArguments) > 0) {
  216. throw new \Exception(sprintf('Missing required arguments: %s', implode(', ', $missingRequiredArguments)));
  217. }
  218. return $reflectionClass->newInstanceArgs($arguments);
  219. }
  220. }