Completed
Push — master ( 2b5327...235414 )
by Peter
09:57
created

IndexModel::apply()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 50
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 8.6315
c 0
b 0
f 0
cc 6
eloc 27
nc 6
nop 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: peter
5
 * Date: 17.12.17
6
 * Time: 15:13
7
 */
8
9
namespace Maslosoft\Mangan\Helpers\Index;
10
11
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
12
use Maslosoft\Mangan\Command;
13
use Maslosoft\Mangan\Criteria\ConditionDecorator;
14
use Maslosoft\Mangan\Interfaces\InternationalInterface;
15
use Maslosoft\Mangan\Mangan;
16
use Maslosoft\Mangan\Meta\IndexMeta;
17
18
class IndexModel
19
{
20
	private $model = null;
21
22
	/**
23
	 * @var IndexMeta
24
	 */
25
	private $meta = null;
26
27
	private $indexes = [];
28
29
	public function __construct(AnnotatedInterface $model, IndexMeta $meta)
30
	{
31
		$this->model = $model;
32
		$this->meta = $meta;
33
	}
34
35
	public function apply()
36
	{
37
		$mn = Mangan::fromModel($this->model);
38
		$cd = new ConditionDecorator($this->model);
39
40
		$decorated = [];
41
		foreach ($this->meta->keys as $name => $sort)
42
		{
43
			if ($this->model instanceof InternationalInterface)
44
			{
45
				foreach ($this->model->getLanguages() as $code)
46
				{
47
					assert(!empty($code));
48
49
					// Reset cloned model languages to get only one
50
					// language that is currently selected. So that
51
					// decorated field name will have proper code.
52
					$cd->getModel()->setLang($code, false);
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Maslosoft\Addendum\Interfaces\AnnotatedInterface as the method setLang() does only exist in the following implementations of said interface: Maslosoft\Mangan\Document, Maslosoft\Mangan\EmbeddedDocument, Maslosoft\Mangan\Example\ExampleAddress, Maslosoft\Mangan\Example\ExampleUser, Maslosoft\Mangan\Model\File, Maslosoft\Mangan\Model\Image, Maslosoft\Mangan\Model\Trash, Maslosoft\Mangan\Model\TrashItem.

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...
53
					$cd->getModel()->setLanguages([$code], false);
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Maslosoft\Addendum\Interfaces\AnnotatedInterface as the method setLanguages() does only exist in the following implementations of said interface: Maslosoft\Mangan\Document, Maslosoft\Mangan\EmbeddedDocument, Maslosoft\Mangan\Example\ExampleAddress, Maslosoft\Mangan\Example\ExampleUser, Maslosoft\Mangan\Model\File, Maslosoft\Mangan\Model\Image, Maslosoft\Mangan\Model\Trash, Maslosoft\Mangan\Model\TrashItem.

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...
54
55
					$field = $cd->decorate($name);
56
					$key = key($field);
57
					$decorationKey = $code . '@' . $sort;
58
					if(empty($decorated[$decorationKey]))
59
					{
60
						$decorated[$decorationKey] = [];
61
					}
62
					$decorated[$decorationKey][$key] = $sort;
63
				}
64
			}
65
			else
66
			{
67
				$field = $cd->decorate($name);
68
				$key = key($field);
69
				$decorated[$key . '@' . $sort] = [$key => $sort];
70
			}
71
		}
72
		$cmd = new Command($this->model, $mn);
73
74
		$results = [];
75
76
		// Remove possible duplicated entries
77
		$unique = array_unique($decorated, SORT_REGULAR);
78
		$this->indexes = $unique;
79
		foreach ($unique as $keys)
80
		{
81
			$results[] = (int)$cmd->createIndex($keys, $this->meta->options);
82
		}
83
		return array_sum($results) === count($results);
84
	}
85
86
	public function getIndexes()
87
	{
88
		return $this->indexes;
89
	}
90
}