public function toArray(Model $model)
    {
        // start with the base representation of the model
        if (method_exists($model, 'withoutArrayHook')) {
            $model->withoutArrayHook();
        }
        $result = $model->toArray();

        // apply namespacing to excluded properties
        $namedExc = [];
        foreach ($this->exclude as $k) {
            array_set($namedExc, $k, true);
        }

        // apply namespacing to included properties
        $namedInc = [];
        foreach ($this->include as $k) {
            array_set($namedInc, $k, true);
        }

        // apply namespacing to expanded properties
        $namedExp = [];
        foreach ($this->expand as $k) {
            array_set($namedExp, $k, true);
        }

        // remove excluded properties
        foreach (array_keys($result) as $k) {
            if (isset($namedExc[$k]) && !is_array($namedExc[$k])) {
                unset($result[$k]);
            }
        }

        // add included properties
        foreach (array_keys($namedInc) as $k) {
            if (!isset($result[$k]) && isset($namedInc[$k])) {
                $result[$k] = $model->$k;
                if ($result[$k] instanceof Model) {
                    $subExc = array_value($namedExc, $k);
                    $subInc = array_value($namedInc, $k);
                    $subExp = array_value($namedExp, $k);

                    // convert exclude, include, and expand into dot notation
                    // then take the keys for a flattened dot notation
                    $flatExc = is_array($subExc) ? array_keys(array_dot($subExc)) : [];
                    $flatInc = is_array($subInc) ? array_keys(array_dot($subInc)) : [];
                    $flatExp = is_array($subExp) ? array_keys(array_dot($subExp)) : [];

                    $serializer = new self($this->request);
                    $serializer->setExclude($flatExc)
                        ->setInclude($flatInc)
                        ->setExpand($flatExp);

                    $result[$k] = $serializer->toArray($result[$k]);
                }
            }
        }

        // expand any relational model properties
        $result = $this->expand($model, $result, $namedExc, $namedInc, $namedExp);

        // apply hooks, if available
        if (method_exists($model, 'toArrayHook')) {
            $model->toArrayHook($result, $namedExc, $namedInc, $namedExp);
        }

        // order the properties array by name for consistency
        // since it is constructed in a random order
        ksort($result);

        return $result;
    }