Jump to content

NotionCommotion

Members
  • Posts

    2,446
  • Joined

  • Last visited

  • Days Won

    10

Everything posted by NotionCommotion

  1. Because validation was not fully implemented. Off topic, but what is your position on utilizing the database to enforce some validation rules? I know that some will disagree, but I feel there are benefits to allowing the database to solely validate unique constraints.
  2. I have a listener which executes a HTTP request to a remote API before the User entity is persisted and uses the response to set one of the entity's properties. It will also listen for update and remove and will make the appropriate HTTP request to the API but will not modify the entity. All works as desired... Almost. If when persisting the entity, I have some error, the remote API and my application become out of sync. I wish to change my application to perform a second call to the API if an error occurs and reverse the previous call. My thoughts on how to implement are: Place a try/catch block when executing the query. Don't like this approach. Add an ExceptionListener which somehow retrieves the entity and makes the applicable changes. Maybe part of the solution, but too complicated to be the full solution. When adding, updating, or deleting a user from the remote API under UserListener's three methods, adding a callback which gets executed upon a PDOException. I think this is the best approach and expanded my thoughts below. <?php namespace App\EventListener; use Doctrine\Persistence\Event\LifecycleEventArgs; use App\Service\HelpDeskClient; use App\Entity\AbstractUser; final class UserListner { private $helpDeskClient; public function __construct(HelpDeskClient $helpDeskClient) { $this->helpDeskClient = $helpDeskClient; } public function prePersist(AbstractUser $user, LifecycleEventArgs $event) { $this->helpDeskClient->addUser($user); //$user will be updated with the HTTP response } public function preUpdate(AbstractUser $user, LifecycleEventArgs $event) { $this->helpDeskClient->updateUser($user); } public function preRemove (AbstractUser $user, LifecycleEventArgs $event) { $this->helpDeskClient->deleteUser($user); } } Okay, how do I actually do this? Was thinking of modifying UserListner as follows: //... use Symfony\Component\HttpKernel\KernelEvents; final class UserListner { // ... public function prePersist(AbstractUser $user, LifecycleEventArgs $event) { $this->helpDeskClient->addUser($user); $event->getObjectManager()->getEventManager()->addEventListener(KernelEvents::EXCEPTION, function($something) use($user) { // Use $this->helpDeskClient to reverse the changes }); } // Similar for update and remove } But when trying this approach, I get a PDOException, but my callback never gets excecated. I've also tried replacing KernelEvents::EXCEPTION with '\PDOException' (note the quotes) with no success. Any ideas what I should be doing differently? Maybe some totally different approach? I suppose I could make the request to the API after the DB query is complete for updating and deleting, but not for adding.
  3. Agree, code thankfully doesn't behave randomly, only me! Also, agree I shouldn't import stuff I don't need, but frustrating that there appears to be no way to determine whether stuff is needed other than trial and error. Back to earlier question, you think PHP8 attributes might be more consistent (assuming the framework supports them)? If you don't know, have what I need. Thanks
  4. Yes! When you commented about the "parser", is this PHP's C code or PHP application code part of a given framework (i.e. Doctrine, Symfony)? If the later, I could see how one might get different results, but would not expect these two frameworks to implement it differently. Also, you will see that the traits provided in the original post use other traits. It is my understanding that doing so is acceptable but maybe I am not doing so correctly?
  5. The "application" I was referring to is Symfony and/or Doctrine. Take the following class which uses the traits posted in my original post: <?php namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; use App\Entity\Owner\Owner; /** * @ORM\Entity() */ class Test { use PublicIdTenantTrait; /** * @ORM\Column(type="string", length=255) */ private $name; } When checking the schema, all validates. But then I comment out the use input statements for Groups, SerializedName, and Owner, and get an error that I didn't use a "use" statement for Groups. I add back Groups, but then get it for SerializedName. I add back SerializedName and then get it for Owner. Nowhere in the Test class am I using any of these classes and only in the traits that I do, but still I get these errors. [michael@devserver api2]$ bin/console doctrine:schema:validate In AnnotationException.php line 39: [Semantical Error] The annotation "@Groups" in property App\Entity\MultiTenenacy\Test::$publicId was never imported. Did you maybe forget to add a "use" statement for this annotation? [michael@devserver api2]$ bin/console doctrine:schema:validate In AnnotationException.php line 39: [Semantical Error] The annotation "@SerializedName" in property App\Entity\MultiTenenacy\Test::$publicId was never imported. Did you maybe forget to add a "use" statement for this annotation? [michael@devserver api2]$ bin/console doctrine:schema:validate Mapping ------- In MappingException.php line 870: The target-entity App\Entity\MultiTenenacy\Owner cannot be found in 'App\Entity\MultiTenenacy\Test#owner'. doctrine:schema:validate [--em EM] [--skip-mapping] [--skip-sync] [michael@devserver api2]$ So, then I put them back in the Test class, and remove them from the traits, and have no errors. And then I remove the import for ApiProperty in the trait and get an error. [michael@devserver api2]$ bin/console doctrine:schema:validate In AnnotationException.php line 39: [Semantical Error] The annotation "@ApiProperty" in property App\Entity\MultiTenenacy\Test::$id was never imported. Did you maybe forget to add a "use" statement for this annotation? [michael@devserver api2]$ I then add ApiProperty to the Test class and then no errors. I see no pattern and am discovering these issues by just trial and error, but there has to be a reason, no?
  6. Thanks requinix, Appears that imports for non-annotation purposes (i.e. type declaration, creating a new object) should be located in the file where they are being used, right? For annotation purposes, sounds like it is based on how the given application's author elected to write the application, true? Is there any approach that is more typical than the other? Does it make sense to always import in both the trait and the class? Do you know whether PHP 8's attributes are independent of the application?
  7. Haven't really used traits much and am confused whether to import other classes in the trait or the class that uses the trait (might also be an annotation question but not sure). Must import statements (i.e. use Foo\Bar;) be included in the class or can they be included in just the trait which is used by a class? Does it depend and if so on what? Does having one class use another class impact the decision? Is it okay for one trait to use another and another trait to just use the first trait or should it use both? What is odd is I apparently must (to not get an error) import ApiProperty to the trait but doing so is not required for the class, and must import Groups, SerializedName, and Mapping in the class but doing so is not required for the trait. Instead of just a yes/no answer, would appreciate an explanation why it is what it is. Thanks! <?php namespace App\Entity\Document; use ApiPlatform\Core\Annotation\ApiResource; use Doctrine\ORM\Mapping as ORM; use App\Entity\MultiTenenacy\PublicIdTenantTrait; // Must Groups, SerializedName, Owner be imported in this class or just PublicIdTenantTrait // use Symfony\Component\Serializer\Annotation\Groups; // use Symfony\Component\Serializer\Annotation\SerializedName;use // use App\Entity\Owner\Owner; /** * @ORM\Entity() * @ApiResource() */ class Document { use PublicIdTenantTrait; } <?php namespace App\Entity\MultiTenenacy; use ApiPlatform\Core\Annotation\ApiProperty; use Doctrine\ORM\Mapping as ORM; trait PublicIdTenantTrait { use PublicIdExtendedTenantTrait; /** * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") * @ApiProperty(identifier=false) * @ORM\Column(type="integer") */ private $id; public function getId(): ?int { return $this->id; } } <?php namespace App\Entity\MultiTenenacy; use ApiPlatform\Core\Annotation\ApiProperty; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\SerializedName; use Doctrine\ORM\Mapping as ORM; trait PublicIdExtendedTenantTrait { use TenantTrait; /** * @ORM\Column(type="integer") * @ApiProperty(identifier=true) * @Groups({"tenant_entity:read"}) * @SerializedName("id") */ private $publicId; public function getPublicId(): ?int { return $this->publicId; } public function setPublicId(int $publicId): PublicIdTenantInterface { $this->publicId = $publicId; return $this; } public function generatePublicId(): PublicIdTenantInterface { $this->getOwner()->setPublicId($this); return $this; } public function getPublicIdTag(): string { return lcfirst((new \ReflectionClass($this))->getShortName()).'Id'; } } <?php namespace App\Entity\MultiTenenacy; use Doctrine\ORM\Mapping as ORM; use App\Entity\Owner\Owner; trait TenantTrait { /** * inversedBy performed in child where required * @ORM\ManyToOne(targetEntity=Owner::class) * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") */ private $owner; public function getOwner(): ?Owner { return $this->owner; } public function setOwner(?Owner $owner): TenantInterface { $this->owner = $owner; return $this; } }
  8. Thanks requinix, Maybe but not sure. Will need to discuss with others. Think I am going to use what I learned here for something else. Have so many dang duplicated photos it stresses me to even attempt to organize them. Should be fairly easy to sort by size and then compare. But then I will want to read the meta data and such. Maybe another day... Appreciate the help.
  9. There are two types of users: vendor users and end users. Vendor users will be uploading files during the project execution and the path where they were posted will remain the path that will retrieve them. End users will later inherit the documents and will only care about quickly getting documents about what they care about. They may still care about whether it was uploaded 10 different times and for which project it was uploaded under, but will not wish to take time determining whether they are looking at the same or different files, and instead will be presented with just the unique files along with the various places it was uploaded.
  10. I agree and the primary reason is to improve the user experience regarding identical files. Various users will be uploading various documents and these documents will be associated with multiple scopes and these scopes will be associated with multiple projects and these projects will be associated with multiple assets. The majority of the documents will be PDF's and will often be downloaded from the same source and be identical but will likely have different filenames. When the project is over, other users will need to access the documents and will perform searches based on things they understand (i.e. the project, scope, and/or asset) and not by the filename which they wouldn't know. When returning the search results, I don't want to have them need to look at a bunch of identical documents but only the unique ones. The only way I could think of doing this is decouple the physical file from the document. Of course, this approach will not help with scanned documents but hopefully will be good enough. Can you think of a better way? Thanks
  11. Thanks requinix and mac_gyver, Sounds like going with MD5 and then some additional checks is the route to go. I would like to provide a little more context and explore a related topic. The application for documentation management and is multitenancy where each tenant will only have access to their own documents. That being said, if two files owned by two tenants is the same string of bits, only the user_provided_filename and uploaded_at belongs to the tenant and the physical file belongs to both of them. My schema will look something like the following, and the physical file will not be exposed as a resource but will instead use read_file() or maybe X-Sendfile, etc to expose them. document id (PK) tenant_id (FK) user_provided_filename (string) uploaded_at (datatime) physical_file_id (datatype TBD and FK to physical_file.id) file_storage_location, file size, media type (NOT INCLUDED) physical_file id (TBD) hash (TBD whether needed and if so what the unique strategy should be) size (int) media_type_id (int FK to media_type_id or maybe use media_type as a natural key but probably not) file_storage_location (string. TBD whether required) user_provided_filename, uploaded_at, tenant_id (NOT INCLUDED) Originally, I was contemplating using the files hash as the physical_file's primary key. And maybe get rid of file_storage_location and using the first four bytes of the hash as the root directory, next four a sub directory, and then save the file with the name as the hash and no extension. But this won't work based on both of your comments as I might have duplicate hashes. So, now I am considering making physical_file's primary key an auto-increment integer, including the hash column with an index but not a unique index (not even with size). When a new document is uploaded, I will get its MD5 hash and will query the DB for existing records with the same hash, size, and media-type (agree with media-type?). If one or more files exist, I will compare the content against each until I get a match and return the ID to be stored in the documents table. If I don't have a match, I will store the file on disk using maybe its PK appended by a ".tbd" extension (I know using the PK outside its intended use in the DB is often frowned on but seems reasonable). For a directory structure, maybe store files with ID from 1 to 10000 in directory "dir-1-to-10000", etc (or 1 to 1000?). Seem reasonable? Thanks
  12. Thanks gw1500se, Looks like I can go with MD5 and also invest $1 in the lottery as insurance. Why do you recommend going with MD5 and not SHA-1 (or even SHA-256) from the get-go? I didn't say so but the frequency of uploading files will be fairly low. Thanks requeinx, For my application, duplicates will be very likely as users will often upload the same document for multiple opportunities. Would you still recommend also comparing the size (likely will include both the hash, size, and mime type in the query) and the content? Surprisingly to me, it takes about 5 times longer to calculate two files hashes (granted I will only need to do one because the other is in the DB) that to compare content using the both functions I showed, and seems like a small performance hit for some peace of mind and have no issuing doing so.
  13. When a file is uploaded, I wish to determine whether an existing identical file (regardless of what it is named or what extension it has) already exists and if so don't save the newly uploaded file but just point it to the existing one. My primary reason for doing so is not really to save hard drive space but to be able to manage duplicate documents. One option is to store a hash of the documents in the DB and when a new document is uploaded, query the DB to see if an identical hash exists. How certain can one be that two hashes will never be duplicated? Another option is to compare the byte stream. For this, I would first query the DB to see if a file with same size and media type exists, and then compare the document to all existing files which have that same criteria. Or many some other approach? Recommendations? Thanks <?php error_reporting(E_ALL); ini_set('display_startup_errors', 1); ini_set('display_errors', 1); function compareFilesTest(string $file_a, string $file_b) { $time = microtime(true); display($time, $file_a, $file_b, 'compareFilesTest', compareFiles($file_a, $file_b)); } function compareFilesTest2(string $file_a, string $file_b) { $time = microtime(true); display($time, $file_a, $file_b, 'compareFilesTest2', identical($file_a, $file_b)); } function compareFilesHashTest(string $file_a, string $file_b, string $algo = 'md5') { $time = microtime(true); display($time, $file_a, $file_b, 'compareFilesHashTest', hash_file($algo, $file_a)===hash_file($algo, $file_b), $algo); } function display(float $time, string $file_a, string $file_b, string $test, bool $status, string $algorithm=null) { printf("\n%s\nFile1: %s\nFile2: %s\nStatus: %s\nTime (uS): %d\n", $test.($algorithm?" ($algorithm)":''), $file_a, $file_b, $status?'EQUAL':'NOT EQUAL', 1000000*(microtime(true) - $time)); } function compareFiles(string $file_a, string $file_b):bool { if (filesize($file_a) == filesize($file_b)) { $fp_a = fopen($file_a, 'rb'); $fp_b = fopen($file_b, 'rb'); while (!feof($fp_a) && ($b = fread($fp_a, 4096)) !== false) { $b_b = fread($fp_b, 4096); if ($b !== $b_b) { fclose($fp_a); fclose($fp_b); return false; } } fclose($fp_a); fclose($fp_b); return true; } return false; } function identical($fileOne, $fileTwo) { if (filetype($fileOne) !== filetype($fileTwo)) return false; if (filesize($fileOne) !== filesize($fileTwo)) return false; if (! $fp1 = fopen($fileOne, 'rb')) return false; if (! $fp2 = fopen($fileTwo, 'rb')) { fclose($fp1); return false; } $same = true; while (! feof($fp1) and ! feof($fp2)) if (fread($fp1, 4096) !== fread($fp2, 4096)) { $same = false; break; } if (feof($fp1) !== feof($fp2)) $same = false; fclose($fp1); fclose($fp2); return $same; } $path = __DIR__.'/test_documents/'; //print_r(hash_algos()); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpg'); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c1c96440_MasterFormat-2016.pdf'); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'x602a9c07af00c_IMG_1225.jpg'); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpgx'); compareFilesHashTest($path.'file1.txt', $path.'file2.md'); compareFilesHashTest($path.'file1.txt', $path.'file3.txt'); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpg', 'sha256'); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c1c96440_MasterFormat-2016.pdf', 'sha256'); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'x602a9c07af00c_IMG_1225.jpg', 'sha256'); compareFilesHashTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpgx', 'sha256'); compareFilesHashTest($path.'file1.txt', $path.'file2.md', 'sha256'); compareFilesHashTest($path.'file1.txt', $path.'file3.txt', 'sha256'); compareFilesTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpg'); compareFilesTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c1c96440_MasterFormat-2016.pdf'); compareFilesTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'x602a9c07af00c_IMG_1225.jpg'); compareFilesTest($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpgx'); compareFilesTest($path.'file1.txt', $path.'file2.md'); compareFilesTest($path.'file1.txt', $path.'file3.txt'); compareFilesTest2($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpg'); compareFilesTest2($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c1c96440_MasterFormat-2016.pdf'); compareFilesTest2($path.'602a9c07af00c_IMG_1225.jpg', $path.'x602a9c07af00c_IMG_1225.jpg'); compareFilesTest2($path.'602a9c07af00c_IMG_1225.jpg', $path.'602a9c07af00c_IMG_1225.jpgx'); compareFilesTest2($path.'file1.txt', $path.'file2.md'); compareFilesTest2($path.'file1.txt', $path.'file3.txt');
  14. Neither did I for quite a while based on your advice. My main reason for starting to use them was being able to see all relevant information in one place (i.e. database and serialization). That being said, have special comments in code still kind of annoys me, and I like having this content divorced from the code. Still find it kind of odd that someone hasn't come up with a annotation formatter/validator. Guess much is based on what is using them, but still...
  15. Bad question or no answers? Does difficulty of formatting annotations annoy anyone other than me?
  16. I always struggle with keeping my annotations pretty. Just about ever IDE beautifies PHP, there are many online PHP beautifiers, and notepad++ and other apps are available. None of them seem to work with annotations. Also, would like to validate them at the same time. Anyone know of any plugins or websites which do this? I would be fine with just cutting and pasting just the comment block and it need not format the entire PHP script (I probably wouldn't even use the PHP portions as git would probably see changes). If nothing is available, suppose I could create one myself. Before doing so, however, would like to better understand best practices. For instance, how many spaces for indentations, what is acceptable to put inline (i.e. the @ORM\Table item should definitely not be on a single line), etc. Thank! /** * @ORM\Entity() * @ORM\Table(uniqueConstraints={@ORM\UniqueConstraint(name="unique_position_serie", columns={"test_chart_id", "position"}), @ORM\UniqueConstraint(name="unique_name_serie", columns={"test_chart_id", "name"})}) * @ApiResource( * collectionOperations={ * "get" = { * "method"="GET", * }, * "post" = { * } * }, * itemOperations={ * "get" = { * "openapi_context" = { * "parameters" = { * { * "name" = "nameOfQueryParameter", * "in" = "query", * "description" = "Description goes here", * "schema" = { * "type" = "string" * } * } * } * } * }, * "put" = { * }, * "patch" = { * }, * "delete" = { * } * } * ) */
  17. Using postgresql, not mysql. michael=# \d information_schema.key_column_usage View "information_schema.key_column_usage" Column | Type | Collation | Nullable | Default -------------------------------+------------------------------------+-----------+----------+--------- constraint_catalog | information_schema.sql_identifier | | | constraint_schema | information_schema.sql_identifier | | | constraint_name | information_schema.sql_identifier | | | table_catalog | information_schema.sql_identifier | | | table_schema | information_schema.sql_identifier | | | table_name | information_schema.sql_identifier | | | column_name | information_schema.sql_identifier | | | ordinal_position | information_schema.cardinal_number | | | position_in_unique_constraint | information_schema.cardinal_number | | | michael=# \d information_schema.table_constraints View "information_schema.table_constraints" Column | Type | Collation | Nullable | Default --------------------+-----------------------------------+-----------+----------+--------- constraint_catalog | information_schema.sql_identifier | | | constraint_schema | information_schema.sql_identifier | | | constraint_name | information_schema.sql_identifier | | | table_catalog | information_schema.sql_identifier | | | table_schema | information_schema.sql_identifier | | | table_name | information_schema.sql_identifier | | | constraint_type | information_schema.character_data | | | is_deferrable | information_schema.yes_or_no | | | initially_deferred | information_schema.yes_or_no | | | enforced | information_schema.yes_or_no | | | michael=# \d information_schema.constraint_column_usage View "information_schema.constraint_column_usage" Column | Type | Collation | Nullable | Default --------------------+-----------------------------------+-----------+----------+--------- table_catalog | information_schema.sql_identifier | | | table_schema | information_schema.sql_identifier | | | table_name | information_schema.sql_identifier | | | column_name | information_schema.sql_identifier | | | constraint_catalog | information_schema.sql_identifier | | | constraint_schema | information_schema.sql_identifier | | | constraint_name | information_schema.sql_identifier | | | michael=# \d information_schema.referential_constraints View "information_schema.referential_constraints" Column | Type | Collation | Nullable | Default ---------------------------+-----------------------------------+-----------+----------+--------- constraint_catalog | information_schema.sql_identifier | | | constraint_schema | information_schema.sql_identifier | | | constraint_name | information_schema.sql_identifier | | | unique_constraint_catalog | information_schema.sql_identifier | | | unique_constraint_schema | information_schema.sql_identifier | | | unique_constraint_name | information_schema.sql_identifier | | | match_option | information_schema.character_data | | | update_rule | information_schema.character_data | | | delete_rule | information_schema.character_data | | | michael=#
  18. Good morning Barand, I substituted "separator" with a comma and removed the prepared statement WHERE clause for constraint_schema, however, then found that information_schema.key_column_usage.referenced_column_name doesn't exist for me. Ah, just noticed your "Perhaps". Oh well, appreciate your response regardless.
  19. I am trying to get a list of all foreign key constraints and executed the following: SELECT kcu.table_name, kcu.column_name, rel_tco.table_name fk_table_name, ccu.column_name AS fk_column_name, tc.constraint_name FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage kcu ON tc.constraint_schema = kcu.constraint_schema AND tc.constraint_name = kcu.constraint_name INNER JOIN information_schema.constraint_column_usage AS ccu ON ccu.table_schema = tc.table_schema AND ccu.constraint_name = tc.constraint_name INNER JOIN information_schema.referential_constraints rco ON tc.constraint_schema = rco.constraint_schema AND tc.constraint_name = rco.constraint_name INNER JOIN information_schema.table_constraints rel_tco ON rco.unique_constraint_schema = rel_tco.constraint_schema AND rco.unique_constraint_name = rel_tco.constraint_name WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema = 'public' ORDER BY kcu.table_name, rel_tco.table_name; It is almost what I want but I am getting duplicates for tables with composite keys. table_name | column_name | fk_table_name | fk_column_name | constraint_name -------------------------------+--------------------------+-----------------------+----------------+------------------------------------ ... upload | guid | guid | guid | fk_17bde61f2b6fcfb2 upload | type | upload_type | mime | fk_17bde61f8cde57291d3960242858050 upload | mime | upload_type | type | fk_17bde61f8cde57291d3960242858050 upload | mime | upload_type | ext | fk_17bde61f8cde57291d3960242858050 upload | mime | upload_type | mime | fk_17bde61f8cde57291d3960242858050 upload | ext | upload_type | type | fk_17bde61f8cde57291d3960242858050 upload | ext | upload_type | ext | fk_17bde61f8cde57291d3960242858050 upload | ext | upload_type | mime | fk_17bde61f8cde57291d3960242858050 upload | type | upload_type | type | fk_17bde61f8cde57291d3960242858050 upload | type | upload_type | ext | fk_17bde61f8cde57291d3960242858050 ... What I would like to receive is this: table_name | column_name | fk_table_name | fk_column_name | constraint_name -------------------------------+--------------------------+-----------------------+----------------+------------------------------------ ... upload | guid | guid | guid | fk_17bde61f2b6fcfb2 upload | mime | upload_type | mime | fk_17bde61f8cde57291d3960242858050 upload | ext | upload_type | ext | fk_17bde61f8cde57291d3960242858050 upload | type | upload_type | type | fk_17bde61f8cde57291d3960242858050 ... Any recommendations? Thank you
  20. Hi Thomas, No direct answer, but have you tried logging/echoing/whatever at the server what it is receiving regarding url, body, headers, etc? Don't know the answer to your issues, but guarantee that if you are getting different results, you are sending a different request.
  21. If you are truly trying to send ?key={' . api_key . '}&email={' . email . '}, that is your error, and you really want to send ?key=yourApiKey&email=theemail@bla.com;
  22. Thank you requinix. Good to know I got two YESs, one MAYBE, and no NOs! It is not Doctrine I am fighting with. Actually know it pretty well. It is that confounding Symfony and associated bundles. I expect I am in the minority in this position, but I focused on SQL first, then PHP, then Doctrine, and only recently Symfony. For instance, I can easily have Doctrine generated SQL for class table inheritance or One-to-One. Inheritance using CTI CREATE TABLE animal ( id SERIAL NOT NULL, name VARCHAR(255) NOT NULL, sex VARCHAR(255) NOT NULL, weight INT NOT NULL, birthday DATE NOT NULL, color VARCHAR(255) NOT NULL, type VARCHAR(32) NOT NULL, PRIMARY KEY(id) ); CREATE TABLE cat ( id INT NOT NULL, likes_to_purr BOOLEAN NOT NULL, PRIMARY KEY(id) ); ALTER TABLE cat ADD CONSTRAINT FK_CAT FOREIGN KEY (id) REFERENCES animal (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; Composition using One-to-One CREATE TABLE animal ( id SERIAL NOT NULL, name VARCHAR(255) NOT NULL, sex VARCHAR(255) NOT NULL, weight INT NOT NULL, birthday DATE NOT NULL, color VARCHAR(255) NOT NULL, PRIMARY KEY(id) ); # animal_id is NOT NULL for Unidirectional and DEFAULT NULL for bidirectional CREATE TABLE cat ( id SERIAL NOT NULL, animal_id INT DEFAULT NULL, likes_to_purr BOOLEAN NOT NULL, PRIMARY KEY(id) ); CREATE UNIQUE INDEX UNIQ_CAT ON cat (animal_id); ALTER TABLE cat ADD CONSTRAINT FK_CAT FOREIGN KEY (animal_id) REFERENCES animal (id) NOT DEFERRABLE INITIALLY IMMEDIATE; I think the inheritance approach makes more sense, however, as I said API-Platform does not play well with inheritance and would like to consider the other approach. One question is whether it makes sense to have an Animal as a property in a Cat, Dog, Mouse. Animal while an entity and not abstract is not fully an animal, and is just part of the story. Maybe I just got to let it go. But also, I can't for instance get the animal with ID #123 and retrieve a cat because animal doesn't contain the cat ID (unless I make the one-to-ones bidirectional in which animal would need a property for cat, dog, and mouse where all would be NULL except one which doesn't seem right). That is why I proposed my unethical DNA solution. While I still have DB inheritance, my various DNA types don't share any properties other than an ID, so I don't "think" I will any problems with API-Platform. And I can make all concrete DNA classes implement an interface so that Animal can contain one dna property and not a separate property for each type. CREATE TABLE animal ( id INT NOT NULL, dna_id INT NOT NULL, name VARCHAR(255) NOT NULL, sex VARCHAR(255) NOT NULL, weight INT NOT NULL, birthday DATE NOT NULL, PRIMARY KEY(id) ); CREATE TABLE dna ( id INT NOT NULL, type VARCHAR(32) NOT NULL, PRIMARY KEY(id) ); CREATE TABLE cat_dna ( id INT NOT NULL, likes_to_purr BOOLEAN NOT NULL, PRIMARY KEY(id) ); CREATE TABLE dog_dna ( id INT NOT NULL, plays_fetch BOOLEAN NOT NULL, doghouse_color VARCHAR(255) NOT NULL, PRIMARY KEY(id) ); CREATE UNIQUE INDEX UNIQ_ANIMAL_DNA_ID ON animal (dna_id); ALTER TABLE animal ADD CONSTRAINT FK_DNA FOREIGN KEY (dna_id) REFERENCES dna (id) NOT DEFERRABLE INITIALLY IMMEDIATE; I know Animal is a made up scenario, however, it is the same as my real inject a Point with a given type of data source to get a PhysicalPoint, VirtualPoint, or TransformedPoint. Sorry in advance if I am being way too obtuse. PS. Your below example is totally obviously, however, that being said I've never done it and like it! BusinessAnimal can deal with DatabaseAnimal and BusinessCat can deal with DatabaseCat without needing a bunch of intermediary getters. Thanks! class BusinessCat extends BusinessAnimal { private $cat; public function __construct(DatabaseCat $cat) { parent::__construct($cat->animal()); $this->cat = $cat; } }
  23. DatabaseCat is the same thing as some would have called EntityCat, and some might have named DatabaseCat's animal() method as getAnimal(), true? And as shown in your BusinessCat's constructor, DatabaseCat $cat contains an instance of DatabaseAnimal. And to get it their in the first place, I would use composition: $databaseAnimal = new DatabaseAnimal($dbAnimProp1, $dpAnimProp1); $databaseCat = new DatabaseCat($dbCatProp1, $dbCatProp2, $databaseAnimal); Just making sure I am on the right page.
  24. What information do you wish to obtain from your array? Assuming your array is named $yourArray, then you can access elements in it using something like $yourArray[0] which will also be an array or $yourArray[0]['id'] which will return 5. Try it out and use either print_r() or var_dump() to view the results.
  25. mysqli_query wants at least two things, right? How many did you give it? Look at the second line of your original post. Now, looking below tells you exactly what it wants. Some sort of link and a query and an optional resultmode (in that order). Which one didn't you give it? mysqli_query ( mysqli $link , string $query , int $resultmode = MYSQLI_STORE_RESULT ) : mixed
×
×
  • 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.