public function register(Template $template) { foreach (['timeAgo', 'duration', 'hours', 'minutes', 'templateLink', 'lcFirst', 'subjectColor', 'subjectIcon', 'highlight', 'vlna'] as $filter) { $template->addFilter($filter, [$this, $filter]); } $cases = ['nominative' => 1, 'genitive' => 2, 'dative' => 3, 'accusative' => 4, 'vocative' => 5, 'locative' => 6, 'instrumental' => 7]; foreach ($cases as $name => $case) { $template->addFilter($name, function ($phrase) use($case) { return $this->inflection->inflect($phrase, $case); }); } }
/** * Translates the given string. * * @param string $steps * @param int $count * @param array $args * @throws \App\InvalidStateException * @throws \App\InvalidArgumentException * @return string */ public function translate($steps, $count = NULL, array $args = []) { // alias for translate($steps, $args) if (is_array($count) && !$args) { $args = $count; $count = NULL; } if (strpos($steps, ' ') !== FALSE) { throw new InvalidArgumentException("Translator expects key such as 'homepage.flash.error', not an actual message."); } if ($this->language === NULL) { throw new InvalidStateException('Translator language not set'); } if (strpos($steps, '/') === 0) { $steps = ltrim($steps, '/'); } else { $steps = $this->prefix . $steps; } $text = $this->findTextByKey($steps, $count); if ($text === NULL) { return $this->fallback($steps, $count); } $values = $args; $values[1] = $count; $translated = preg_replace_callback('~%([\\w\\d]+)(?:\\((?P<case>[a-z1-7])\\))?~i', function ($match) use($values, $steps) { $key = $match[1]; if (!isset($values[$key])) { $count = count($values); $this->log->addNotice("Translation for '{$steps}' has placeholder for '{$match['0']}' but arg count is {$count}", [$this->language]); return $match[0]; } if (isset($match['case'])) { return $this->inflection->inflect($values[$key], $match['case']); } return $values[$key]; }, $text); if (array_key_exists(self::GENDER, $values)) { // inflect by gender from '[he|she]' syntax $isFemale = $values[self::GENDER] === Gender::FEMALE; $translated = preg_replace_callback('~\\[([^|]*)\\|([^|]*)\\]~', function ($m) use($isFemale) { return $isFemale ? $m[2] : $m[1]; }, $translated); } return $translated; }
/** * @param string $view email template * @param User $user * @param NULL|array $args template variables * * @throws Exception from Latte\Engine * @throws SmtpException from Mailer */ public function send($view, User $user, array $args = []) { if ($this->orm->unsubscribes->getByEmail($user->email)) { // Last line of defense. Make sure unsubscribed users // really dont receive any email. This should however // be handled before the task is queued. $this->logger->addAlert("Email to '{$user->email}' not send, user unsubscribed. Find out why it was queued"); return; } $msg = new Message(); $msg->setFrom('Khanova škola <*****@*****.**>'); $msg->addReplyTo('Markéta Matějíčková <*****@*****.**>'); $msg->addTo($user->email, $user->name); $token = Unsubscribe::createFromUser($user); $token->emailType = $view; $this->orm->tokens->attach($token); $this->orm->flush(); $args['recipient'] = $user; $args['email'] = $msg; $args['unsubscribe'] = (object) ['token' => $token, 'code' => $token->getUnsafe()]; $args['baseUrl'] = rtrim($this->baseUrl, '/'); $latte = new Engine(); /** @var Presenters\Token $presenter */ $presenter = $this->factory->createPresenter('Token'); $presenter->autoCanonicalize = FALSE; $ref = new \ReflectionProperty(Presenter::class, 'globalParams'); $ref->setAccessible(TRUE); $ref->setValue($presenter, []); $latte->addFilter('token', function (Token $token, $unsafe) use($presenter, $view) { return $presenter->link('//Token:', ['token' => $token->toString($unsafe), 'utm_campaign' => "email-{$view}"]); }); $latte->addFilter('vocative', function ($phrase) { return $this->inflection->inflect($phrase, 5); }); $template = $latte->renderToString($this->getTemplate($view), $args); $msg->setHtmlBody($template); $this->mailer->send($msg); $this->logger->addInfo('Email send', ['view' => $view, 'email' => $user->email]); }
/** * @param array $node * @param array $vars * @param $inLatex * @param $inColor * @return string */ private function compileNode(array $node, array $vars, &$inLatex, &$inColor) { switch ($node['tag']) { case self::T_TEXT: return isset($node['value']) ? $node['value'] : ''; case self::T_EVAL: if ($node['type'] !== self::S_COMPLETE) { throw new InvalidArgumentException(); } return $this->evaluate($node['value'], $vars); case self::T_LATEX: if ($node['type'] === self::S_OPEN) { $inLatex = TRUE; $out = '$'; if ($inColor) { $open = $this->getColorOpen($inColor, TRUE); $out = "</span>\${$open}"; } return $out . (isset($node['value']) ? $node['value'] : ''); } else { if ($node['type'] === self::S_CLOSE) { $inLatex = FALSE; if ($inColor) { $open = $this->getColorOpen($inColor, FALSE); return "}\${$open}"; } return '$'; } else { if ($node['type'] === self::S_INNER) { return $node['value']; } else { if ($inColor) { $openLatex = $this->getColorOpen($inColor, TRUE); $openText = $this->getColorOpen($inColor, FALSE); return "</span>\${$openLatex}{$node['value']}}\${$openText}"; } return '$' . $node['value'] . '$'; } } } case self::T_COLOR: $color = $inColor ?: $node['attributes']['ID']; $open = $this->getColorOpen($color, $inLatex); $close = $inLatex ? '}' : '</span>'; if ($node['type'] === self::S_COMPLETE) { return $open . $node['value'] . $close; } else { if ($node['type'] === self::S_OPEN) { $inColor = $color; return $open . (isset($node['value']) ? $node['value'] : ''); } else { if ($node['type'] === self::S_INNER) { return $node['value']; } else { $inColor = FALSE; return $close; } } } case self::T_INFLECT: if ($node['type'] === self::S_COMPLETE) { return $this->inflection->inflect($node['value'], $node['attributes']['CASE']); } else { if ($node['type'] === self::S_OPEN) { $this->bufferLevel++; $this->bufferData[$this->bufferLevel] = $node['attributes']['CASE']; return ''; } else { if ($node['type'] === self::S_INNER) { return $node['value']; } else { $buffer = $this->buffers[$this->bufferLevel]; $case = $this->bufferData[$this->bufferLevel]; $out = $this->inflection->inflect($buffer, $case); $this->bufferLevel--; array_pop($this->buffers); return $out; } } } case self::T_IMG: if ($node['type'] !== self::S_COMPLETE) { throw new BlueprintCompilerException('Invalid image syntax'); } $url = isset($node['attributes']['SRC']) ? $node['attributes']['SRC'] : $this->evaluate($node['attributes']['EVALSRC'], $vars); if (strpos($url, 'http://') !== FALSE) { throw new BlueprintCompilerException("Invalid image source '{$url}', http not allowed."); } if (strpos($url, 'https://') === FALSE) { $url = "/data/exercise/{$url}"; } $count = $this->evaluate($node['attributes']['COUNT'], $vars); $size = isset($node['attributes']['SIZE']) ? $node['attributes']['SIZE'] : 48; return str_repeat("<img src=\"{$url}\" height=\"{$size}\" />", max(0, $count)); case self::T_NUMBER: if ($node['type'] === self::S_COMPLETE) { return Cislo::toWord($node['value']); } else { if ($node['type'] === self::S_OPEN) { $this->bufferLevel++; return ''; } else { if ($node['type'] === self::S_INNER) { return $node['value']; } else { $buffer = $this->buffers[$this->bufferLevel]; $out = Cislo::toWord($buffer); $this->bufferLevel--; array_pop($this->buffers); return $out; } } } case self::T_BOX: return '<span class="fillin-box"></span>'; default: throw new NotImplementedException("Unknown tag '{$node['tag']}' in '{$this->errorContext}'"); } }
/** * @param string $firstName * @param NULL|string $lastName * @return Gender::MALE|Gender::FEMALE */ public function getGender($firstName, $lastName = NULL) { return $this->inflection->gender($firstName); }