Jump to content

NotionCommotion

Members
  • Posts

    2,446
  • Joined

  • Last visited

  • Days Won

    10

Everything posted by NotionCommotion

  1. I am pretty sure I can guess your table names before I can guess your UUIDs. ULIDs are another option, and while I think they might be less likely to have conflicts than UUIDs (UUIDs have 1 in 1,000,000,000,000,000,000,000 odds of a duplicate), they provide other benefits.
  2. Really hoping to get my dilemma resolved as I have tried to multiple times and it just stays in limbo. I provided more access control detail per request even though my real question relates to how best to allow a single object to have reciprocating relationships to multiple other objects. I recognize that no one has any obligation to help, yet many of you have done so and most of what I know is thanks to you. If there just isn't a good answer, please also let me know that so I may stop searching. I am starting to think that ORMs or at least Doctrine too closely couple the DB schema to the object model, and if I wish to use one, I need to compromise on the database schema or other aspects. Thanks again
  3. I gave a little thought on why I have concerns about my proposed schema changes (Option 1). The problem is I have more concerns about the alternate approaches I could think of (Option 2 and Option 3). Option 1. Object that has/owns a property references that property instead of the other way around. Orphan PermissionPolicy records can exist if no Projects, Assets, etc reference it. Can't delete a Projects, Assets, etc, and cascade delete the PermissionPolicy record. Adds complexity to ensure that a given PermissionPolicy is referenced by only a single Project, Asset, etc. Can't switch from OneToOne to ManyToOne by simply removing the unique constraint. Project - Id (PK) - PermissionPolicyId (FK to PermissionPolicy.Id, UNIQUE) - Data Asset - Id (PK) - PermissionPolicyId (FK to PermissionPolicy.Id, UNIQUE) - Data PermissionPolicy - Id (PK) - RequiredPermissionData Member - PermissionPolicyId (PK, FK to PermissionPolicy.Id) - UserId (PK, FK to User.Id) - MemberPermissionData User - Id (PK) - GeneralUserPermissionData - OtherData Option 2. Unique tables for each entity. I don't care for the duplication. User will have individual collections for each type. Project - Id (PK) - Data Asset - Id (PK) - Data ProjectPermissionPolicy - Id (PK) - ProjectId (FK to Project.Id, CASCADE DELETE, UNIQUE) - RequiredPermissionData AssetPermissionPolicy - Id (PK) - AssetId (FK to Asset.Id, CASCADE DELETE, UNIQUE) - RequiredPermissionData ProjectMember - ProjectPermissionPolicyId (PK, FK to ProjectPermissionPolicy.Id, CASCADE DELETE) - UserId (PK, FK to User.Id) - MemberPermissionData AssetMember - AssetPermissionPolicyId (PK, FK to AssetPermissionPolicy.Id, CASCADE DELETE) - UserId (PK, FK to User.Id) - MemberPermissionData User - Id (PK) - GeneralUserPermissionData - OtherData Option 3. Extend every entity from AbstractBaseEntity. I have a few entities which do use inheritance (i.e. CommonToAllSpecification and CustomUserDefinedSpecification) and I will need to have CommonToAllSpecification joined even though there is no access policy for it. Later adding access control to an entity will require changing the primary keys. AbstractBaseEntity - Id (PK) Project extends AbstractBaseEntity - Id (PK) - Data Asset extends AbstractBaseEntity - Id (PK) - Data PermissionPolicy - Id (PK) - AbstractBaseEntityId (FK to AbstractBaseEntity.Id, CASCADE DELETE, UNIQUE) - RequiredPermissionData Member - PermissionPolicyId (PK, FK to PermissionPolicy.Id, CASCADE DELETE) - UserId (PK, FK to User.Id) - MemberPermissionData User - Id (PK) - GeneralUserPermissionData - OtherData
  4. I am not trying to be vague and the roller coaster example is very close. And while I appreciate your help regarding my approach to access policy, my desire is to determine how best to define the database schema and relate the entity objects. I have provided specific details below and hope that it doesn't distract from what I thought was a simple question regarding modelling using composition instead of inheritance. I have these entities (Project, Asset, Vendor) which have properties and some (Project, Asset, but not Vendor) also act as a container for documents. There are three types of users: AdminUser, InternalUser, and ExternalUser, and internal and external users will typically have different access policies. Admin users have the capability to create the parent entities and specify on a per-record basis the access policy for the parent entity and for the documents which they contain. The access policy for the parent entity determines ability to read and update with possible values ALL/NONE. The access policy for the documents is common to all documents contained in a given parent entity, determines ability to create, read, update, and delete with possible values ALL/OWNER/NONE where OWNER represents the logged on user being the user who created the document (note that create doesn't support OWNER). Both internal and external users may also join as a member to a given parent entity, and their permission policy maybe be modified for the given entity. An example Project is as follows, Asset will look the same, and Vendor will look the same except not have the document permission policies. { "id": "01GFJTS5W4DQGVRD6FT1P5SQNW", "name": "MyProject", "type": "project", "otherProperties": "bla", "internalUserAccessPolicy": { "read_parent": "ALL", "update_parent": "NONE", "create_documents": "ALL", "read_documents": "ALL", "update_documents": "OWNER", "delete_documents": "NONE" }, "externallUserAccessPolicy": { "read_parent": "NONE", "update_parent": "NONE", "create_documents": "NONE", "read_documents": "OWNER", "update_documents": "OWNER", "delete_documents": "NONE" }, "members": [{ "userId": "01GFJTSKMT2VVZF90X89D33S38", "UserPermissionPolicy": { "read_parent": "ALL", "update_parent": "NONE", "create_documents": "ALL", "read_documents": "ALL", "update_documents": "OWNER", "delete_documents": "OWNER" } }, { "userId": "01GFJV47D64FNBRM4YW1HGK49J", "UserPermissionPolicy": { "read_parent": "ALL", "update_parent": "NONE", "create_documents": "ALL", "read_documents": "OWNER", "update_documents": "OWNER", "delete_documents": "NONE" } } ], "documents": [{ "documentId": "01GFJVKAC2CT077865KX97TQVH", "name": "siteplan.pdf", "path": "https://example.com/documents/01GFJV9WV055RZDDYFA4W6MPJC", "owner": "01GFJTSKMT2VVZF90X89D33S38" }, { "documentId": "01GFJV9WV055RZDDYFA4W6MPJC", "name": "drawings.pdf", "path": "https://example.com/documents/01GFJVKAC2CT077865KX97TQVH", "owner": "01GFJTSKMT2VVZF90X89D33S38" } ] } The schema is currently as follows: AbstractResource - id (PK) - name - type - internalUserAccessPolicy (value object) - externallUserAccessPolicy (value object) - otherProperties Project extends AbstractResource - id (PK, one-to-one FK to AbstractResource.id) - otherProperties Asset extends AbstractResource - id (PK, one-to-one FK to AbstractResource.id) - otherProperties User - id (PK) - name Member - resourceId (PK, many-to-many FK to AbstractResource.id) - userId (PK, many-to-many FK to User.id) - userAccessPermission (value object) I am thinking of changing the schema to the following where Project and Asset will now have an AccessPolicy property: ResourceAccessPolicy - id (PK) - discriminator (ResourceAccessPolicy or DocumentAccessPolicy) - internalUserResourceAccessPolicy (value object) - externallUserResourcePolicy (value object) DocumentAccessPolicy extends ResourceAccessPolicy - id (PK, one-to-one FK to ResourceAccessPolicy.id) - internalUserDocumentAccessPolicy (value object) - externallUserDocumentPolicy (value object) Project - id (PK, one-to-one FK to DocumentAccessPolicy.id) - discriminatorCopy (FK to ResourceAccessPolicy.className in order to prevent multiple resources from being associated with the same ResourceAccessPolicy) - otherProperties Asset - id (PK, one-to-one FK to DocumentAccessPolicy.id) - discriminatorCopy (FK to ResourceAccessPolicy.className in order to prevent multiple resources from being associated with the same ResourceAccessPolicy) - otherProperties Vendor - id (PK, one-to-one FK to ResourceAccessPolicy.id) - discriminatorCopy (FK to ResourceAccessPolicy.className in order to prevent multiple resources from being associated with the same ResourceAccessPolicy) - otherProperties User - id (PK) - name Member - accessPolicyId (PK, FK to ResourceAccessPolicy.id) - userId (PK, FK to User.id) - userAccessPermission (value object) Maybe it is obvious that I should do it this way, but I've never done it this way and for unknown reasons, have concerns. While I will gladly accept any access policy specific critique, please also let me know whether there is anything fundamentally wrong with this schema approach and whether I should make any changes.
  5. I like the roller coaster analogy! Yep, the roller coaster access policy is as follows: Giant Dipper Ride with an adult: 36" tall or 6 years old Ride solo: 48" tall or 13 years old American Eagle Ride with an adult: 32" tall or 9 years old Ride solo: 38" tall or 15 years old The Fury Ride with an adult: 38" tall or 5 years old Ride solo: 42" tall or 16 years old And, not just roller coasters, but similar requirements are used for ferris wheels, haunted houses, bumper cars, and carousels which are modelled slightly differently than roller coasters. If the user doesn't meet these requirements, they may take a specialized class specifically for a given ride, and based on the grade they received, the requirements are reduced. I model it as such, but later, there is some new requirement and I find the inheritance prevents the flexibility to make the required changes. So, how should I model it? AbstractRide - id (PK) - minimum_height_with_adult - minimum_age_with_adult - minimum_height_solo - minimum_age_solo - discriminator (roller_coaster, ferris_wheel, etc) - applicableCommonData RollerCoaster extends AbstractRide - id (PK, FK to AbstractRide.id) - applicableData FerrisWheel extends AbstractRide - id (PK, FK to AbstractRide.id) - applicableData HauntedHouse extends AbstractRide... UserTakesRideClass - ride_id (PK, FK to AbstractRide.id) - user_id (PK, FK to User.id) - grade User - id - height - age
  6. Thank you requinix and maxxd, Sorry about the lack of details and misused definitions. "Resource" is just an entity class and "access control" is the required permission needed to access a particular record. In addition, there is a ResourceMember object which is associated with a single User and a single resource object which also has required permission data, and this is the part which I am struggling with. One approach I might take is something like: AbstractResourceUnderAccessControl - id (PK) - discriminator - applicableData ResourceUnderAccessControlOne extends AbstractResourceUnderAccessControl - id (PK, FK to resource_under_access_control.id) - applicableData ResourceUnderAccessControlTwo extends AbstractResourceUnderAccessControl - id (PK, FK to resource_under_access_control.id) - applicableData ResourceMember - resource_under_access_control_id (PK, FK to resource_under_access_control.id) - user_id (PK, FK to user.id) - applicableData But doing it this way paints me into a corner, and would like to consider having each ResourceUnderAccessControl and the associated AccessControl different objects and using composition. But it just seems wrong having all these independent ResourceUnderAccessControl entities having a one-to-one relationship to a single AccessControl entity. In addition to making it more complicated to have the database enforce an AccessControl object to only be associated with a single resource, there is also the concern of later putting another resource under access control and having conflicting IDs, however, for this situation, I am using ULIDs and am not worried about it. While I very much appreciate your specific recommendations and advise how to best solve my immediate access control need, I also very much want to better figure out this generic concept as I have been struggling with it literally for years (composition-over-inheritance-examples, alternatives-to-entity-inheritance, favor-traits-with-interfaces-over-inheritance). Is there anything fundamentally wrong with doing it as I showed in my initial post?
  7. I need certain entity classes (i.e. ResourceUnderAccessControOne and ResourceUnderAccessControlTwo) to have more granular access control, and will need to store applicable for each resource on a per-record basis. I am using Doctrine, and one way to do so is have ResourceUnderAccessControlOne and ResourceUnderAccessControlTwo extend AccessControl, however, there are certain shortcomings with Doctrine and inheritance. As an alternative approach, I am thinking of using a one-to-one between each individual resource class and Acl, however, for no particular reason, I have concerns with this approach. Should I? The following provides a bit more context. I do not believe AccessControl will ever need to directly get the resource tied to it, but the resource will need to directly access its associated AccessControl object. For this schema, ResourceUnderAccessControlOne and ResourceUnderAccessControlTwo can share the same AccessControl which goes against business rules, however, either I can have PHP enforce this rule or add a "type" column to all tables and add the appropriate foreign keys. While "maybe" I shouldn't be implementing access control this way, I would still hope for advise for the stated question. Thanks! AccessControl - id (pk) - applicableDataForAccessControl ResourceUnderAccessControlOne - id (pk, FK to AccessControl.id) - applicableDataforResourceOne ResourceUnderAccessControlTwo - id (pk, FK to AccessControl.id) - applicableDataforResourceTwo
  8. Yeah, the Permission vs PermissionEnum thing kind of confusing to me as well! Yes, Doctrine has generic support for them. Will downgrade and wait it out. Thanks PS. I had tried to throw an __isString() in my enum, but evidently doing so is a no-no. Guess an __isInt() is a bit too niche and I understand why it doesn't exist.
  9. Thanks kicken, I had attempted to change App\Doctrine\Types\PermissionType (this is what you meant by doctrine configuration, right?) to not use a generic small int type and instead use a normal int type but it remained small int. Thinking it is a doctrine bug https://github.com/doctrine/orm/issues/10066.
  10. The following Doctrine method throws error Warning: Object of class App\\Entity\AccessControl\Acl\PermissionEnum could not be converted to int namespace Doctrine\DBAL\Types; class SmallIntType extends Type implements PhpIntegerMappingType { ... public function convertToPHPValue($value, AbstractPlatform $platform) { return $value === null ? null : (int) $value; } ... } PermissionEnum is a backed integer enum. enum PermissionEnum: int { case public = 0b00; case owner = 0b01; case restrict = 0b10; case extra = 0b11; } Similar to the __toString() magic method, is there a way to change my PermissionEnum so when type casted as an integer, returns an integer? Supplementary info below if of interest While outside of the scope of this question, the following added lines of code were added by Doctrine's latest commit and if removed, the issue goes away. PermissionEnum is used by class Permission which in turn is converted to an integer when saving the the database. namespace Doctrine\ORM\Query; class SqlWalker implements TreeWalker { public function walkSelectExpression($selectExpression) { ... if (! empty($mapping['enumType'])) { $this->rsm->addEnumResult($columnAlias, $mapping['enumType']); } ... } } namespace App\Doctrine\Types; use App\Entity\AccessControl\Acl\Permission; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\Type; final class PermissionType extends Type { private const PERMISSION = 'permission'; public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { return $platform->getSmallIntTypeDeclarationSQL($fieldDeclaration); } public function convertToPHPValue($value, AbstractPlatform $platform): mixed { if (null === $value) { return null; } if (\is_int($value)) { return Permission::createFromValue($value); } throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['int', 'null']); } public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed { if (null === $value) { return null; } if ($value instanceof Permission) { return $value->getValue(); } throw ConversionException::conversionFailedInvalidType($value, $this->getName(), [Permission::class, 'null']); } public function requiresSQLCommentHint(AbstractPlatform $platform): bool { return true; } public function getName(): string { return self::PERMISSION; } } class Permission { private const READ = 0b0000000011; private const CREATE = 0b0000001100; private const MODIFY = 0b0000110000; private const DELETE = 0b0011000000; private const COWORKER = 0b0100000000; // Not currently used. private const OWNER = 0b1000000000; // Not currently used. public function __construct( private ?PermissionEnum $read=null, private ?PermissionEnum $create=null, private ?PermissionEnum $modify=null, private ?PermissionEnum $delete=null, private ?bool $restrictToOwner=null, private ?bool $coworkers=null ) { } public function getValue(): ?int { if($this->hasNullValue()) { throw new Exception('Permission has NULL values.'); } $rs = $this->read->value | $this->create->value << 2 | $this->modify->value << 4 | $this->delete->value << 6; $rs = $this->coworkers ? $rs | self::COWORKER : $rs & ~self::COWORKER; return $this->restrictToOwner ? $rs | self::OWNER : $rs & ~self::OWNER; } }
  11. Sorry, thought I had included links to both the github and composer pages but evidently not. Github: https://github.com/api-platform/core/blob/3.0/src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php Packagist: https://packagist.org/packages/api-platform/core#3.0.x-dev
  12. I wish to use this version of ApiPlatformExtension which is the most current on the 3.0 branch. Note that there is no tag associated with it as v3.0.0 is several days older. Now, on packagist, there are several versions available, and based on the 2022-09-20 08:49 UTC date associated with 3.0.x-dev, it appears that is the one I want. It is my understanding that this branch only looks like a version, but isn't as indicated by the .x in the name. How should I make my project use the specific file which I stated above I wish to use? The project is not in production, so while maybe not ideal, I am okay with using an untagged version. I've tried the following and multiple similar attempts, but only get the previous version of the file. { "type": "project", "license": "proprietary", "minimum-stability": "stable", "prefer-stable": true, "require": { "php": ">=8.1", "api-platform/core": "3.0.x-dev", ... } }
  13. Agreed it didn't make sense. Just didn't know whether I was missing something else. Thanks
  14. Per the docs: Okay, guess that makes sense. But what doesn't make sense (at least to me) is why I am getting the following error. Can anyone explain why I am getting it? final class DocumentExtension implements QueryCollectionExtensionInterface { final private const EXEMPT_USER_ROLE = 'ROLE_TENANT_ADMIN'; private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): bool { if ($this->security->isGranted(self::EXEMPT_USER_ROLE)) { return false; } } }
  15. Agree it will likely not be an issue and even more agree it will not be an issue if only occurring when the database is being changed. Figured so much. Initially thought that if the content that was being saved was identical both times, it would somehow go through, but more I think about it, the more I think unlikely. I've conceded on not trying to overly optimize, however, I think this is a great solution. Let me check right now whether it works. On face value, it works great. The only thing I am not sure about is whether some method such as getId() is being invoked on it and it is being populated from the database. I looked at the SQL log and found that the user table is being queried three times. Guess if I was really concerned about performance, I wouldn't be using Doctrine. Appreciate the help!
  16. Thanks kicken! Was hoping it was going to be that easy, but nothing is ever easy! I have a TokenUser object which is my limited user object which is stored in the token. When passing it to BlameableListener, I get error: The class 'App\Security\TokenUser' was not found in the chain configured namespaces App\Entity, Tbbc\MoneyBundle\Entity, Money TokenUser contains a Ulid property, and when passing it to BlameableListener, I get error: The class 'Symfony\Component\Uid\Ulid' was not found in the chain configured namespaces App\Entity, Tbbc\MoneyBundle\Entity, Money So, then I tried passing BlameableListener the Ulid string value, but get error: Blame is reference, user must be an object I apply Blamable as an association, so I expect that explains the last error. #[ORM\ManyToOne(targetEntity: UserInterface::class)] #[ORM\JoinColumn(nullable: false)] #[Gedmo\Blameable(on: 'update')] protected ?UserInterface $updateBy = null; I don't really understand the chain configured namespaces errors. My condensed security.yaml is: security: providers: app_logon_user_provider: id: App\Security\LogonUserProvider jwt: lexik_jwt: class: App\Security\TokenUser firewalls: main: provider: jwt jwt: ~ json_login: provider: app_logon_user_provider check_path: /authentication_token username_path: email password_path: password success_handler: lexik_jwt_authentication.handler.authentication_success failure_handler: lexik_jwt_authentication.handler.authentication_failure TokenUser is: final class TokenUser implements JWTUserInterface, BasicUserInterface { public function __construct(private Ulid $id, private OrganizationType $type, private array $roles, private Ulid $organizationId, private ?Ulid $tenantId) { } public static function createFromPayload($id, array $payload):self { return new self(Ulid::fromString($id), OrganizationType::fromName($payload['type']), $payload['roles'], Ulid::fromString($payload['organizationId']), $payload['tenantId']?Ulid::fromString($payload['tenantId']):null); } // Some more methods... } My LogonUserProvider::loadUserByIdentifier() queries the DB for the user and if it exists, returns the doctrine User. I also tried returning TokenUser instead of the Doctrine User, but I recall it also having issues. Maybe I should be? My JWTCreatedListener sets the payload based on the Doctrine User, and the Jwt package takes it from there. final class JWTCreatedListener { public function onJWTCreated(JWTCreatedEvent $event) { $user = $event->getUser(); $payload = $event->getData(); $payload['organizationId'] = $user->getOrganization()->toRfc4122(); $payload['tenantId'] = ($tenant=$user->getTenant())?$tenant->toRfc4122():null; $event->setData($payload); } } I also have another AuthenticationSuccessListener which sets some public data (never understood why this needs to be a separate listener, but oh well...). final class AuthenticationSuccessListener { public function onAuthenticationSuccessResponse(AuthenticationSuccessEvent $authenticationSuccessEvent): void { $user = $authenticationSuccessEvent->getUser(); if (!$user instanceof UserInterface) { return; } $data = $authenticationSuccessEvent->getData(); $data['data'] = [ 'id' => $user->getId()->toRfc4122(), 'firstName' => $user->getFirstName(), 'lastName' => $user->getLastName(), 'roles' => $user->getRoles(), ]; $authenticationSuccessEvent->setData($data); } } The only way I have been able to eliminate errors is pass BlameableListener the hydrated Doctrine Users. Instead of getting this Doctrine User on any POST/PUT/PATCH requests as I suggested I might do in my initial post, I am doing so during the preFlush event which I suppose is a little better. Still kind of annoys me, and would rather not do so. Any advise? Thanks!
  17. I am using a 3rd party plugin called blamable which sets the createBy and updateBy property when entity which have these properties are changed. While it happens to by Symfony/Doctrine related, I don't think the solution need be based on either. It is the responsibility of the developer to set the user within the blamable listener and I have seen this be done by setting it upon each request regardless of whether it will be required for the given request. I happen to be using JWT's where a minimal user entity is stored in the token and used for most requests and I just query the DB and transform to the real user entity where needed. As such, I don't want to make the DB call for all requests, and instead also listen for entities which contain these properties are created or updated, but listen faster than the blamable listener and set it first. All great... Until I discover the blamable bundle also considers an entity changed when something is added or removed from a many-to-many relationship to an entity, and my listener doesn't get triggered, and updateBy is set to null resulting in a not-null constraint error. I suppose I "could" try to predict these edge cases, but feel this is getting too fragile. One option is to set it very early for all post/patch/put requests before I know whether it will actually be necessary, but my OCD nature doesn't want to (actually, as I write this, thinking doing so might not be so bad). Instead, I would like to set it very early with some "preliminary user object" which gets converted to the real user object only when the blamable plugin actually tries to do something with this preliminary user object. Below is a very condensed version of BlameableListener and AbstractTrackingListener. I am questioning whether I am going down a rabbit hole which doesn't come back up. Think so? If it might be feasible, ideas where to start? Was thinking my preliminary user object might use overloading so that I know when any of the methods are called, but I don't think doing so will be allowed by an interface. Maybe I am going about this totally the wrong way. class BlameableListener extends AbstractTrackingListener { protected $user; // This is the method I am suppose to set before blamable needs it. public function setUserValue($user) { $this->user = $user; } public function getFieldValue($meta, $field, $eventAdapter) { // Does a little work and returns $this->user. } public function prePersist(EventArgs $args) { // Checks things out and maybe calls updateField(). This is easy as I can independent listen when an entity is persisted (Doctrine talk as scheduled to be intered into the DB). } public function onFlush(EventArgs $args) { // Checks things out and maybe calls updateField(). This one is not easy as flush happens after the persist event and I have missed the chance to set the user. } protected function updateField($object, $eventAdapter, $meta, $field) { // $object is an entity which has a updateBy property which needs to be set with the logged on user $property = $meta->getReflectionProperty($field); // $property is ReflectionProperty Object ([name] => updateBy [class] => App\Entity\Asset\Asset) ... $newValue = $this->getFieldValue($meta, $field, $eventAdapter); // $newValue should be the user but will be NULL if I haven't set it. ... $property->setValue($object, $newValue); } }
  18. Is there any slick way of applying a method conditionally like my made up syntax below? Thanks $flag = true; $obj ->setName('bob') ->setAge(99) ->?$flag->setFoo('xxx'); //Only call setFoo if $flag is true. $obj ->setName('bob') ->setAge(99) ->?$flag->setFoo('xxx'):setBar('yyy'); //Call setFoo if $flag is true, else call setBar public function setName(string $name):self;
  19. The following four methods were changed. The first three seem to be correct but not sure about the last one (hasPhysicalMedia). Agree? Best way to fix is just type casting the returned value? Thanks public function getPhysicalMedia(): ?PhysicalMedia { - return $this->activeMedia?$this->activeMedia->getPhysicalMedia():null; + return $this->activeMedia?->getPhysicalMedia(); } public function getMediaType(): ?MediaType { - return $this->activeMedia?$this->activeMedia->getMediaType():null; + return $this->activeMedia?->getMediaType(); } public function getFilename(): ?string { - return $this->activeMedia?$this->activeMedia->getFilename():null; + return $this->activeMedia?->getFilename(); } public function hasPhysicalMedia(): bool { - return $this->activeMedia && $this->activeMedia->hasPhysicalMedia(); + return $this->activeMedia?->hasPhysicalMedia(); } class ActiveMedia { public function getPhysicalMedia(): PhysicalMedia { return $this->physicalMedia; } public function getMediaType(): ?MediaType { return $this->mediaType; } public function getFilename(): ?string { return $this->filename; } public function hasPhysicalMedia(): bool { return (bool) $this->physicalMedia; } }
  20. Thanks requinix, Seem like if a user doesn't have a home directory, php assumes it is at the typical /home/abtfile. Ended up going with "abtfile:x:1001:1001::/var/www/abtfile:/usr/sbin/nologin".
  21. Finally left Centos and gave Ubuntu a try. Also, changed from apache to nginix. All went much easier than Centos but have one issue. I wish to have a non-human user dedicated to each website which PHP will run under and postgresql will use. I created my user but didn't provide a home directory (useradd -M abtfile). My configuration is shown below and phpinfo shows abtfile as the user but /home/abtfile as the home. I am now thinking I should have created a home for the user should keys or similar be needed for it, and think my options are: Home directory: /home/abtfile Host site: /var/www/abtfile/public. Doesn't seem right. Home directory: /home/abtfile Host site: /home/abtfile/public. Better but not sure. Home directory: /var/www/abtfile Host site: /var/www/abtfile/public. Likely but not sure. Questions. Should abtfile user have a home directory? Which of my three options or some other approach should be used? Do I define the home directory location the same way as for any linux user or must it also be defined under some php or nginix config file? Thanks! PS. Not having issues (yet), however, if you see any issues under my below configuration files, please let me know. /etc/php/8.1/fpm/pool.d/abtfile.conf [abtfile] user = abtfile group = abtfile ; Call whatever I want. Use ls -l /run/php/ to see existing sockets. listen = /var/run/php8.1-fpm-abtfile.sock ; Must match to the user and group on which NGINX is running listen.owner = www-data listen.group = www-data ; Consider changing below valves. ; mandatory pm = dynamic pm.max_children = 5 pm.min_spare_servers = 1 pm.max_spare_servers = 3 ; Use default values. ; pm.start_servers = 2 ; pm.max_spawn_rate = 32 ; pm.process_idle_timeout = 10s ; Not sure if necessary or correct ; Allows to set custom php configuration values. ; php_admin_value[disable_functions] = exec,passthru,shell_exec,system ; Allows to set PHP boolean flags ; php_admin_flag[allow_url_fopen] = off ; Add environmental data if desired. ; env[HOSTNAME] = $HOSTNAME ; env[TMP] = /tmp /etc/nginx/sites-available/abtfile server { server_name abtfile.testing.com; listen 80; listen [::]:80; root /var/www/abtfile/public; index index.php index.html index.htm; access_log /var/log/nginx/abtfile-access.log; error_log /var/log/nginx/abtfile-error.log; location / { try_files $uri $uri/ =404; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php8.1-fpm-abtfile.sock; fastcgi_split_path_info ^(.+\.php)(/.+)$; # What does this do? #fastcgi_index index.php; # Causes error. Maybe remove from above? } } /etc/nginx/php_fastcgi.conf try_files $fastcgi_script_name =404; include fastcgi_params; fastcgi_pass unix:/run/php/php-fpm.sock; fastcgi_index index.php; fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; fastcgi_hide_header X-Powered-By; fastcgi_hide_header X-CF-Powered-By;
  22. Ended up forking the git repo, adding it as a repository in composer.json, and manually adding 'hautelook/alice-bundle": "2.10" to require.dev.
  23. Trying to install a package but received a version error: composer require --dev alice Using version ^2.10 for hautelook/alice-bundle ./composer.json has been updated Running composer update hautelook/alice-bundle Loading composer repositories with package information Updating dependencies Your requirements could not be resolved to an installable set of packages. Problem 1 - Root composer.json requires hautelook/alice-bundle ^2.10 -> satisfiable by hautelook/alice-bundle[2.10.0]. - hautelook/alice-bundle 2.10.0 requires doctrine/persistence ^2.2 -> found doctrine/persistence[2.2.0, ..., 2.5.3] but the package is fixed to 3.0.2 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command. Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions. You can also try re-running composer require with an explicit version constraint, e.g. "composer require hautelook/alice-bundle:*" to figure out if any version is installable, or "composer require hautelook/alice-bundle:^2.1" if you know which you need. Installation failed, reverting ./composer.json and ./composer.lock to their original content. An issue has been created and a pull request fixing the issue has been made. The fix just changed composer.json "doctrine/persistence": "^2.2", to "doctrine/persistence": "^2.2 || ^3.0" What are my options to use this package before the github and composer package is updated? Ideally, I would like to instruct composer to allow hautelook/alice-bundle to use 3.0 either by adding some argument when I call composer on the command line or by manually editing composer.json as applicable. Is this possible? If this is not possible, I suppose my next best choice is to downgrade doctrine/persistence from 3.02 to 2.2, however, doctrine/persistence is not in my composer.json file and only in my composer.lock file which I suspect I shouldn't be manually editing it. Guess my third choice would be to clone it from github, make the changes, and then modify my composer file to use a local copy. Maybe there are other approaches? Thanks
  24. class IteratorIterator implements OuterIterator and this class permits access to methods of the inner iterator via the __call magic method. class RecursiveIteratorIterator implements OuterIterator interface OuterIterator extends Iterator Should I conclude that any class that implements OuterIterator permits access to methods of the inner iterator via the __call magic method, and not just IteratorIterator? Thanks PS. Totally off topic, but is there a way to embed a link when one quotes something (i.e. your quote would include https://www.php.net/manual/en/class.iteratoriterator.php)? Array ( [0] => RecursiveIteratorIterator [1] => IteratorIterator [2] => FilterIterator [3] => RecursiveFilterIterator [4] => CallbackFilterIterator [5] => RecursiveCallbackFilterIterator [6] => ParentIterator [7] => LimitIterator [8] => CachingIterator [9] => RecursiveCachingIterator [10] => NoRewindIterator [11] => AppendIterator [12] => InfiniteIterator [13] => RegexIterator [14] => RecursiveRegexIterator [15] => RecursiveTreeIterator )
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.