Completed
Push — master ( 2f347b...82694e )
by Haralan
12s
created

builder_paranoid_filter()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 11
cts 11
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 12
nc 8
nop 1
crap 5
1
<?php
2
3
/**
4
 * Implementation of the paranoid behavior, so when you delete soemthing it does not dissapear but is set with a flag is_deleted
5
 *
6
 * @package    Jam
7
 * @category   Behavior
8
 * @author     Ivan Kerin
9
 * @copyright  (c) 2011-2012 Despark Ltd.
10
 * @license    http://www.opensource.org/licenses/isc-license.txt
11
 */
12
class Kohana_Jam_Behavior_Paranoid extends Jam_Behavior
13
{
14
	protected static $_default_filter = 'normal';
15
16 29
	public static function filter($filter = NULL)
17
	{
18 29
		if ($filter !== NULL)
19
		{
20 4
			Jam_Behavior_Paranoid::$_default_filter = $filter;
0 ignored issues
show
Bug introduced by
The property _default_filter cannot be accessed from this context as it is declared protected in class Kohana_Jam_Behavior_Paranoid.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
21
		}
22
23 29
		return Jam_Behavior_Paranoid::$_default_filter;
0 ignored issues
show
Bug introduced by
The property _default_filter cannot be accessed from this context as it is declared protected in class Kohana_Jam_Behavior_Paranoid.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
24
	}
25
26 1
	public static function with_filter($filter, $closure)
27
	{
28 1
		$current_filter = static::filter();
29 1
		static::filter($filter);
30
31 1
		$result = call_user_func($closure);
32
33 1
		static::filter($current_filter);
34 1
		return $result;
35
	}
36
37
	const ALL = 'all';
38
	const DELETED = 'deleted';
39
	const NORMAL = 'normal';
40
41
	/**
42
	 * The field used for checking if an item is deleated
43
	 *
44
	 * @var string
45
	 */
46
	protected $_field = 'is_deleted';
47
48
	public function initialize(Jam_Meta $meta, $name)
49
	{
50
		parent::initialize($meta, $name);
51
52
		$meta
53
			->field($this->_field, Jam::field('boolean', array('default' => FALSE)));
54
55
		$meta->events()
56
			->bind('builder.before_select', array($this, 'builder_paranoid_filter'))
57
			->bind('builder.before_update', array($this, 'builder_paranoid_filter'));
58
	}
59
60
	/**
61
	 * Perform the actual where modification when it is needed
62
	 *
63
	 * @param Jam_Query_Builder_Select    $builder
64
	 */
65 29
	public function builder_paranoid_filter(Database_Query $builder)
66
	{
67 29
		$filter_type = $builder->params('paranoid_filter_type') ?: Jam_Behavior_Paranoid::filter();
0 ignored issues
show
Bug introduced by
The method params() does not exist on Database_Query. Did you maybe mean param()?

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...
68
69
		switch ($filter_type)
70
		{
71 29
			case Jam_Behavior_Paranoid::ALL:
72 4
			break;
73
74 29
			case Jam_Behavior_Paranoid::DELETED:
75 4
				$builder->where($this->_field, '=', TRUE);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Database_Query as the method where() does only exist in the following sub-classes of Database_Query: Database_Query_Builder_Delete, Database_Query_Builder_Select, Database_Query_Builder_Update, Database_Query_Builder_Where, Jam_Query_Builder_Collection, Jam_Query_Builder_Delete, Jam_Query_Builder_Select, Jam_Query_Builder_Update, Kohana_Database_Query_Builder_Delete, Kohana_Database_Query_Builder_Select, Kohana_Database_Query_Builder_Update, Kohana_Database_Query_Builder_Where, Kohana_Jam_Query_Builder_Collection, Kohana_Jam_Query_Builder_Delete, Kohana_Jam_Query_Builder_Select, Kohana_Jam_Query_Builder_Update. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
76 4
			break;
77
78 29
			case Jam_Behavior_Paranoid::NORMAL:
79
			default:
80 29
				$builder->where($this->_field, '=', FALSE);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Database_Query as the method where() does only exist in the following sub-classes of Database_Query: Database_Query_Builder_Delete, Database_Query_Builder_Select, Database_Query_Builder_Update, Database_Query_Builder_Where, Jam_Query_Builder_Collection, Jam_Query_Builder_Delete, Jam_Query_Builder_Select, Jam_Query_Builder_Update, Kohana_Database_Query_Builder_Delete, Kohana_Database_Query_Builder_Select, Kohana_Database_Query_Builder_Update, Kohana_Database_Query_Builder_Where, Kohana_Jam_Query_Builder_Collection, Kohana_Jam_Query_Builder_Delete, Kohana_Jam_Query_Builder_Select, Kohana_Jam_Query_Builder_Update. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
81 29
			break;
82
		}
83 29
	}
84
85
	/**
86
	 * $builder->deleted(Jam_Behavior_Paranoid::ALL),
87
	 * $builder->deleted(Jam_Behavior_Paranoid::DELETED),
88
	 * $builder->deleted(Jam_Behavior_Paranoid::NORMAL)
89
	 *
90
	 * @param Jam_Builder    $builder
91
	 * @param Jam_Event_Data $data
92
	 * @param string         $paranoid_filter_type
93
	 */
94 4
	public function builder_call_deleted(Database_Query $builder, Jam_Event_Data $data, $paranoid_filter_type = Jam_Behavior_Paranoid::NORMAL)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
95
	{
96 4
		if ( ! in_array($paranoid_filter_type, array(Jam_Behavior_Paranoid::DELETED, Jam_Behavior_Paranoid::NORMAL, Jam_Behavior_Paranoid::ALL)))
97
			throw new Kohana_Exception("Deleted type should be Jam_Behavior_Paranoid::DELETED, Jam_Behavior_Paranoid::NORMAL or Jam_Behavior_Paranoid::ALL");
98
99 4
		$builder->params('paranoid_filter_type', $paranoid_filter_type);
0 ignored issues
show
Bug introduced by
The method params() does not exist on Database_Query. Did you maybe mean param()?

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...
100 4
	}
101
102
	/**
103
	 * $model->delete() Delete the item only if the "real delete" flag has been set to TRUE, otherwise set the 'is_deleted' column to TRUE
104
	 *
105
	 * @param Jam_Model      $model
106
	 * @param Jam_Event_Data $data
107
	 */
108 3
	public function model_before_delete(Jam_Model $model, Jam_Event_Data $data)
109
	{
110 3
		if ( ! $model->_real_delete)
0 ignored issues
show
Documentation introduced by
The property _real_delete does not exist on object<Jam_Model>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
111
		{
112 3
			Jam::update($this->_model)
113 3
				->where_key($model->id())
114 3
				->value($this->_field, TRUE)
115 3
				->execute();
116
117 3
			$data->return = FALSE;
118
		}
119 3
	}
120
121
	/**
122
	 * $model->real_delte() Set the flag 'real_delete' to true and perform the deletion
123
	 *
124
	 * @param Jam_Model      $model
125
	 * @param Jam_Event_Data $data
126
	 */
127 3
	public function model_call_real_delete(Jam_Model $model, Jam_Event_Data $data)
128
	{
129 3
		$model->_real_delete = TRUE;
0 ignored issues
show
Documentation introduced by
The property _real_delete does not exist on object<Jam_Model>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
130 3
		$data->stop = TRUE;
131 3
		$data->return = $model->delete();
132 3
	}
133
134
	/**
135
	 * $model->restore_delete() Perform this to "undelete" a model
136
	 *
137
	 * @param Jam_Model      $model
138
	 * @param Jam_Event_Data $data
0 ignored issues
show
Bug introduced by
There is no parameter named $data. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
139
	 */
140 3
	public function model_call_restore_delete(Jam_Model $model)
141
	{
142 3
		Jam::update($this->_model)
0 ignored issues
show
Documentation Bug introduced by
The method deleted does not exist on object<Jam_Query_Builder_Update>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
143 3
			->where_key($model->id())
144 3
			->deleted(Jam_Behavior_Paranoid::DELETED)
145 3
			->value($this->_field, FALSE)
146 3
			->execute();
147 3
	}
148
}
149