Jump to content

NotionCommotion

Members
  • Posts

    2,446
  • Joined

  • Last visited

  • Days Won

    10

Everything posted by NotionCommotion

  1. The previous code that is working shown below along with a pre-persist event listener is used to create an auto-incrementing identifier (called publicId) for each type of entity on a per account/tenant basis. I later had a need to get this publicId before the entity was persisted. This made me consider that I am way overcomplicating matters and should just set this publicId when setting the entities tenant property, and I added the following method: trait HasPublicIdTrait { // other methods // Override parent to set entities publicid. public function setTenant(?Tenant $tenant): self { $this->tenant = $tenant; $tenant->generatePublicId($this); return $this; } } When trying it out, however, I got the following error: Compile Error: Trait method App\Entity\MultiTenenacy\HasPublicIdTrait::setTenant has not been applied as App\Entity\Organization\Vendor::setTenant, because of collision with App\Entity\MultiTenenacy\BelongsToTenantTrait::set Is it possible to make trait methods override other trait methods? Any other suggestions other than just not having AbstractPublicIdTenantEntity extend AbstractPublicIdTenantEntity? PREVIOUS CODE THAT IS WORKING <?php declare(strict_types=1); namespace App\Entity\Organization; use Doctrine\ORM\Mapping as ORM; use App\Repository\Organization\TenantRepository; use App\Entity\MultiTenenacy\HasPublicIdInterface; #[ORM\Entity(repositoryClass: TenantRepository::class)] class Tenant extends AbstractOrganization { #[ORM\Column(type: 'json')] private array $publicIdStack = []; public function publicIdSetter(HasPublicIdInterface $hasPublicId): self { $publicIdIndex = $hasPublicId->getPublicIdIndex(); $this->publicIdStack[$publicIdIndex] = ($this->publicIdStack[$publicIdIndex]??0) + 1; $hasPublicId->setPublicId($this->publicIdStack[$publicIdIndex]); return $this; } } <?php namespace App\Entity\MyEntity; use App\Entity\MultiTenenacy\AbstractPublicIdTenantEntity; class MyEntity extends AbstractPublicIdTenantEntity { public function getPublicIdIndex(): ?string { return 'my-entity'; } } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use App\Entity\Trait\NonIdentifyingIdTrait; abstract class AbstractPublicIdTenantEntity extends AbstractTenantEntity implements HasPublicIdInterface { use NonIdentifyingIdTrait; use HasPublicIdTrait; } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use App\Entity\AbstractEntity; abstract class AbstractTenantEntity extends AbstractEntity implements BelongsToTenantInterface { use BelongsToTenantTrait; } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use App\Entity\Organization\Tenant; use Symfony\Component\Serializer\Annotation\Ignore; trait BelongsToTenantTrait { #[ORM\ManyToOne(targetEntity: Tenant::class)] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] #[Ignore] protected ?Tenant $tenant = null; public function getTenant(): Tenant { return $this->tenant; } public function setTenant(?Tenant $tenant): self { $this->tenant = $tenant; return $this; } } <?php declare(strict_types=1); namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; use Symfony\Component\Serializer\Annotation\Ignore; use App\Entity\Organization\Tenant; #[ORM\UniqueConstraint(columns: ['public_id', 'tenant_id'])] trait HasPublicIdTrait { #[SerializedName('id')] #[Groups(['public_id:read'])] #[ORM\Column(type: 'integer')] protected ?int $publicId = null; public function getPublicId(): ?int { return $this->publicId; } public function setPublicId(int $publicId): HasPublicIdInterface { $this->publicId = $publicId; return $this; } public function generatePublicId(): HasPublicIdInterface { $this->getTenant()->publicIdSetter($this); return $this; } abstract public function getPublicIdIndex(): ?string; }
  2. No change. Just to be "extra sure", even deleted the vendor directory. EDIT - Just deleted it again and did the composer require package instead of install and then it worked. Why I have no idea...
  3. How should one go about troubleshooting composer? composer.lock does in fact show doctrine/dbal as 3.3.2. I don't think that my composer.json shown at the bottom is causing this. What does it mean regarding "by a partial update"? Thanks $ docker-compose exec php \ > composer require brick/phonenumber-doctrine Using version ^0.1.1 for brick/phonenumber-doctrine ./composer.json has been updated Running composer update brick/phonenumber-doctrine 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 brick/phonenumber-doctrine ^0.1.1 -> satisfiable by brick/phonenumber-doctrine[0.1.1]. - brick/phonenumber-doctrine 0.1.1 requires doctrine/dbal ^2.7.0 -> found doctrine/dbal[v2.7.0, ..., 2.13.7] but the package is fixed to 3.3.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 brick/phonenumber-doctrine:*" to figure out if any version is installable, or "composer require brick/phonenumber-doctrine:^2.1" if you know which you need. Installation failed, reverting ./composer.json and ./composer.lock to their original content. $ composer.lock (partial) { "name": "doctrine/dbal", "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", "reference": "35eae239ef515d55ebb24e9d4715cad09a4f58ed" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/doctrine/dbal/zipball/35eae239ef515d55ebb24e9d4715cad09a4f58ed", "reference": "35eae239ef515d55ebb24e9d4715cad09a4f58ed", "shasum": "" }, "require": { "composer-runtime-api": "^2", "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", "php": "^7.3 || ^8.0", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2021.1", "phpstan/phpstan": "1.4.0", "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "9.5.11", "psalm/plugin-phpunit": "0.16.1", "squizlabs/php_codesniffer": "3.6.2", "symfony/cache": "^5.2|^6.0", "symfony/console": "^2.7|^3.0|^4.0|^5.0|^6.0", "vimeo/psalm": "4.16.1" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." }, "bin": [ "bin/doctrine-dbal" ], "type": "library", "autoload": { "psr-4": { "Doctrine\\DBAL\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com" }, { "name": "Roman Borschel", "email": "roman@code-factory.org" }, { "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" } ], "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", "homepage": "https://www.doctrine-project.org/projects/dbal.html", "keywords": [ "abstraction", "database", "db2", "dbal", "mariadb", "mssql", "mysql", "oci8", "oracle", "pdo", "pgsql", "postgresql", "queryobject", "sasql", "sql", "sqlite", "sqlserver", "sqlsrv" ], "support": { "issues": "https://github.com/doctrine/dbal/issues", "source": "https://github.com/doctrine/dbal/tree/3.3.2" }, "funding": [ { "url": "https://www.doctrine-project.org/sponsorship.html", "type": "custom" }, { "url": "https://www.patreon.com/phpdoctrine", "type": "patreon" }, { "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal", "type": "tidelift" } ], "time": "2022-02-05T16:33:45+00:00" }, composer.json (partial) { "require": { "brick/phonenumber": "^0.4.0", "doctrine/annotations": "^1.0", "doctrine/doctrine-bundle": "^2.4", "doctrine/doctrine-migrations-bundle": "^3.0", "doctrine/orm": "^2.9" }, "require-dev": { "doctrine/doctrine-fixtures-bundle": "^3.4" } }
  4. Yeah, my spider sense told me so but I was just being lazy/dumb. Unfortunately, I am not dealing with big money but if one were, they should definitely not be using floats and if anything but US currency, I believe only integers for the value plus a string for the currency which would use ISO-4217 (hooray, a standard!) to lookup the base currency value and decimal places.
  5. There should be! Why not go per ISO-4217 regarding the unit and decimal so for US units are dollars and decimals are 2 and for Japan units are yen and decimals are zero, and I don't need to come up with with what I think the lowest units are? I suspected that trying to combine amount and units in a single string is a bad idea and sounds like you agree, however, would like to still hear your reason why not to do so.
  6. I wish to store money (value/currency) in a database, and thinking of following ISO-4217. For example, $50.45 is represented as 5045/USD and ¥227 is represented as 227/JPY. If I use two columns, suppose I should use big integer and char(3) as it gets me up to +/- 4.6 quintillion dollars which is pretty big. It would make some things simpler to store as a single string such as USD:5045 and JPY:227, however, I have some concerns. Instead of me making up my own format, is there any recognized format such as what RFC3339 is for time? I recognize it makes sorting by cost a little challenging, but since exchange rates are not fixed and there is no way to normalize the data like using UTC, it will be challenging regardless. Any other concerns or ideas? Thanks A couple ISO-4217 examples.
  7. Thanks for your sound advice maxxd, I am still back and forth but more in your camp. I thought this blog was good as it tried to give perspectives of both approaches, but it ultimately recommended hard deletes. Definitely not saying it is right and would much appreciate your thoughts of their pros and cons. More importantly, and high-level recommendations (and maybe later low-level) on how to implement with PHP would be great.
  8. Thanks Strider, For some applications, I understand one can get in legal trouble for not hard-deleting the data (privacy, etc). Not for my application and not over the top security as well. While adding a constraint on email and username/street/birthday/etc solves some of the constraint issues, wouldn't doing so prevent allowing users to sign in using just their email?
  9. I am working on a document management system where users that belong to a given organization can upload documents and tag them accordingly and then later retrieve them. Note that these documents are not owned by the individual users who uploaded them but by the organization. I am trying to decide whether I should push for one of the following business rules regarding the deletion of records: Do not delete the data but tag them as deleted (soft-delete). Actually delete the row from the table (hard-delete). Move the deleted record to another table (moved-delete). Maybe some other strategy? Under what conditions, would you recommend having a business rule of one of the above? Some concerns/thoughts for each option: Soft-Delete - How should unique constraints such as user's email and username be handled? I think a reasonable business rule is to make username unique for all time but not for email. Hard-Delete - Foreign key constraints could be an issue. For instance, I currently have a non-NULL uploadedByUserId column. If an individual user uploads a document and that user is later deleted, I can't just delete the document because it wasn't the user's but the organization. One option is to change it to nullable, but doing so isn't ideal, and there are other use-cases other than user-id which are not so simple. Or maybe the user is required to reassign all documents first so there will not be a constraint violation? Moved-Deletes - Seems like it will have the same challenges with foreign keys as with hard-delete. If going this path, should one mirror the columns of each not-deleted and deleted table or serializing the data and sav as JSON in the deleted table? Any other general insight would be appreciated.
  10. Thanks requinix. I was previously using 5.1.19 and after upgrading to 5..1.21, no errors. Just curious but do you know why PHP reported "Unknown on line 0"? PHP Deprecated: Return type of APCUIterator::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0
  11. I upgraded a docker-compose package to use PHP 8.1, and the application still works but I get the following warnings. $ docker-compose exec php php -v PHP Deprecated: Return type of APCUIterator::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 Deprecated: Return type of APCUIterator::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 PHP Deprecated: Return type of APCUIterator::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 Deprecated: Return type of APCUIterator::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 PHP Deprecated: Return type of APCUIterator::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 Deprecated: Return type of APCUIterator::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 PHP Deprecated: Return type of APCUIterator::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 Deprecated: Return type of APCUIterator::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 PHP Deprecated: Return type of APCUIterator::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 Deprecated: Return type of APCUIterator::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in Unknown on line 0 PHP 8.1.1 (cli) (built: Dec 18 2021 01:38:53) (NTS) Copyright (c) The PHP Group Zend Engine v4.1.1, Copyright (c) Zend Technologies with Zend OPcache v8.1.1, Copyright (c), by Zend Technologies Looking for the cause, I searched for "APCUIterator" and found very few occurrences. No return declaration on APCUIterator in the two PHP files and I don't think they are the cause. The binary files I think might be the issue as I do see "class APCUIterator implements Iterator{...}" but hard to tell as they are binary files and I don't really know what they do. Maybe that PHP says "Unknown on line 0"? Any suggestions? If the warning is caused by script maintained by others and I just want to wait for them to update it, is it possible to silence just this specific warning and ideally just for the specific files? $ grep -inr . -eAPCUIterator ./api/vendor/symfony/cache/Adapter/ApcuAdapter.php:97: return isset($namespace[0]) && class_exists(\APCuIterator::class, false) && ('cli' !== \PHP_SAPI || filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) ./api/vendor/symfony/cache/Adapter/ApcuAdapter.php:98: ? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY)) Binary file ./api/vendor/phpstan/phpstan/phpstan.phar matches Binary file ./api/vendor/rector/rector/vendor/phpstan/phpstan/phpstan.phar matches
  12. I never used to and also didn't originally understand the point of doing so, but eventually came to appreciate how sprintf/printf offers some separation of concerns. I am sure it is personal choice but other reasons why I like to use them include: Ability to format/pad/etc. Consistency when working with associated arrays and multiple-dimension sequential arrays. Ability to apply a function to the arguments, ability for arguments to be a method applied to an object, etc. Reuse of templates. Less troubleshooting values that need to be escaped. Easier to read and less dinking around with presentation (once you get used to them!).
  13. Don't know whether more efficient or not from a processing perspective but using printf/sprintf will be more efficient from a your time perspective.
  14. There are also some existing libraries to meet this need: https://github.com/brick/money https://github.com/moneyphp/money
  15. I would try to minimize the number of PHP scripts which are publicly accessible and typically just have a single index.php in my public folder, and would locate header.php outside of the document route. This way, you don't have to add all those silly "if something is not defined, die not accessible" It also makes the paths easy to deal with relative url's to your client resources and you can hardcode them in your HTML if you wish. YourProject/ public/ index.php (routes to the appropriate part of the application) style/ custom.css js/ custom.js images/ custom.png src/ YourClasses.php testing/ test.php vendor/ (if you currently don't use composer, I recommend you learn about it) template/ includes/ header.php config/ config.ini (or json, etc)
  16. I too do not understand what "complete cyber security mitigation" is and https://github.com/rectorphp/rector certainly is not, however, it may help you identify and revise some legacy or poorly written code and thus improve security.
  17. While not curated, I suppose I could build my own using https://www.iana.org/assignments/media-types/media-types.xhtml as a reference, or perhaps https://github.com/jshttp/mime-db will be a better starting point. I seems, however, that this would be a fairly common need in PHP applications and there would be some composer package which would be easier to maintain.
  18. Yes, I think so. Any suggestions on where to find one? Thank you, I was originally thinking differently, but now fully agree.
  19. There is both the Content-Length in the request header and the size value in $_FILES. Aren't they two separate things? My purpose is to allow a user (organization) to limit the types of files outside users can upload based on the software the user/organization has. Almost everyone has software for PDF's, various images, various Microsoft documents, etc, but there is also file types such as AutoCAD, various BIM formats, and others. ZIP archives will need to be supported to allow OpenDOcument files and they add some complexity as they contain other files, but suppose they can be opened and inspected prior to saving. Regarding validating that the detected MIME type is consistent with the extension, seems like this is a common need and there would be some de facto standard opensource package but I haven't found it. Will have to give this one more thought... Guess I can store it but don't know what to do with it. When later providing the file for download, would I want to use this value or the detected value? What if two identical files were uploaded but with different clients and were given different MIME types? Would I return them with different MIME types?
  20. When a file is uploaded, $_FILES will be populated with the name, type, and size (which are all provided by the browser and in the body and not headers, right?) as well as the tmp_name and errors (which is presumably set by PHP). If browser provided size is different than what filesize() reports, should I care or just go with filesize()? What about similar question but for mime type? Some file types result in false positives such as the following and I will want to accept those as being valid, but should I reject them as being invalid if if they are actually different? Regarding detecting these multiple valid mime types, is there a PHP function to do so or any good composer/etc packages? Also, I am thinking I should never bother saving the browser provided mime type because it is based on the individual browser and/or operating system the user happened to be using at the time, agree? printf('extention: %s type: %s (provided) %s (fileinfo) FILEINFO_EXTENSION: %s<br>'.PHP_EOL, pathinfo($_FILES['expenseFile']['name'])['extension'], $_FILES['expenseFile']['type'], (new \finfo(FILEINFO_MIME_TYPE))->file($_FILES['expenseFile']['tmp_name']), (new \finfo(FILEINFO_EXTENSION))->file($_FILES['expenseFile']['tmp_name']) ); extention: csv type: application/vnd.ms-excel (provided) application/csv (fileinfo) FILEINFO_EXTENSION: ??? extention: gz type: application/x-gzip (provided) application/gzip (fileinfo) FILEINFO_EXTENSION: ??? extention: js type: text/javascript (provided) text/plain (fileinfo) FILEINFO_EXTENSION: ??? extention: css type: text/css (provided) text/plain (fileinfo) FILEINFO_EXTENSION: ??? extention: yaml type: application/octet-stream (provided) text/plain (fileinfo) FILEINFO_EXTENSION: ??? extention: ini type: application/octet-stream (provided) text/plain (fileinfo) FILEINFO_EXTENSION: ??? There is also the issue of having file extensions that matches the actual file type and I wish to reject those that do not. finfo's FILEINFO_EXTENSION constant provides solutions for some but very few at least with my version of magic.mime database. Any good approaches or 3rd party packages that can manage this? extention: ods type: application/vnd.oasis.opendocument.spreadsheet (provided) application/vnd.oasis.opendocument.spreadsheet (fileinfo) FILEINFO_EXTENSION: ods extention: png type: image/png (provided) image/png (fileinfo) FILEINFO_EXTENSION: png extention: jpg type: image/jpeg (provided) image/jpeg (fileinfo) FILEINFO_EXTENSION: jpeg/jpg/jpe/jfif Thanks!
  21. Thanks again kicken, I thought that php-fpm brought some unique differences but maybe not.
  22. Thanks kicken, I removed all the settings I showed for the pool and just used Apache's Timeout and it worked perfect. May I ask what if any is the any difference between using ini_set ('max_execution_time', '120') and set_time_limit(120)? Also, I have found that some settings must be made by editing the pool while others are set by php.ini and/or php commands such as ini_set() and set_time_limit(). Is there any general categorization which dictates which must be defined where?
  23. When making a request from the browser, I get a 503 Service Unavailable after exactly 60 seconds, however, the I see that PHP is still executing the script. I first tried the following without success. Curiosity question - What is the difference between these two lines? ini_set ('max_execution_time', (string) $container['maxTime']); set_time_limit($container['maxTime']); I then tried making the following changes to my default pool /etc/php-fpm.d/www.conf, but still defaults at 60 seconds. Note that the only reason I added default_socket_timeout is that it is the only item displayed with a value of 60 by phpinfo() and was just hoping. request_terminate_timeout = 120 ;max_execution_time=120 ;results in error php_value[max_input_time] = 120 php_value[max_execution_time] = 120 php_value[default_socket_timeout] = 120 Any ideas? Thanks
  24. Start by looking at phpinfo(), /etc/php.ini (or whatever on windows), and your php fpm settings if used. If no culprits, maybe your web server? Also, I often do reality checks such as the following. printf('filesize: %s copy(%s, %s)<br>'.PHP_EOL, filesize($source . $file), $source . $file, $destPath . $file);
  25. Ah, got it! The above also says the same, and the datetime string can contain the timezone and nothing says that it needs to contain more. Not a bug, not incomplete documentation (but a little ambiguous, but my misunderstanding. Thank you for your clarification. My initial thought was to first use DateTime and then validate against false positives, but I cannot disagree with your position and will most likely do as you recommend.
×
×
  • 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.