1<?php
2
3namespace Egulias\EmailValidator;
4
5use Egulias\EmailValidator\Exception\ExpectingATEXT;
6use Egulias\EmailValidator\Exception\NoLocalPart;
7use Egulias\EmailValidator\Parser\DomainPart;
8use Egulias\EmailValidator\Parser\LocalPart;
9use Egulias\EmailValidator\Warning\EmailTooLong;
10
11/**
12 * EmailParser
13 *
14 * @author Eduardo Gulias Davis <me@egulias.com>
15 */
16class EmailParser
17{
18    const EMAIL_MAX_LENGTH = 254;
19
20    protected $warnings;
21    protected $domainPart = '';
22    protected $localPart = '';
23    protected $lexer;
24    protected $localPartParser;
25    protected $domainPartParser;
26
27    public function __construct(EmailLexer $lexer)
28    {
29        $this->lexer = $lexer;
30        $this->localPartParser = new LocalPart($this->lexer);
31        $this->domainPartParser = new DomainPart($this->lexer);
32        $this->warnings = new \SplObjectStorage();
33    }
34
35    /**
36     * @param $str
37     * @return array
38     */
39    public function parse($str)
40    {
41        $this->lexer->setInput($str);
42
43        if (!$this->hasAtToken()) {
44            throw new NoLocalPart();
45        }
46
47
48        $this->localPartParser->parse($str);
49        $this->domainPartParser->parse($str);
50
51        $this->setParts($str);
52
53        if ($this->lexer->hasInvalidTokens()) {
54            throw new ExpectingATEXT();
55        }
56
57        return array('local' => $this->localPart, 'domain' => $this->domainPart);
58    }
59
60    public function getWarnings()
61    {
62        $localPartWarnings = $this->localPartParser->getWarnings();
63        $domainPartWarnings = $this->domainPartParser->getWarnings();
64        $this->warnings = array_merge($localPartWarnings, $domainPartWarnings);
65
66        $this->addLongEmailWarning($this->localPart, $this->domainPart);
67
68        return $this->warnings;
69    }
70
71    public function getParsedDomainPart()
72    {
73        return $this->domainPart;
74    }
75
76    protected function setParts($email)
77    {
78        $parts = explode('@', $email);
79        $this->domainPart = $this->domainPartParser->getDomainPart();
80        $this->localPart = $parts[0];
81    }
82
83    protected function hasAtToken()
84    {
85        $this->lexer->moveNext();
86        $this->lexer->moveNext();
87        if ($this->lexer->token['type'] === EmailLexer::S_AT) {
88            return false;
89        }
90
91        return true;
92    }
93
94    /**
95     * @param string $localPart
96     * @param string $parsedDomainPart
97     */
98    protected function addLongEmailWarning($localPart, $parsedDomainPart)
99    {
100        if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) {
101            $this->warnings[EmailTooLong::CODE] = new EmailTooLong();
102        }
103    }
104}
105