public function obj($fieldName, $arguments = [], $cache = false, $cacheName = null)
    {
        if (!$cacheName && $cache) {
            $cacheName = $this->objCacheName($fieldName, $arguments);
        }

        // Check pre-cached value
        $value = $cache ? $this->objCacheGet($cacheName) : null;
        if ($value !== null) {
            return $value;
        }

        // Load value from record
        if ($this->hasMethod($fieldName)) {
            $value = call_user_func_array(array($this, $fieldName), $arguments ?: []);
        } else {
            $value = $this->$fieldName;
        }

        // Cast object
        if (!is_object($value)) {
            // Force cast
            $castingHelper = $this->castingHelper($fieldName);
            $valueObject = Injector::inst()->create($castingHelper, $fieldName);
            $valueObject->setValue($value, $this);
            $value = $valueObject;
        }

        // Record in cache
        if ($cache) {
            $this->objCacheSet($cacheName, $value);
        }

        return $value;
    }