Completed
Pull Request — master (#16)
by Fabien
07:08 queued 03:51
created

CurriculumVitae::getCurriculumVitaeArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
ccs 10
cts 10
cp 1
rs 9.4285
cc 1
eloc 10
nc 1
nop 0
crap 1
1
<?php
2
3
/*
4
 * This file is part of the FabienCrassat\CurriculumVitaeBundle Symfony bundle.
5
 *
6
 * (c) Fabien Crassat <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FabienCrassat\CurriculumVitaeBundle\Entity;
13
14
use FabienCrassat\CurriculumVitaeBundle\Utility\LibXmlDisplayErrors;
15
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
16
17
class CurriculumVitae extends Xml2arrayFunctions
18
{
19
    private $lang;
20
    private $curriculumVitae;
21
    private $pathToFile;
22
    private $interface;
23
    private $cvFile;
24
    private $xml2arrayFunctions;
25
26
    /**
27
     * @param string $pathToFile
28
     * @param string $lang
29
     */
30 29
    public function __construct($pathToFile, $lang = 'en') {
31 29
        $this->pathToFile = $pathToFile;
32 29
        $this->setFileName();
33 29
        $this->lang               = $lang;
34 29
        $this->curriculumVitae    = $this->getXmlCurriculumVitae();
35 26
        $this->xml2arrayFunctions = New Xml2arrayFunctions($this->curriculumVitae, $this->lang);
36 26
    }
37
38
    /**
39
     * @return null|array
40
     */
41 23
    public function getDropDownLanguages() {
42 23
        $this->interface = $this->curriculumVitae->{'langs'};
43 9
        $return          = $this->getXMLValue();
44 9
        if(!$return) {
45 1
            $return = array($this->lang => $this->lang);
46 1
        }
47
48 9
        return $return;
49
    }
50
51
    /**
52
     * @return array
53
     */
54 4
    public function getAnchors() {
55 4
        $anchorsAttribute = $this->curriculumVitae->xpath('curriculumVitae/*[attribute::anchor]');
56
57 4
        $anchors = array();
58 4
        foreach ($anchorsAttribute as $anchorsValue) {
59 4
            $anchor = (string) $anchorsValue['anchor'];
60 4
            $title  = $anchorsValue->xpath("anchorTitle[@lang='" . $this->lang . "']");
61 4
            if (count($title) == 0) {
62 1
                $title = $anchorsValue->xpath('anchorTitle');
63 1
            }
64 4
            $anchors[$anchor] = array(
65 4
                'href'  => $anchor,
66 4
                'title' => (string) $title[0],
67
            );
68 4
        };
69
70 4
        return $anchors;
71
    }
72
73
    /**
74
     * @return string
75
     */
76 5
    public function getHumanFileName() {
77 5
        $myName = $this->getMyName();
78 5
        if (empty($myName)) return $this->cvFile;
79
80 4
        $myCurrentJob = $this->getMyCurrentJob();
81 4
        if (empty($myCurrentJob)) return $myName;
82
83 3
        return $myName.' - '.$myCurrentJob;
84
    }
85
86
    /**
87
     * @return array<string,array|null>
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,null|array<string,array>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
88
     */
89 5
    public function getCurriculumVitaeArray() {
90
        return array(
91 5
            'identity'          => $this->getIdentity(),
92 5
            'followMe'          => $this->getFollowMe(),
93 5
            'lookingFor'        => $this->getLookingFor(),
94 5
            'experiences'       => $this->getExperiences(),
95 5
            'skills'            => $this->getSkills(),
96 5
            'educations'        => $this->getEducations(),
97 5
            'languageSkills'    => $this->getLanguageSkills(),
98 5
            'miscellaneous'     => $this->getMiscellaneous(),
99 5
        );
100
    }
101
102
    /**
103
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
104
     */
105 13
    public function getIdentity() {
106 13
        $this->interface = $this->curriculumVitae->curriculumVitae->identity->items;
107 13
        return $this->getXMLValue();
108
    }
109
110
    /**
111
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
112
     */
113 6
    public function getFollowMe() {
114 6
        $this->interface = $this->curriculumVitae->curriculumVitae->followMe->items;
115 6
        return $this->getXMLValue();
116
    }
117
118
    /**
119
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
120
     */
121 11
    public function getLookingFor() {
122 11
        $this->interface = $this->curriculumVitae->curriculumVitae->lookingFor;
123 11
        return $this->getXMLValue();
124
    }
125
126
    /**
127
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
128
     */
129 7
    public function getExperiences() {
130 7
        $this->interface = $this->curriculumVitae->curriculumVitae->experiences->items;
131 7
        return $this->getXMLValue();
132
    }
133
134
    /**
135
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
136
     */
137 6
    public function getSkills() {
138 6
        $this->interface = $this->curriculumVitae->curriculumVitae->skills->items;
139 6
        return $this->getXMLValue();
140
    }
141
142
    /**
143
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
144
     */
145 6
    public function getEducations() {
146 6
        $this->interface = $this->curriculumVitae->curriculumVitae->educations->items;
147 6
        return $this->getXMLValue();
148
    }
149
150
    /**
151
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
152
     */
153 6
    public function getLanguageSkills() {
154 6
        $this->interface = $this->curriculumVitae->curriculumVitae->languageSkills->items;
155 6
        return $this->getXMLValue();
156
    }
157
158
    /**
159
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
160
     */
161 6
    public function getMiscellaneous() {
162 6
        $this->interface = $this->curriculumVitae->curriculumVitae->miscellaneous->items;
163 6
        return $this->getXMLValue();
164
    }
165
166 29
    private function setFileName() {
167 29
        $data = explode('/', $this->pathToFile);
168 29
        $data = $data[count($data) - 1];
169 29
        $data = explode('.', $data);
170
171 29
        $this->cvFile = $data[0];
172 29
    }
173
174
    /**
175
     * @return null|string
176
     */
177 5
    private function getMyName() {
178 5
        $identity = $this->getIdentity();
179
180 5
        if (isset($identity['myself']['name'])) {
181 4
            return $identity['myself']['name'];
182
        }
183
184 1
        return NULL;
185
    }
186
187
    /**
188
     * @return null|string
189
     */
190 4
    private function getMyCurrentJob() {
191 4
        $lookingFor = $this->getLookingFor();
192 4
        if (isset($lookingFor['experience']['job'])) {
193 3
            return $lookingFor['experience']['job'];
194 2
        } elseif (isset($lookingFor['experience'])) {
195 1
            return $lookingFor['experience'];
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $lookingFor['experience']; (array) is incompatible with the return type documented by FabienCrassat\Curriculum...mVitae::getMyCurrentJob of type null|string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
196
        }
197
198 1
        return NULL;
199
    }
200
201
    /**
202
     * @return \SimpleXMLElement
203
     */
204 29
    private function getXmlCurriculumVitae() {
205 29
        if (is_null($this->pathToFile) || !is_file($this->pathToFile)) {
206 1
            throw new InvalidArgumentException('The path ' . $this->pathToFile . ' is not a valid path to file.');
207
        }
208 28
        $this->isValidXmlCurriculumVitae();
209
210 26
        return simplexml_load_file($this->pathToFile);
211
    }
212
213
    /**
214
     * @return boolean
215
     */
216 28
    private function isValidXmlCurriculumVitae() {
217
        // Active "user error handling"
218 28
        libxml_use_internal_errors(TRUE);
219
220
        // Instanciate of a DOMDocument
221 28
        $dom = new \DOMDocument('1.0');
222
223
        // Load the XML from the file
224 28
        $dom->load($this->pathToFile);
225
226
        // Validation duof the XML document
227 28
        $reflClass = new \ReflectionClass(get_class($this));
228 28
        $xsdFile   = dirname($reflClass->getFileName()).'/validator.xsd';
229 28
        $validate  = $dom->schemaValidate($xsdFile);
230 28
        if (!$validate) {
231 2
            $libxmlDisplayErrors = new LibXmlDisplayErrors;
232 2
            throw new InvalidArgumentException($libxmlDisplayErrors->libXmlDisplayErrors());
233
        }
234
235 26
        return $validate;
236
    }
237
238
    /**
239
     * @return array|null
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use null|array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
240
     */
241 25
    private function getXMLValue() {
242 25
        if (!$this->interface) return NULL;
243
244 23
        return $this->xml2arrayFunctions->xml2array($this->interface);
245
    }
246
}
247