public function validate($failOn = Validator\Rule::ERROR)
    {
        $this->warnings = [];
        $this->errors = [];

        foreach ($this->rules as $rule) {

            if ($rule instanceof Validator\Condition) {
                // Condition

                $condition = $rule;
                if ($condition->validate()) {
                    // Conditions rules

                    if (!$condition->getValidator()->validate($failOn)) {

                        $this->errors = array_merge(
                            $this->errors,
                            $rule->getValidator()->getErrors()
                        );
                    }
                    $this->warnings = array_merge(
                        $this->warnings,
                        $rule->getValidator()->getWarnings()
                    );
                }
            } else {
                // Rule

                if (!$rule->validate()) {

                    if ($rule->getSeverity() <= $failOn) {
                        $this->errors[] = $rule;
                    } else {
                        $this->warnings[] = $rule;
                    }
                }
            }
        }

        // Run nested validators - every entity may have its own validator
        foreach ($this->entity->getData() as $propertyName => $value) {

            if ($value instanceof Entity) {

                $validator = $value->getValidator();

                if (!$validator->validate($failOn)) {

                    foreach ($validator->getErrors() as $error) {

                        $rule = clone $error;
                        $rule->setPath(
                            array_merge([$propertyName], $rule->getPath())
                        );
                        $this->errors[] = $rule;
                    }
                }

                foreach ($validator->getWarnings() as $warning) {

                    $rule = clone $warning;
                    $rule->setPath(
                        array_merge([$propertyName], $rule->getPath())
                    );
                    $this->warnings[] = $rule;
                }
            }
        }

        return count($this->errors) === 0;
    }