Completed
Push — develop ( 09456b...2094a2 )
by Mathias
14s queued 10s
created

JobContext::getCategories()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 1
1
<?php
2
/**
3
 * YAWIK
4
 *
5
 * @filesource
6
 * @license MIT
7
 * @copyright  2013 - 2017 Cross Solution <http://cross-solution.de>
8
 */
9
10
namespace Yawik\Behat;
11
12
use Auth\Entity\Status;
13
use Auth\Entity\User;
14
use Behat\Behat\Context\Context;
15
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
16
use Behat\Gherkin\Node\TableNode;
17
use Core\Entity\Permissions;
18
use Doctrine\Common\Util\Inflector;
19
use Documents\UserRepository;
20
use Geo\Service\Photon;
21
use Jobs\Entity\Classifications;
22
use Jobs\Entity\Job;
23
use Jobs\Entity\Location;
24
use Jobs\Entity\StatusInterface;
25
use Jobs\Repository\Categories as CategoriesRepo;
26
use Jobs\Repository\Job as JobRepository;
27
use Zend\Json\Json;
28
29
/**
30
 * Class JobContext
31
 *
32
 * @author Anthonius Munthi <[email protected]>
33
 * @package Yawik\Behat
34
 */
35
class JobContext implements Context
36
{
37
	use CommonContextTrait;
38
	
39
	/**
40
	 * @var Select2Context
41
	 */
42
	private $select2Context;
43
	
44
	/**
45
	 * @var Job
46
	 */
47
	private $currentJob;
48
	
49
	/**
50
	 * @var JobRepository
51
	 */
52
	static private $jobRepo;
53
	
54
	/**
55
	 * @param User $user
56
	 */
57
	static public function removeJobByUser(User $user)
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
58
	{
59
		$repo = static::$jobRepo;
0 ignored issues
show
Bug introduced by
Since $jobRepo is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $jobRepo to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
60
		$results = $repo->findBy(['user' => $user]);
61
		foreach($results as $result){
62
			$repo->remove($result,true);
63
		}
64
	}
65
	
66
	/**
67
	 * @BeforeScenario
68
	 *
69
	 * @param BeforeScenarioScope $scope
70
	 */
71
	public function beforeScenario(BeforeScenarioScope $scope)
72
	{
73
		$this->select2Context = $scope->getEnvironment()->getContext(Select2Context::class);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Testwork\Environment\Environment as the method getContext() does only exist in the following implementations of said interface: Behat\Behat\Context\Envi...lizedContextEnvironment, FriendsOfBehat\ContextSe...ntextServiceEnvironment.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
74
		if(is_null(static::$jobRepo)){
0 ignored issues
show
Bug introduced by
Since $jobRepo is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $jobRepo to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
75
			$this->gatherContexts($scope);
76
			static::$jobRepo = $this->getJobRepository();
0 ignored issues
show
Bug introduced by
Since $jobRepo is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $jobRepo to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
77
		}
78
	}
79
	
80
	/**
81
	 * @Given I go to job board page
82
	 */
83
	public function iGoToJobBoardPage()
84
	{
85
		$this->visit('/jobboard');
86
	}
87
	
88
	/**
89
	 * @Given I go to create job page
90
	 */
91
	public function iGoToCreateJob()
92
	{
93
	    $url = $this->buildUrl('lang/jobs/manage',['action' => 'edit']);
94
		$this->visit($url);
95
	}
96
	
97
	/**
98
	 * @Given I go to job overview page
99
	 */
100
	public function iGoToJobOverviewPage()
101
	{
102
		$this->visit('/jobs');
103
	}
104
	
105
	/**
106
	 * @Given I go to edit job draft with title :jobTitle
107
	 * @param $jobTitle
108
	 * @throws \Exception when job is not found
109
	 */
110
	public function iGoToEditJobWithTitle($jobTitle)
111
	{
112
		$job = $this->getJobRepository()->findOneBy(['title' => $jobTitle]);
113
		if(!$job instanceof Job){
114
			throw new \Exception(sprintf('Job with title "%s" is not found',$jobTitle));
115
		}
116
		$this->currentJob = $job;
117
		$url = $this->buildUrl('lang/jobs/manage',[
118
		    'id' => $job->getId()
119
        ]);
120
		$this->visit($url);
121
	}
122
	
123
	/**
124
	 * @Given I don't have any classification data
125
	 */
126
	public function iDonTHaveAnyClassificationData()
127
	{
128
		$this->currentJob->setClassifications(new Classifications());
129
		$this->getJobRepository()->store($this->currentJob);
130
	}
131
	
132
	/**
133
	 * @When I don't have any posted job
134
	 */
135
	public function iDonTHaveAnyPostedJob()
136
	{
137
		/* @var $jobRepository JobRepository */
138
		/* @var $job Job */
139
		$user = $this->getUserContext()->getCurrentUser();
140
141
		$jobRepository = $this->getJobRepository();
142
		$results = $jobRepository->getUserJobs($user->getId());
143
		foreach($results as $job){
144
			$jobRepository->remove($job,true);
145
		}
146
		$this->currentJob = null;
147
	}
148
	
149
	/**
150
	 * @When I fill job location search with :search and choose :choice
151
	 *
152
	 */
153
	public function iFillJobLocationAndChoose($search,$choice)
154
	{
155
		$select2 = $this->select2Context;
156
		$select2->iFillInSelect2FieldWith('jobBase[geoLocation]',$search,$choice);
157
	}
158
	
159
	/**
160
	 * @When I choose :value from :field
161
	 */
162
	public function iJobClassificationSelect($value,$field)
163
	{
164
		$field = Inflector::camelize($field);
165
		
166
		$mapSelect2 = [
167
			'professions' => '#classifications-professions-span .select2-container',
168
			'industries'  => '#classifications-industries-span .select2-container',
169
			'employmentTypes' => '#classifications-employmentTypes-span .select2-container',
170
		];
171
		
172
		$mapMultiple = [
173
			'professions'       => "select#classifications-professions",
174
			'industries'        => "select#classifications-industries",
175
			'employmentTypes'    => "select#classifications-employmentTypes",
176
		];
177
		
178
		if(!isset($mapSelect2[$field])){
179
			throw new \Exception('Undefined field selection value "'.$field.'"');
180
		}
181
		
182
		$multipleField = $mapMultiple[$field];
183
		$page = $this->minkContext->getSession()->getPage();
184
		$element = $page->find('css',$mapMultiple[$field]);
185
		if(!is_null($element) && $element->getAttribute('multiple')=='multiple'){
186
			$this->minkContext->selectOption($value,$multipleField);
187
		}else{
188
			$locator = $mapSelect2[$field];
189
			$this->select2Context->iFillInSelect2Field($locator,$value);
190
		}
191
	}
192
	
193
	/**
194
	 * @return JobRepository
195
	 */
196
	public function getJobRepository()
197
	{
198
		return $this->getRepository('Jobs/Job');
199
	}
200
	
201
	/**
202
	 * @return CategoriesRepo
203
	 */
204
	public function getCategoriesRepository()
205
	{
206
		return $this->getRepository('Jobs/Category');
207
	}
208
	
209
	/**
210
	 * @When I have a :status job with the following:
211
	 * @param TableNode $fields
212
	 */
213
	public function iHaveAJobWithTheFollowing($status,TableNode $fields)
214
	{
215
		$this->buildJob($status,$fields->getRowsHash());
216
	}
217
218
	public function buildJob($status, $definitions,$organization = null)
219
    {
220
        $normalizedField = [
221
            'template' => 'modern',
222
        ];
223
        foreach($definitions as $field => $value){
224
            $field = Inflector::camelize($field);
225
            if($field == 'professions' || $field == 'industries'){
226
                $value = explode(',',$value);
227
            }
228
            $normalizedField[$field] = $value;
229
        }
230
231
        $jobRepo = $this->getJobRepository();
232
        $job = $jobRepo->findOneBy([
233
            'title' => $normalizedField['title']
234
        ]);
235
        if(!$job instanceof Job){
236
            $job = new Job();
237
            $job->setTitle($normalizedField['title']);
238
        }
239
240
        if(isset($normalizedField['user'])){
241
            /* @var $userRepo UserRepository */
242
            $userRepo = $this->getRepository('Auth\Entity\User');
243
            $user = $userRepo->findOneBy(['login' => $normalizedField['user']]);
244
            if(is_null($organization)){
245
                $organization = $user->getOrganization()->getOrganization();
246
            }
247
            if($user instanceof User){
248
                $job->setUser($user);
249
                $job->setOrganization($organization);
250
            }else{
251
                throw new \Exception('There is no user with this login:"'.$normalizedField['user'.'"']);
252
            }
253
        }
254
255
        if($status == 'draft'){
256
            $job->setIsDraft(true);
257
        }elseif($status == 'published'){
258
            $job->setIsDraft(false);
259
            $job->setDatePublishStart(new \DateTime());
0 ignored issues
show
Documentation introduced by
new \DateTime() is of type object<DateTime>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
260
        }
261
        $job->setStatus(Status::ACTIVE);
262
263
        if(isset($normalizedField['location'])){
264
            $this->setLocation($job,$normalizedField['location']);
265
        }
266
        if(isset($normalizedField['professions'])){
267
            $this->addProfessions($job,$normalizedField['professions']);
268
        }
269
270
        if(isset($normalizedField['industries'])){
271
            $this->addIndustries($job,$normalizedField['industries']);
272
        }
273
        if(isset($normalizedField['employmentTypes'])){
274
            $types = $this->getCategories([$normalizedField['employmentTypes']]);
275
            $type = array_shift($types);
276
            $values = $job->getClassifications()->getEmploymentTypes()->getValues();
277
            if(!is_array($values) || !in_array($type,$values)){
278
                $job->getClassifications()->getEmploymentTypes()->getItems()->add($type);
279
            }
280
        }
281
282
        $jobRepo->store($job);
283
        $this->currentJob = $job;
284
    }
285
286
	
287
	private function setLocation(Job $job, $term)
288
	{
289
		/* @var $client Photon */
290
		$client = $this->coreContext->getServiceManager()->get('Geo/Client');
291
		$result = $client->queryOne($term);
292
		$location = new Location();
293
		$serialized = Json::encode($result);
294
		$location->fromString($serialized);
295
		
296
		$locations = $job->getLocations();
297
		if(count($locations)){
298
			$locations->clear();
299
		}
300
		$job->getLocations()->add($location);
301
	}
302
	
303 View Code Duplication
	private function addProfessions(Job &$job,$terms)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
304
	{
305
		$professions = $this->getCategories($terms);
306
		foreach($professions as $profession){
307
			$values = $job->getClassifications()->getProfessions()->getValues();
308
			if(!is_array($values) || !in_array($profession,$values)){
309
				$job->getClassifications()->getProfessions()->getItems()->add($profession);
310
			}
311
		}
312
	}
313
	
314 View Code Duplication
	private function addIndustries(Job &$job, $terms)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
315
	{
316
		$industries = $this->getCategories($terms);
317
		foreach($industries as $industry){
318
			$values = $job->getClassifications()->getIndustries()->getValues();
319
			if(!is_array($values) || !in_array($industry,$values)){
320
				$job->getClassifications()->getIndustries()->getItems()->add($industry);
321
			}
322
		}
323
	}
324
	
325
	/**
326
	 * @param array $categories
327
	 *
328
	 * @return mixed
329
	 */
330
	private function getCategories(array $categories)
331
	{
332
		$catRepo = $this->getCategoriesRepository();
333
		
334
		// get a professions
335
		$qb = $catRepo->createQueryBuilder()
336
		              ->field('name')->in($categories)
337
		              ->getQuery()
338
		;
339
		$results = $qb->execute();
340
		return $results->toArray();
341
	}
342
	
343
	
344
	/**
345
	 * @return Job
346
	 */
347
	private function getCurrentUserJobDraft($jobTitle)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
348
	{
349
		$repo = $this->getJobRepository();
350
		$user = $this->getCurrentUser();
0 ignored issues
show
Bug introduced by
The method getCurrentUser() does not exist on Yawik\Behat\JobContext. Did you maybe mean getCurrentUserJobDraft()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
351
		
352
		$job = $repo->findDraft($user);
353
		
354
		if(is_null($job)){
355
			$job = new Job();
356
			$job
357
				->setUser($user)
358
				->setOrganization($user->getOrganization()->getOrganization())
359
				->setStatus(StatusInterface::CREATED)
360
			;
361
			$job->setIsDraft(true);
362
		}
363
		$job->setTitle($jobTitle);
364
		$repo->store($job);
365
		return $job;
366
	}
367
}
368