Skip to content

Commit

Permalink
updates
Browse files Browse the repository at this point in the history
  • Loading branch information
arietimmerman committed Jul 2, 2024
1 parent caf39ab commit 284bf99
Show file tree
Hide file tree
Showing 11 changed files with 542 additions and 263 deletions.
161 changes: 22 additions & 139 deletions src/Attribute/Attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
namespace ArieTimmerman\Laravel\SCIMServer\Attribute;

use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
use ArieTimmerman\Laravel\SCIMServer\Parser\Path;
use ArieTimmerman\Laravel\SCIMServer\SCIM\Schema;
use Illuminate\Database\Eloquent\Model;
use Tmilos\ScimFilterParser\Ast\AttributePath;
use Tmilos\ScimFilterParser\Ast\ComparisonExpression;
use Tmilos\ScimSchema\Model\Resource;

class Attribute
{
Expand All @@ -32,23 +35,16 @@ class Attribute
public $filter;
public $sortAttribute;

/**
* @var Attribute[]
*/
public $subAttributes = [];
public $dirty = false;



public function __construct($name = null, $schemaNode = false)
{
$this->name = $name;
$this->schemaNode = $schemaNode;
}

public function getSubNode($key)
{
return collect($this->subAttributes)->first(function ($element) use ($key) {
return $element->name == $key;
});
}

public function ensure(...$validations)
{
Expand Down Expand Up @@ -82,102 +78,15 @@ public function shouldReturn(&$object)
return true;
}

public function eloquent(string $attribute = null)
{
if ($attribute == null) {
$attribute = $this->name;
}

$this->eloquentAttributes = [$attribute];

$this->setRead(function ($object) use ($attribute) {

$value = $object->{$attribute};

if ($value instanceof \Carbon\Carbon) {
$value = $value->format('c');
}

return $value;
})->setAdd(
function ($value, &$object) use ($attribute) {
$object->{$attribute} = $value;
}
)->setReplace(
function ($value, &$object) use ($attribute) {
$object->{$attribute} = $value;
}
)->setSortAttribute($attribute);

return $this;
}

public function constant($text)
{
return $this->disableWrite()->setRead(
function (&$object) use ($text) {
return $text;
}
);
}

public function setParent($parent)
{
$this->parent = $parent;
return $this;
}

public function object(...$attributes)
{
$this->subAttributes = $attributes;

foreach ($attributes as $attribute) {
$attribute->setParent($this);
}

$this->setRead(function (&$object) {
$result = [];
foreach ($this->subAttributes as $attribute) {
$result[$attribute->name] = $attribute->read($object);
}
return $result;
});

return $this;
}

public function collection(...$attributes)
{
$this->subAttributes = $attributes;

foreach ($attributes as $attribute) {
$attribute->setParent($this);
}

$this->setRead(function (&$object) {
$result = [];
foreach ($this->subAttributes as $attribute) {
$result[] = $attribute->read($object);
}
return $result;
});

return $this;
}

public function read(&$object)
{
if ($this->read) {
return ($this->read)($object);
} else {
throw new SCIMException(sprintf('Read is not implemented for "%s"', $this->getFullKey()));
};
}

public function setRead($read)
{
$this->read = $read;
return $this;
throw new SCIMException(sprintf('Read is not implemented for "%s"', $this->getFullKey()));
}

public function disableWrite(): Attribute
Expand Down Expand Up @@ -221,7 +130,7 @@ public function setRelationship($relationship)

public function getFullKey()
{
if ($this->parent != null) {
if ($this->parent != null && $this->parent->name != null) {
$seperator = $this->parent->schemaNode ? ':' : '.';
return $this->parent->getFullKey() . $seperator . $this->name;
} else {
Expand All @@ -244,15 +153,14 @@ public function getSchema()
}
}

// TODO: only invoked on the highest level???
public function getNode(?AttributePath $attributePath)
{
if (empty($attributePath)) {
return $this;
}

//The first schema should be the default one
$schema = $attributePath->schema ?? $this->getDefaultSchema()[0];
$schema = $attributePath->schema ?? $this->getDefaultSchema();

if (!empty($schema) && !empty($this->getSchema()) && $this->getSchema() != $schema) {
throw (new SCIMException(sprintf('Trying to get attribute for schema "%s". But schema is already "%s"', $attributePath->schema, $this->getSchema())))->setCode(500)->setScimType('noTarget');
Expand Down Expand Up @@ -403,54 +311,24 @@ function ($query) use ($attribute, $operator, $value) {
}
}

public function writeAfterIgnore($value, &$object)
public function add($value, Model &$object)
{
new SCIMException(sprintf('Write is not implemented for "%s"', $this->getFullKey()));
}

public function add($value, &$object)
public function replace($value, Model &$object, Path $path = null)
{
return $this->add ? ($this->add)($value, $object) : new SCIMException(sprintf('Write is not implemented for "%s"', $this->getFullKey()));
throw new SCIMException(sprintf('Replace is not implemented for "%s"', $this->getFullKey()));
}

public function replace($value, &$object)
public function patch($operation, $value, Model &$object, Path $path = null)
{
$current = $this->read($object);

//TODO: Really implement replace ...???
return $this->replace ? ($this->replace)($value, $object) : throw new SCIMException(sprintf('Replace is not implemented for "%s"', $this->getFullKey()));
throw new SCIMException(sprintf('Patch is not implemented for "%s"', $this->getFullKey()));
}

public function remove($value, &$object)
public function remove($value, Model &$object, string $path = null)
{

//TODO: implement remove for multi valued attributes
return $this->remove ? ($this->remove)($value, $object) : null;
}

public function writeAfter($value, &$object)
{
return $this->writeAfter ? ($this->writeAfter)($value, $object) : $this->writeAfterIgnore($value, $object);
}

public function setAdd($write)
{
$this->add = $write;

return $this;
}

public function setRemove($write)
{
$this->remove = $write;

return $this;
}

public function setReplace($replace)
{
$this->replace = $replace;

return $this;
throw new SCIMException(sprintf('Remove is not implemented for "%s"', $this->getFullKey()));
}

public function setSortAttribute($attribute)
Expand All @@ -468,4 +346,9 @@ public function getSortAttribute()

return $this->sortAttribute;
}

public function isDirty()
{
return $this->dirty;
}
}
147 changes: 147 additions & 0 deletions src/Attribute/Complex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php

namespace ArieTimmerman\Laravel\SCIMServer\Attribute;

use ArieTimmerman\Laravel\SCIMServer\Exceptions\SCIMException;
use ArieTimmerman\Laravel\SCIMServer\Parser\Path;
use Illuminate\Database\Eloquent\Model;

class Complex extends Attribute
{
/**
* @var Attribute[]
*/
public $subAttributes = [];

public function getSubNode(string $key): ?Attribute
{
return collect($this->subAttributes)->first(fn ($element) => $element->name == $key);
}

public function getSchemaNode(): ?Attribute
{
if ($this->parent != null) {
return null;
}

return collect($this->subAttributes)->first(fn ($element) => $element->schemaNode);
}

public function withSubAttributes(...$subAttributes)
{
foreach ($subAttributes as $attribute) {
$attribute->setParent($this);
}

$this->subAttributes = $subAttributes;

return $this;
}

public function read(&$object)
{
$result = [];
foreach ($this->subAttributes as $attribute) {
$result[$attribute->name] = $attribute->read($object);
}
return $result;
}

public function patch($operation, $value, Model &$object, Path $path = null, $removeIfNotSet = false)
{
if ($path != null && $path->isNotEmpty()) {
$attributeNames = $path->getValuePathAttributes();

if (!empty($attributeNames)) {
// TODO: search for schema node
$attribute = $this->getSubNode($attributeNames[0]);
if ($attribute != null) {
$attribute->patch($operation, $value, $object, $path->shiftValuePathAttributes());
} elseif ($this->parent == null) {
// pass the unchanged path object to the schema node
$this->getSchemaNode()->patch($operation, $value, $object, $path);
} else {
throw new SCIMException('Unknown path: ' . (string)$path . ", in object: " . $this->getFullKey());
}
} elseif ($path->getValuePathFilter() != null) {
// apply filtering here, for each match, call replace with updated path
throw new \Exception('Filtering not implemented for this complex attribute');
} elseif ($path->getAttributePath() != null) {
$attributeNames = $path?->getAttributePath()?->getAttributeNames() ?? [];

if (!empty($attributeNames)) {
$attribute = $this->getSubNode($attributeNames[0]);
if ($attribute != null) {
$attribute->patch($operation, $value, $object, $path->shiftAttributePathAttributes());
} elseif ($this->parent == null) {
// this is the root node, check within the first (the default) schema node
// pass the unchanged path object
$this->getSchemaNode()->patch($operation, $value, $object, $path);
} else {
throw new SCIMException('Unknown path: ' . (string)$path . ", in object: " . $this->getFullKey());
}
}
}
} else {
// if there is no path, keys of value are attribute names
switch($operation) {
case 'replace':
$this->replace($value, $object, $path, false);
break;
case 'add':
$this->add($value, $object, $path);
break;
case 'remove':
$this->remove($value, $object, $path);
break;
default:
throw new SCIMException('Unknown operation: ' . $operation);
}
}
}

/*
* @param $value
* @param Model $object
*/
public function replace($value, Model &$object, Path $path = null, $removeIfNotSet = false)
{
$match = false;

// if there is no path, keys of value are attribute names
foreach ($value as $key => $v) {
if (is_numeric($key)) {
throw new SCIMException('Invalid key: ' . $key . ' for complex object ' . $this->getFullKey());
}

$attribute = $this->getSubNode($key);
if ($attribute != null) {
$attribute->replace($v, $object, $path);
$match = true;
}
}

// if this is the root, we may also check the schema nodes
if (!$match && $this->parent == null) {
foreach ($this->subAttributes as $attribute) {
if ($attribute->schemaNode) {
$attribute->replace($value, $object, $path);
}
}
}

if ($removeIfNotSet) {
foreach ($this->subAttributes as $attribute) {
if (!$attribute->isDirty()) {
$attribute->remove(null, $object);
}
}
}
}


public function remove($value, Model &$object, string $path = null)
{
// TODO: implement
}
}
Loading

0 comments on commit 284bf99

Please sign in to comment.