Completed
Push — milestone/2.0 ( 8a1186...26a446 )
by
unknown
04:33
created

Term_Meta_Container::_is_valid_attach()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 8
Code Lines 5

Duplication

Lines 8
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 5
c 1
b 0
f 0
nc 4
nop 0
dl 8
loc 8
rs 9.2
1
<?php
2
3
namespace Carbon_Fields\Container;
4
5
use Carbon_Fields\Datastore\Datastore;
6
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
7
8
/**
9
 * Term meta container class.
10
 */
11
class Term_Meta_Container extends Container {
12
	protected $term_id;
13
14
	public $settings = array(
15
		'taxonomy' => array( 'category' ),
16
		'show_on_level' => false,
17
	);
18
19
	/**
20
	 * Create a new container
21
	 *
22
	 * @param string $unique_id Unique id of the container
23
	 * @param string $title title of the container
24
	 * @param string $type Type of the container
25
	 **/
26 View Code Duplication
	public function __construct( $unique_id, $title, $type ) {
27
		parent::__construct( $unique_id, $title, $type );
28
29
		if ( ! $this->get_datastore() ) {
30
			$this->set_datastore( Datastore::make( 'term_meta' ), $this->has_default_datastore() );
31
		}
32
	}
33
34
	/**
35
	 * Bind attach() and save() to the appropriate WordPress actions.
36
	 **/
37
	public function init() {
38
		// force taxonomy to be array
39
		if ( ! is_array( $this->settings['taxonomy'] ) ) {
40
			$this->settings['taxonomy'] = array( $this->settings['taxonomy'] );
41
		}
42
43
		add_action( 'admin_init', array( $this, '_attach' ) );
44
45
		foreach ( $this->settings['taxonomy'] as $taxonomy ) {
46
			add_action( 'edited_' . $taxonomy, array( $this, '_save' ), 10, 2 );
47
			add_action( 'created_' . $taxonomy, array( $this, '_save' ), 10, 2 );
48
		}
49
	}
50
51
	/**
52
	 * Perform checks whether the current save() request is valid.
53
	 *
54
	 * @param int $term_id ID of the term against which save() is ran
55
	 * @return bool
56
	 **/
57
	public function is_valid_save( $term_id = null ) {
58
		if ( ! $this->verified_nonce_in_request() ) {
59
			return false;
60
		}
61
62
		return $this->is_valid_attach_for_object( $term_id );
63
	}
64
65
	/**
66
	 * Perform save operation after successful is_valid_save() check.
67
	 * The call is propagated to all fields in the container.
68
	 *
69
	 * @param int $term_id ID of the term against which save() is ran
70
	 **/
71
	public function save( $term_id ) {
72
		$this->set_term_id( $term_id );
73
74
		foreach ( $this->fields as $field ) {
75
			$field->set_value_from_input();
76
			$field->save();
77
		}
78
79
		do_action( 'carbon_after_save_term_meta', $term_id );
80
	}
81
82
	/**
83
	 * Perform checks whether the container should be attached during the current request
84
	 *
85
	 * @return bool True if the container is allowed to be attached
86
	 **/
87 View Code Duplication
	public function is_valid_attach_for_request() {
1 ignored issue
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...
88
		$request_taxonomy = isset( $_GET['taxonomy'] ) ? $_GET['taxonomy'] : '';
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
89
		if ( ! empty( $request_taxonomy ) && in_array( $request_taxonomy, $this->settings['taxonomy'] ) ) {
90
			return true;
91
		}
92
93
		return false;
94
	}
95
96
	/**
97
	 * Check container attachment rules against object id
98
	 *
99
	 * @return bool
100
	 **/
101
	public function is_valid_attach_for_object( $object_id = null ) {
102
		return ( $object_id > 0 );
103
	}
104
105
	/**
106
	 * Add term meta for each of the container taxonomies
107
	 **/
108
	public function attach() {
109
		foreach ( $this->settings['taxonomy'] as $taxonomy ) {
110
			add_action( $taxonomy . '_edit_form_fields', array( $this, 'render' ), 10, 2 );
111
			add_action( $taxonomy . '_add_form_fields', array( $this, 'render' ), 10, 2 );
112
		}
113
	}
114
115
	/**
116
	 * Output the container markup
117
	 **/
118
	public function render( $term = null ) {
119
		if ( is_object( $term ) ) {
120
			$this->set_term_id( $term->term_id );
121
		}
122
123
		include \Carbon_Fields\DIR . '/templates/Container/term_meta.php';
124
	}
125
126
	/**
127
	 * Set the term ID the container will operate with.
128
	 *
129
	 * @param int $term_id
130
	 **/
131
	public function set_term_id( $term_id ) {
132
		$this->term_id = $term_id;
133
		$this->get_datastore()->set_id( $term_id );
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Carbon_Fields\Datastore\Datastore_Interface as the method set_id() does only exist in the following implementations of said interface: Carbon_Fields\Datastore\Comment_Meta_Datastore, Carbon_Fields\Datastore\Meta_Datastore, Carbon_Fields\Datastore\Nav_Menu_Item_Datastore, Carbon_Fields\Datastore\Post_Meta_Datastore, Carbon_Fields\Datastore\Term_Meta_Datastore, Carbon_Fields\Datastore\User_Meta_Datastore.

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...
134
	}
135
136
	/**
137
	 * COMMON USAGE METHODS
138
	 */
139
140
	/**
141
	 * Show the container only on terms from the specified taxonomies.
142
	 *
143
	 * @param string|array $taxonomies
144
	 * @return object $this
145
	 **/
146
	public function show_on_taxonomy( $taxonomies ) {
147
		$taxonomies = (array) $taxonomies;
148
149
		$this->settings['taxonomy'] = $taxonomies;
150
151
		return $this;
152
	}
153
154
	/**
155
	 * Show the container only on particular term level.
156
	 *
157
	 * @param int $term_level
158
	 * @return object $this
159
	 */
160
	public function show_on_level( $term_level ) {
161
		$this->settings['show_on_level'] = $term_level;
162
		return $this;
163
	}
164
}
165