diff --git a/composer.json b/composer.json index 1827d26..6b478a9 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "doctrine/doctrine-migrations-bundle": "^3.2", "doctrine/orm": "^2.16", "emcconville/google-map-polyline-encoding-tool": "^1.3", + "league/flysystem-bundle": "^3.2", "lexik/jwt-authentication-bundle": "^2.19", "nelmio/cors-bundle": "^2.3", "oilstone/php-rsql-parser": "^1.0", diff --git a/composer.lock b/composer.lock index 6a4f9dc..2beaa9d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "993e44379322a5074c2650973a2f602f", + "content-hash": "58d0e9ef8bba6cdea92e8c7f1f905077", "packages": [ { "name": "brick/geo", @@ -1821,6 +1821,272 @@ ], "time": "2023-02-25T21:35:16+00:00" }, + { + "name": "league/flysystem", + "version": "3.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729", + "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5", + "async-aws/simple-s3": "^1.1", + "aws/aws-sdk-php": "^3.220.0", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "microsoft/azure-storage-blob": "^1.1", + "phpseclib/phpseclib": "^3.0.14", + "phpstan/phpstan": "^0.12.26", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.16.0" + }, + "funding": [ + { + "url": "https://ecologi.com/frankdejonge", + "type": "custom" + }, + { + "url": "https://github.com/frankdejonge", + "type": "github" + } + ], + "time": "2023-09-07T19:22:17+00:00" + }, + { + "name": "league/flysystem-bundle", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-bundle.git", + "reference": "c056bef0e8e0cdfb349e568d69e8337ce17ef6e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-bundle/zipball/c056bef0e8e0cdfb349e568d69e8337ce17ef6e1", + "reference": "c056bef0e8e0cdfb349e568d69e8337ce17ef6e1", + "shasum": "" + }, + "require": { + "league/flysystem": "^3.0", + "php": ">=8.0", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/http-kernel": "^5.4|^6.0", + "symfony/options-resolver": "^5.4|^6.0" + }, + "require-dev": { + "league/flysystem-async-aws-s3": "^3.1", + "league/flysystem-aws-s3-v3": "^3.1", + "league/flysystem-azure-blob-storage": "^3.1", + "league/flysystem-ftp": "^3.1", + "league/flysystem-google-cloud-storage": "^3.1", + "league/flysystem-memory": "^3.1", + "league/flysystem-sftp-v3": "^3.1", + "symfony/dotenv": "^5.4|^6.0", + "symfony/framework-bundle": "^5.4|^6.0", + "symfony/phpunit-bridge": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0", + "symfony/yaml": "^5.4|^6.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "League\\FlysystemBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Titouan Galopin", + "email": "galopintitouan@gmail.com" + } + ], + "description": "Symfony bundle integrating Flysystem into Symfony 5.4+ applications", + "support": { + "issues": "https://github.com/thephpleague/flysystem-bundle/issues", + "source": "https://github.com/thephpleague/flysystem-bundle/tree/3.2.0" + }, + "time": "2023-08-21T15:19:15+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "ec7383f25642e6fd4bb0c9554fc2311245391781" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/ec7383f25642e6fd4bb0c9554fc2311245391781", + "reference": "ec7383f25642e6fd4bb0c9554fc2311245391781", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem-local/issues", + "source": "https://github.com/thephpleague/flysystem-local/tree/3.16.0" + }, + "funding": [ + { + "url": "https://ecologi.com/frankdejonge", + "type": "custom" + }, + { + "url": "https://github.com/frankdejonge", + "type": "github" + } + ], + "time": "2023-08-30T10:23:59+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/a6dfb1194a2946fcdc1f38219445234f65b35c96", + "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.13.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2023-08-05T12:09:49+00:00" + }, { "name": "lexik/jwt-authentication-bundle", "version": "v2.19.1", diff --git a/config/bundles.php b/config/bundles.php index 59c0dc8..687b99b 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -16,4 +16,5 @@ Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true], Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true], Bazinga\GeocoderBundle\BazingaGeocoderBundle::class => ['all' => true], + League\FlysystemBundle\FlysystemBundle::class => ['all' => true], ]; diff --git a/config/packages/flysystem.yaml b/config/packages/flysystem.yaml new file mode 100644 index 0000000..d104e2e --- /dev/null +++ b/config/packages/flysystem.yaml @@ -0,0 +1,7 @@ +# Read the documentation at https://github.com/thephpleague/flysystem-bundle/blob/master/docs/1-getting-started.md +flysystem: + storages: + default.storage: + adapter: 'local' + options: + directory: '%kernel.project_dir%/var/storage/default' diff --git a/migrations/Version20230918080220.php b/migrations/Version20230918080220.php new file mode 100644 index 0000000..410d5ff --- /dev/null +++ b/migrations/Version20230918080220.php @@ -0,0 +1,107 @@ +addSql('CREATE TABLE address (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', coordinate_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', first_name VARCHAR(64) DEFAULT NULL, last_name VARCHAR(64) DEFAULT NULL, phone_number VARCHAR(32) DEFAULT NULL, email_address VARCHAR(64) DEFAULT NULL, company VARCHAR(64) DEFAULT NULL, country_code VARCHAR(3) NOT NULL, province_code VARCHAR(16) DEFAULT NULL, province_name VARCHAR(64) DEFAULT NULL, city VARCHAR(64) DEFAULT NULL, street VARCHAR(128) DEFAULT NULL, postcode VARCHAR(8) DEFAULT NULL, updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', google_id VARCHAR(255) DEFAULT NULL, formatted VARCHAR(255) DEFAULT NULL, arrive_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', dtype VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_D4E6F8198BBE953 (coordinate_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE address_coordinates (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', latitude DOUBLE PRECISION NOT NULL, longitude DOUBLE PRECISION NOT NULL, altitude DOUBLE PRECISION DEFAULT NULL, accuracy DOUBLE PRECISION DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE driver (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', user_account_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', verified TINYINT(1) DEFAULT 1 NOT NULL, UNIQUE INDEX UNIQ_11667CD93C0C9956 (user_account_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE product (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', price_id BINARY(16) DEFAULT NULL COMMENT \'(DC2Type:ulid)\', dimension_id BINARY(16) DEFAULT NULL COMMENT \'(DC2Type:ulid)\', title VARCHAR(64) NOT NULL, description VARCHAR(255) DEFAULT NULL, weight INT DEFAULT 0 NOT NULL, dtype VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_D34A04ADD614C7E7 (price_id), UNIQUE INDEX UNIQ_D34A04AD277428AD (dimension_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE product_category (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', code VARCHAR(32) NOT NULL, name VARCHAR(64) NOT NULL, short_name VARCHAR(16) DEFAULT NULL, icon_image VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE product_dimension (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', length INT NOT NULL, width INT NOT NULL, height INT NOT NULL, unit VARCHAR(16) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE product_price (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', currency VARCHAR(3) NOT NULL, amount INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE route (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', code VARCHAR(64) NOT NULL, name VARCHAR(128) DEFAULT NULL, start_point POINT DEFAULT NULL COMMENT \'(DC2Type:Point)\', end_point POINT DEFAULT NULL COMMENT \'(DC2Type:Point)\', start_place_id VARCHAR(255) DEFAULT NULL, end_place_id VARCHAR(255) DEFAULT NULL, polyline LINESTRING NOT NULL COMMENT \'(DC2Type:LineString)\', distance INT DEFAULT NULL, duration INT DEFAULT NULL, updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE route_segment (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE shipment (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', owner_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', billing_address_id BINARY(16) DEFAULT NULL COMMENT \'(DC2Type:ulid)\', origin_address_id BINARY(16) DEFAULT NULL COMMENT \'(DC2Type:ulid)\', destination_address_id BINARY(16) DEFAULT NULL COMMENT \'(DC2Type:ulid)\', budget_id BINARY(16) DEFAULT NULL COMMENT \'(DC2Type:ulid)\', route_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', type VARCHAR(64) NOT NULL, updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', status VARCHAR(64) DEFAULT \'PENDING\' NOT NULL, pickup_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', delivery_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', code VARCHAR(32) NOT NULL, INDEX IDX_2CB20DC7E3C61F9 (owner_id), INDEX IDX_2CB20DC79D0C0E4 (billing_address_id), INDEX IDX_2CB20DC4C6CF538 (origin_address_id), INDEX IDX_2CB20DCA88E34C7 (destination_address_id), UNIQUE INDEX UNIQ_2CB20DC36ABA6B8 (budget_id), INDEX IDX_2CB20DC34ECB4E6 (route_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE shipment_budget (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', currency VARCHAR(3) NOT NULL, dtype VARCHAR(255) NOT NULL, price INT DEFAULT NULL, min_price INT DEFAULT NULL, max_price INT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE shipment_driver_bid (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', shipment_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', driver_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', price INT NOT NULL, currency_code VARCHAR(3) NOT NULL, title VARCHAR(64) DEFAULT NULL, description VARCHAR(1000) DEFAULT NULL, status VARCHAR(64) NOT NULL, updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_9DD32C17BE036FC (shipment_id), INDEX IDX_9DD32C1C3423909 (driver_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE shipment_item (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', shipment_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', product_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', quantity INT NOT NULL, description VARCHAR(255) DEFAULT NULL, updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_1C573407BE036FC (shipment_id), INDEX IDX_1C573404584665A (product_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE `user` (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', email VARCHAR(180) NOT NULL, roles LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, first_name VARCHAR(64) NOT NULL, last_name VARCHAR(64) NOT NULL, phone VARCHAR(64) DEFAULT NULL, is_verified TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_address (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', owner_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', INDEX IDX_5543718B7E3C61F9 (owner_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_product (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', owner_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', INDEX IDX_8B471AA77E3C61F9 (owner_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE vehicle (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', type_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', driver_id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', status VARCHAR(32) NOT NULL, updated_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_1B80E486C54C8C93 (type_id), INDEX IDX_1B80E486C3423909 (driver_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE vehicle_type (id BINARY(16) NOT NULL COMMENT \'(DC2Type:ulid)\', code VARCHAR(32) NOT NULL, short_name VARCHAR(12) NOT NULL, name VARCHAR(64) NOT NULL, icon_image VARCHAR(255) DEFAULT NULL, primary_image VARCHAR(255) DEFAULT NULL, cover_image VARCHAR(255) DEFAULT NULL, client_note VARCHAR(255) DEFAULT NULL, driver_note VARCHAR(255) DEFAULT NULL, description LONGTEXT DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE messenger_messages (id BIGINT AUTO_INCREMENT NOT NULL, body LONGTEXT NOT NULL, headers LONGTEXT NOT NULL, queue_name VARCHAR(190) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', available_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', delivered_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_75EA56E0FB7336F0 (queue_name), INDEX IDX_75EA56E0E3BD61CE (available_at), INDEX IDX_75EA56E016BA31DB (delivered_at), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE address ADD CONSTRAINT FK_D4E6F8198BBE953 FOREIGN KEY (coordinate_id) REFERENCES address_coordinates (id)'); + $this->addSql('ALTER TABLE driver ADD CONSTRAINT FK_11667CD93C0C9956 FOREIGN KEY (user_account_id) REFERENCES `user` (id)'); + $this->addSql('ALTER TABLE product ADD CONSTRAINT FK_D34A04ADD614C7E7 FOREIGN KEY (price_id) REFERENCES product_price (id)'); + $this->addSql('ALTER TABLE product ADD CONSTRAINT FK_D34A04AD277428AD FOREIGN KEY (dimension_id) REFERENCES product_dimension (id)'); + $this->addSql('ALTER TABLE shipment ADD CONSTRAINT FK_2CB20DC7E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)'); + $this->addSql('ALTER TABLE shipment ADD CONSTRAINT FK_2CB20DC79D0C0E4 FOREIGN KEY (billing_address_id) REFERENCES user_address (id)'); + $this->addSql('ALTER TABLE shipment ADD CONSTRAINT FK_2CB20DC4C6CF538 FOREIGN KEY (origin_address_id) REFERENCES user_address (id)'); + $this->addSql('ALTER TABLE shipment ADD CONSTRAINT FK_2CB20DCA88E34C7 FOREIGN KEY (destination_address_id) REFERENCES user_address (id)'); + $this->addSql('ALTER TABLE shipment ADD CONSTRAINT FK_2CB20DC36ABA6B8 FOREIGN KEY (budget_id) REFERENCES shipment_budget (id)'); + $this->addSql('ALTER TABLE shipment ADD CONSTRAINT FK_2CB20DC34ECB4E6 FOREIGN KEY (route_id) REFERENCES route (id)'); + $this->addSql('ALTER TABLE shipment_driver_bid ADD CONSTRAINT FK_9DD32C17BE036FC FOREIGN KEY (shipment_id) REFERENCES shipment (id)'); + $this->addSql('ALTER TABLE shipment_driver_bid ADD CONSTRAINT FK_9DD32C1C3423909 FOREIGN KEY (driver_id) REFERENCES driver (id)'); + $this->addSql('ALTER TABLE shipment_item ADD CONSTRAINT FK_1C573407BE036FC FOREIGN KEY (shipment_id) REFERENCES shipment (id)'); + $this->addSql('ALTER TABLE shipment_item ADD CONSTRAINT FK_1C573404584665A FOREIGN KEY (product_id) REFERENCES user_product (id)'); + $this->addSql('ALTER TABLE user_address ADD CONSTRAINT FK_5543718B7E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)'); + $this->addSql('ALTER TABLE user_address ADD CONSTRAINT FK_5543718BBF396750 FOREIGN KEY (id) REFERENCES address (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE user_product ADD CONSTRAINT FK_8B471AA77E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)'); + $this->addSql('ALTER TABLE user_product ADD CONSTRAINT FK_8B471AA7BF396750 FOREIGN KEY (id) REFERENCES product (id) ON DELETE CASCADE'); + $this->addSql('ALTER TABLE vehicle ADD CONSTRAINT FK_1B80E486C54C8C93 FOREIGN KEY (type_id) REFERENCES vehicle_type (id)'); + $this->addSql('ALTER TABLE vehicle ADD CONSTRAINT FK_1B80E486C3423909 FOREIGN KEY (driver_id) REFERENCES driver (id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE address DROP FOREIGN KEY FK_D4E6F8198BBE953'); + $this->addSql('ALTER TABLE driver DROP FOREIGN KEY FK_11667CD93C0C9956'); + $this->addSql('ALTER TABLE product DROP FOREIGN KEY FK_D34A04ADD614C7E7'); + $this->addSql('ALTER TABLE product DROP FOREIGN KEY FK_D34A04AD277428AD'); + $this->addSql('ALTER TABLE shipment DROP FOREIGN KEY FK_2CB20DC7E3C61F9'); + $this->addSql('ALTER TABLE shipment DROP FOREIGN KEY FK_2CB20DC79D0C0E4'); + $this->addSql('ALTER TABLE shipment DROP FOREIGN KEY FK_2CB20DC4C6CF538'); + $this->addSql('ALTER TABLE shipment DROP FOREIGN KEY FK_2CB20DCA88E34C7'); + $this->addSql('ALTER TABLE shipment DROP FOREIGN KEY FK_2CB20DC36ABA6B8'); + $this->addSql('ALTER TABLE shipment DROP FOREIGN KEY FK_2CB20DC34ECB4E6'); + $this->addSql('ALTER TABLE shipment_driver_bid DROP FOREIGN KEY FK_9DD32C17BE036FC'); + $this->addSql('ALTER TABLE shipment_driver_bid DROP FOREIGN KEY FK_9DD32C1C3423909'); + $this->addSql('ALTER TABLE shipment_item DROP FOREIGN KEY FK_1C573407BE036FC'); + $this->addSql('ALTER TABLE shipment_item DROP FOREIGN KEY FK_1C573404584665A'); + $this->addSql('ALTER TABLE user_address DROP FOREIGN KEY FK_5543718B7E3C61F9'); + $this->addSql('ALTER TABLE user_address DROP FOREIGN KEY FK_5543718BBF396750'); + $this->addSql('ALTER TABLE user_product DROP FOREIGN KEY FK_8B471AA77E3C61F9'); + $this->addSql('ALTER TABLE user_product DROP FOREIGN KEY FK_8B471AA7BF396750'); + $this->addSql('ALTER TABLE vehicle DROP FOREIGN KEY FK_1B80E486C54C8C93'); + $this->addSql('ALTER TABLE vehicle DROP FOREIGN KEY FK_1B80E486C3423909'); + $this->addSql('DROP TABLE address'); + $this->addSql('DROP TABLE address_coordinates'); + $this->addSql('DROP TABLE driver'); + $this->addSql('DROP TABLE product'); + $this->addSql('DROP TABLE product_category'); + $this->addSql('DROP TABLE product_dimension'); + $this->addSql('DROP TABLE product_price'); + $this->addSql('DROP TABLE route'); + $this->addSql('DROP TABLE route_segment'); + $this->addSql('DROP TABLE shipment'); + $this->addSql('DROP TABLE shipment_budget'); + $this->addSql('DROP TABLE shipment_driver_bid'); + $this->addSql('DROP TABLE shipment_item'); + $this->addSql('DROP TABLE `user`'); + $this->addSql('DROP TABLE user_address'); + $this->addSql('DROP TABLE user_product'); + $this->addSql('DROP TABLE vehicle'); + $this->addSql('DROP TABLE vehicle_type'); + $this->addSql('DROP TABLE messenger_messages'); + } +} diff --git a/migrations/Version20230918152734.php b/migrations/Version20230918152734.php new file mode 100644 index 0000000..3ee2522 --- /dev/null +++ b/migrations/Version20230918152734.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE product ADD category_id BINARY(16) DEFAULT NULL COMMENT \'(DC2Type:ulid)\''); + $this->addSql('ALTER TABLE product ADD CONSTRAINT FK_D34A04AD12469DE2 FOREIGN KEY (category_id) REFERENCES product_category (id)'); + $this->addSql('CREATE INDEX IDX_D34A04AD12469DE2 ON product (category_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE product DROP FOREIGN KEY FK_D34A04AD12469DE2'); + $this->addSql('DROP INDEX IDX_D34A04AD12469DE2 ON product'); + $this->addSql('ALTER TABLE product DROP category_id'); + } +} diff --git a/src/Entity/Addressing/Address.php b/src/Entity/Addressing/Address.php index e3015d2..9189d5e 100644 --- a/src/Entity/Addressing/Address.php +++ b/src/Entity/Addressing/Address.php @@ -8,11 +8,13 @@ use Symfony\Bridge\Doctrine\Types\UlidType; use Symfony\Component\Intl\Countries; use Symfony\Component\Uid\Ulid; +use Overblog\GraphQLBundle\Resolver\TypeResolver; +use GraphQL\Type\Definition\Type; -#[GQL\Type()] +#[GQL\TypeInterface(resolveType:'value.resolveGQLType(typeResolver)')] #[ORM\InheritanceType("JOINED")] #[ORM\Entity(repositoryClass: AddressRepository::class)] -class Address +abstract class Address { #[GQL\Field(type: 'Ulid')] @@ -349,4 +351,5 @@ public function getFormattedRepresentaion(): string } + abstract function resolveGQLType( TypeResolver $typeResolver): Type; } diff --git a/src/Entity/Addressing/UserAddress.php b/src/Entity/Addressing/UserAddress.php index 01619d4..3794c9e 100644 --- a/src/Entity/Addressing/UserAddress.php +++ b/src/Entity/Addressing/UserAddress.php @@ -6,6 +6,8 @@ use App\Repository\Addressing\UserAddressRepository; use Doctrine\ORM\Mapping as ORM; use Overblog\GraphQLBundle\Annotation as GQL; +use GraphQL\Type\Definition\Type; +use Overblog\GraphQLBundle\Resolver\TypeResolver; #[GQL\Type()] #[ORM\Entity(repositoryClass: UserAddressRepository::class)] @@ -28,4 +30,8 @@ public function setOwner(?User $owner): static return $this; } + public function resolveGQLType(TypeResolver $typeResolver): Type + { + return $typeResolver->resolve('UserAddress'); + } } diff --git a/src/Entity/Catalog/Product.php b/src/Entity/Catalog/Product.php index 08621ac..6789a65 100644 --- a/src/Entity/Catalog/Product.php +++ b/src/Entity/Catalog/Product.php @@ -7,11 +7,13 @@ use Symfony\Bridge\Doctrine\Types\UlidType; use Symfony\Component\Uid\Ulid; use Overblog\GraphQLBundle\Annotation as GQL; +use Overblog\GraphQLBundle\Resolver\TypeResolver; +use GraphQL\Type\Definition\Type; -#[GQL\Type()] +#[GQL\TypeInterface(resolveType:'value.resolveGQLType(typeResolver)')] #[ORM\Entity(repositoryClass: ProductRepository::class)] #[ORM\InheritanceType("JOINED")] -class Product +abstract class Product { #[GQL\Field(type: "Ulid")] #[ORM\Id] @@ -40,6 +42,10 @@ class Product #[ORM\Column(options:['default' => 0])] private ?int $weight = null; + #[GQL\Field()] + #[ORM\ManyToOne(inversedBy: 'products')] + private ?ProductCategory $category = null; + public function getId(): ?Ulid { return $this->id; @@ -104,4 +110,19 @@ public function setWeight(int $weight): static return $this; } + + + abstract function resolveGQLType( TypeResolver $typeResolver): Type; + + public function getCategory(): ?ProductCategory + { + return $this->category; + } + + public function setCategory(?ProductCategory $category): static + { + $this->category = $category; + + return $this; + } } diff --git a/src/Entity/Catalog/ProductCategory.php b/src/Entity/Catalog/ProductCategory.php new file mode 100644 index 0000000..aed2fb6 --- /dev/null +++ b/src/Entity/Catalog/ProductCategory.php @@ -0,0 +1,132 @@ +products = new ArrayCollection(); + } + + public function getId(): ?Ulid + { + return $this->id; + } + + public function getCode(): ?string + { + return $this->code; + } + + public function setCode(string $code): static + { + $this->code = $code; + + return $this; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + public function getShortName(): ?string + { + return $this->shortName; + } + + public function setShortName(?string $shortName): static + { + $this->shortName = $shortName; + + return $this; + } + + public function getIconImage(): ?string + { + return $this->iconImage; + } + + public function setIconImage(?string $iconImage): static + { + $this->iconImage = $iconImage; + + return $this; + } + + /** + * @return Collection + */ + public function getProducts(): Collection + { + return $this->products; + } + + public function addProduct(Product $product): static + { + if (!$this->products->contains($product)) { + $this->products->add($product); + $product->setCategory($this); + } + + return $this; + } + + public function removeProduct(Product $product): static + { + if ($this->products->removeElement($product)) { + // set the owning side to null (unless already changed) + if ($product->getCategory() === $this) { + $product->setCategory(null); + } + } + + return $this; + } +} diff --git a/src/Entity/Catalog/UserProduct.php b/src/Entity/Catalog/UserProduct.php index 18db45b..63d00d2 100644 --- a/src/Entity/Catalog/UserProduct.php +++ b/src/Entity/Catalog/UserProduct.php @@ -6,12 +6,14 @@ use App\Repository\Catalog\UserProductRepository; use Doctrine\ORM\Mapping as ORM; use Overblog\GraphQLBundle\Annotation as GQL; +use GraphQL\Type\Definition\Type; +use Overblog\GraphQLBundle\Resolver\TypeResolver; #[GQL\Type()] #[ORM\Entity(repositoryClass: UserProductRepository::class)] class UserProduct extends Product { - + #[GQL\Field()] #[ORM\ManyToOne] #[ORM\JoinColumn(nullable: false)] @@ -28,4 +30,9 @@ public function setOwner(?User $owner): static return $this; } + + public function resolveGQLType(TypeResolver $typeResolver): Type + { + return $typeResolver->resolve('UserProduct'); + } } diff --git a/src/Entity/Shipment/Shipment.php b/src/Entity/Shipment/Shipment.php index 8511f50..98bfc30 100644 --- a/src/Entity/Shipment/Shipment.php +++ b/src/Entity/Shipment/Shipment.php @@ -322,4 +322,15 @@ public function setCode(string $code): static return $this; } + + #[GQL\Field(name:'weight')] + public function calculateWeight(): int{ + $weight = 0; + foreach($this->getItems() as $item){ + if($iWeight = $item->getProduct()?->getWeight()){ + $weight += $iWeight; + } + } + return $weight; + } } diff --git a/src/Entity/Shipment/ShipmentFixedBudget.php b/src/Entity/Shipment/ShipmentFixedBudget.php index 1ea8c2e..3e3db0b 100644 --- a/src/Entity/Shipment/ShipmentFixedBudget.php +++ b/src/Entity/Shipment/ShipmentFixedBudget.php @@ -3,9 +3,9 @@ namespace App\Entity\Shipment; use App\Repository\Shipment\ShipmentFixedBudgetRepository; -use GraphQL\Type\Definition\Type; use Doctrine\ORM\Mapping as ORM; use Overblog\GraphQLBundle\Annotation as GQL; +use GraphQL\Type\Definition\Type; use Overblog\GraphQLBundle\Resolver\TypeResolver; use Symfony\Component\Validator\Constraints as Assert; diff --git a/src/Entity/Vehicle/Vehicle.php b/src/Entity/Vehicle/Vehicle.php index 6cb5f70..8da8e09 100644 --- a/src/Entity/Vehicle/Vehicle.php +++ b/src/Entity/Vehicle/Vehicle.php @@ -5,33 +5,50 @@ use App\Entity\Account\Driver; use App\Repository\Vehicle\VehicleRepository; use Doctrine\ORM\Mapping as ORM; +use Overblog\GraphQLBundle\Annotation as GQL; +use Symfony\Bridge\Doctrine\Types\UlidType; +use Symfony\Component\Uid\Ulid; +#[GQL\Type()] #[ORM\Entity(repositoryClass: VehicleRepository::class)] class Vehicle { + #[GQL\Field(type:'Ulid')] #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] + #[ORM\Column(type: UlidType::NAME, unique: true)] + #[ORM\GeneratedValue(strategy: 'CUSTOM')] + #[ORM\CustomIdGenerator(class: 'doctrine.ulid_generator')] private ?int $id = null; + #[GQL\Field()] #[ORM\ManyToOne] #[ORM\JoinColumn(nullable: false)] private ?VehicleType $type = null; + #[GQL\Field()] #[ORM\ManyToOne] #[ORM\JoinColumn(nullable: false)] private ?Driver $driver = null; - #[ORM\Column(length: 32)] - private ?string $status = null; + #[GQL\Field()] + #[ORM\Column(length: 32, enumType: VehicleStatus::class)] + private ?VehicleStatus $status = VehicleStatus::PENDING; + #[GQL\Field(type: 'DateTime')] #[ORM\Column(nullable: true)] private ?\DateTimeImmutable $updatedAt = null; + #[GQL\Field(type: 'DateTime')] #[ORM\Column] private ?\DateTimeImmutable $createdAt = null; - public function getId(): ?int + + public function __construct(?Ulid $id = null){ + $this->id = $id; + $this->createdAt = new \DateTimeImmutable(); + } + + public function getId(): ?Ulid { return $this->id; } @@ -60,12 +77,12 @@ public function setDriver(?Driver $driver): static return $this; } - public function getStatus(): ?string + public function getStatus(): ?VehicleStatus { return $this->status; } - public function setStatus(string $status): static + public function setStatus(VehicleStatus $status): static { $this->status = $status; diff --git a/src/Entity/Vehicle/VehicleStatus.php b/src/Entity/Vehicle/VehicleStatus.php new file mode 100644 index 0000000..9c63ad7 --- /dev/null +++ b/src/Entity/Vehicle/VehicleStatus.php @@ -0,0 +1,17 @@ +id; } @@ -107,4 +132,40 @@ public function setCoverImage(?string $coverImage): static return $this; } + + public function getClientNote(): ?string + { + return $this->clientNote; + } + + public function setClientNote(?string $clientNote): static + { + $this->clientNote = $clientNote; + + return $this; + } + + public function getDriverNote(): ?string + { + return $this->driverNote; + } + + public function setDriverNote(?string $driverNote): static + { + $this->driverNote = $driverNote; + + return $this; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } } diff --git a/src/GraphQL/Account/Input/UserInput.php b/src/GraphQL/Account/Input/UserInput.php index 6a422e9..4aea5a9 100644 --- a/src/GraphQL/Account/Input/UserInput.php +++ b/src/GraphQL/Account/Input/UserInput.php @@ -4,21 +4,39 @@ use App\Entity\Account\User; use Overblog\GraphQLBundle\Annotation as GQL; +use Symfony\Component\Validator\Constraints as Assert; #[GQL\Input()] class UserInput { #[GQL\Field()] - public string $title; + public string $firstName; #[GQL\Field()] - public ?string $description; + public string $lastName; + + #[GQL\Field()] + public string $email; + + #[GQL\Field()] + public string $phone; + + #[GQL\Field()] + public string $password; + + #[Assert\Choice(options: ['SHIPPER', 'TRUCKER'])] + #[GQL\Field()] + public ?string $type; public function build(User $user): void { $user + ->setFirstName($this->firstName) + ->setLastName($this->lastName) + ->setEmail($this->email) + ->setPhone($this->phone) // ->setTitle($this->title) // ->setDescription($this->description) - ; + ; } } diff --git a/src/GraphQL/Account/Input/UserUpdateInput.php b/src/GraphQL/Account/Input/UserUpdateInput.php new file mode 100644 index 0000000..9903dc6 --- /dev/null +++ b/src/GraphQL/Account/Input/UserUpdateInput.php @@ -0,0 +1,10 @@ +security->isGranted('view', $user)) { - throw new UserError( - message: "Permision Denied: You may not view this resource" - ); - } + // if (!$this->security->isGranted('view', $user)) { + // throw new UserError( + // message: "Permision Denied: You may not view this resource" + // ); + // } return $user; } @@ -128,4 +129,37 @@ public function createNewUser(UserCreationInput $input): User return $user; } + + + + #[GQL\Mutation()] + #[GQL\Arg( + name: 'id', + type: 'Ulid!' + )] + #[GQL\Arg( + name: 'input', + type: 'UserUpdateInput!' + )] + public function updateUser(Ulid $id, UserUpdateInput $input): User + { + + $user = $this->getUserById($id); + $input->build($user); + + $this->entityManager->persist($user); + $this->entityManager->flush(); + + return $user; + } + + + private function getUserById(Ulid $id): User + { + $user = $this->userRepository->find($id); + if (null === $user) { + throw new UserError("Cannot find user with [id:{$id}]"); + } + return $user; + } } diff --git a/src/GraphQL/Addressing/Input/AdminAddressCreationInput.php b/src/GraphQL/Addressing/Input/AdminAddressCreationInput.php index 7cbff31..83e8387 100644 --- a/src/GraphQL/Addressing/Input/AdminAddressCreationInput.php +++ b/src/GraphQL/Addressing/Input/AdminAddressCreationInput.php @@ -7,5 +7,5 @@ class AdminAddressCreationInput extends AddressInput{ #[GQL\Field(type: "Ulid!")] - public Ulid $userId; + public Ulid $ownerId; } \ No newline at end of file diff --git a/src/GraphQL/Addressing/Resolver/AdminAddressResolver.php b/src/GraphQL/Addressing/Resolver/AdminAddressResolver.php index 6976bb1..8113a83 100644 --- a/src/GraphQL/Addressing/Resolver/AdminAddressResolver.php +++ b/src/GraphQL/Addressing/Resolver/AdminAddressResolver.php @@ -1,19 +1,30 @@ addressRepository->find($id); + if ($address === null) { + throw new UserError( + message: "Cannot find address with [id:$id]" + ); + } + return $address; } + #[GQL\Query(name: "get_address_list")] + public function getAddressConnection( + ?int $first, + ?String $after, + ?String $filter, + ?String $sort, + ): AddressConnection { + + $user = $this->security->getUser(); + if (!($user instanceof User)) { + throw new UserError("Permission Denied: You may not perform this operation"); + } + + $cb = new ConnectionBuilder( + null, + fn ($edges, PageInfoInterface $pageInfo) => new AddressConnection($edges, $pageInfo), + fn (string $coursor, Address $address, int $index) => new AddressEdge($coursor, $address) + ); + + $qb = $this->addressRepository->createQueryBuilder('address'); + + QueryBuilderHelper::applyCriteria($qb, $filter, 'address'); + + $total = fn () => (int) (clone $qb)->select('COUNT(address.id)')->getQuery()->getSingleScalarResult(); + $paginator = new Paginator(function (?int $offset, ?int $limit) use ($qb) { + return $qb + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getQuery() + ->getResult(); + }, false, $cb); + + return $paginator->auto(new Argument(['first' => $first, 'after' => $after]), $total); + } + + + #[GQL\Mutation()] - public function createNewAddress(AdminAddressCreationInput $input): Address{ + public function createNewAddress(AdminAddressCreationInput $input): Address + { - $user = $this->getUserById($input->userId); + $user = $this->getUserById($input->ownerId); $address = new UserAddress(); $input->build($address); @@ -41,7 +110,7 @@ public function createNewAddress(AdminAddressCreationInput $input): Address{ return $address; } - + public function getUserById(Ulid $id): User { diff --git a/src/GraphQL/Catalog/Input/AdminProductCreationInput.php b/src/GraphQL/Catalog/Input/AdminProductCreationInput.php index 01360df..04dfc6d 100644 --- a/src/GraphQL/Catalog/Input/AdminProductCreationInput.php +++ b/src/GraphQL/Catalog/Input/AdminProductCreationInput.php @@ -7,5 +7,5 @@ class AdminProductCreationInput extends AdminProductInput{ #[GQL\Field(type: "Ulid!")] - public Ulid $userId; + public Ulid $ownerId; } \ No newline at end of file diff --git a/src/GraphQL/Catalog/Input/ProductCategoryCreationInput.php b/src/GraphQL/Catalog/Input/ProductCategoryCreationInput.php new file mode 100644 index 0000000..ec30cda --- /dev/null +++ b/src/GraphQL/Catalog/Input/ProductCategoryCreationInput.php @@ -0,0 +1,8 @@ +getProductCategoryById($id); + } + + #[GQL\Query(name: "get_product_category_list")] + public function getProductCategoryConnection( + ?int $first, + ?String $after, + ?String $filter, + ?String $sort, + ): ProductCategoryConnection { + + + $cb = new ConnectionBuilder( + null, + fn ($edges, PageInfoInterface $pageInfo) => new ProductCategoryConnection($edges, $pageInfo), + fn (string $coursor, ProductCategory $productCategory, int $index) => new ProductCategoryEdge($coursor, $productCategory) + ); + + $qb = $this->productCategoryRepository->createQueryBuilder('productCategory'); + QueryBuilderHelper::applyCriteria($qb, $filter, 'productCategory'); + + $total = fn () => (int) (clone $qb)->select('COUNT(productCategory.id)')->getQuery()->getSingleScalarResult(); + $paginator = new Paginator(function (?int $offset, ?int $limit) use ($qb) { + return $qb + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getQuery() + ->getResult(); + }, false, $cb); + + return $paginator->auto(new Argument(['first' => $first, 'after' => $after]), $total); + } + + + #[GQL\Mutation()] + public function createNewProductCategory(ProductCategoryCreationInput $input): ProductCategory + { + $productCategory = new ProductCategory(); + + $productCategory + ->setCode($input->code ?? $this->codeGenerator->generateCode(length: 8)) + ->setShortName($input->shortName) + ->setName($input->name) + ->setIconImage($input->iconImage) + // ->setPrimaryImage($input->primaryImage) + // ->setCoverImage($input->coverImage) + // ->setClientNote($input->clientNote) + // ->setDriverNote($input->driverNote) + // ->setDescription($input->description) + // ->setEnabled($input->enabled) + ; + + $this->entityManager->persist($productCategory); + $this->entityManager->flush(); + + return $productCategory; + } + + + + + #[GQL\Mutation()] + #[GQL\Arg( + name: 'id', + type: 'Ulid!' + )] + #[GQL\Arg( + name: 'input', + type: 'ProductCategoryUpdateInput!' + )] + public function updateProductCategory(Ulid $id, ProductCategoryUpdateInput $input): ProductCategory + { + $productCategory = $this->getProductCategoryById($id); + + $productCategory + ->setCode($input->code ?? $this->codeGenerator->generateCode(length: 8)) + ->setShortName($input->shortName) + ->setName($input->name) + ->setIconImage($input->iconImage) + // ->setPrimaryImage($input->primaryImage) + // ->setCoverImage($input->coverImage) + // ->setClientNote($input->clientNote) + // ->setDriverNote($input->driverNote) + // ->setDescription($input->description) + // ->setEnabled($input->enabled) + ; + + $this->entityManager->persist($productCategory); + $this->entityManager->flush(); + + return $productCategory; + } + + + #[GQL\Mutation()] + #[GQL\Arg( + name: 'id', + type: 'Ulid!' + )] + public function deleteProductCategory(Ulid $id): ProductCategory{ + $productCategory = $this->getProductCategoryById($id); + $this->entityManager->remove($productCategory); + $this->entityManager->flush(); + return $productCategory; + } + + + + private function getProductCategoryById(Ulid $id): ProductCategory + { + $vType = $this->productCategoryRepository->find($id); + if (null == $vType) { + throw new UserError("Could not find Catalog type with [id:{$id}]"); + } + return $vType; + } +} diff --git a/src/GraphQL/Catalog/Resolver/AdminProductResolver.php b/src/GraphQL/Catalog/Resolver/AdminProductResolver.php index 0e4aa15..da975c4 100644 --- a/src/GraphQL/Catalog/Resolver/AdminProductResolver.php +++ b/src/GraphQL/Catalog/Resolver/AdminProductResolver.php @@ -4,34 +4,36 @@ use App\Entity\Account\User; use App\Entity\Catalog\Product; +use App\Entity\Catalog\ProductCategory; use App\Entity\Catalog\UserProduct; use App\GraphQL\Catalog\Input\AdminProductCreationInput; +use App\GraphQL\Catalog\Input\ProductUpdateInput; use App\GraphQL\Catalog\Type\ProductConnection; use App\GraphQL\Catalog\Type\ProductEdge; use App\Repository\Account\UserRepository; -use App\Repository\Catalog\ProductRepository; +use App\Repository\Catalog\ProductCategoryRepository; use App\Repository\Catalog\UserProductRepository; use App\Util\Doctrine\QueryBuilderHelper; use Doctrine\ORM\EntityManagerInterface; -use Overblog\GraphQLBundle\Annotation as GQL; use Overblog\GraphQLBundle\Annotation\Query; use Overblog\GraphQLBundle\Definition\Argument; use Overblog\GraphQLBundle\Error\UserError; use Overblog\GraphQLBundle\Relay\Connection\ConnectionBuilder; use Overblog\GraphQLBundle\Relay\Connection\PageInfoInterface; use Overblog\GraphQLBundle\Relay\Connection\Paginator; -use Symfony\Bridge\Doctrine\Types\UlidType; use Symfony\Bundle\SecurityBundle\Security; +use Overblog\GraphQLBundle\Annotation as GQL; use Symfony\Component\Uid\Ulid; #[GQL\Provider( - targetQueryTypes: ['AdminQuery'] + targetQueryTypes: ['AdminQuery'], + targetMutationTypes: ['AdminMutation'], )] class AdminProductResolver { - public function __construct( + private ProductCategoryRepository $productCategoryRepository, private UserProductRepository $productRepository, private EntityManagerInterface $entityManager, private UserRepository $userRepository, @@ -57,11 +59,11 @@ public function getProductItem( ); } - if (!$this->security->isGranted('view', $product)) { - throw new UserError( - message: "Permision Denied: You may not view this resource" - ); - } + // if (!$this->security->isGranted('view', $product)) { + // throw new UserError( + // message: "Permision Denied: You may not view this resource" + // ); + // } return $product; } @@ -103,11 +105,13 @@ public function getProductConnection( #[GQL\Mutation()] public function createNewProduct(AdminProductCreationInput $input): Product { - $user = $this->getUserById($input->userId); + $user = $this->getUserById($input->ownerId); + $category = $this->getProductCategoryById($input->categoryId); $product = new UserProduct(); $input->build($product); $product->setOwner($user); + $product->setCategory($category); $this->entityManager->persist($product); $this->entityManager->flush(); @@ -116,6 +120,40 @@ public function createNewProduct(AdminProductCreationInput $input): Product } + + #[GQL\Mutation()] + #[GQL\Arg( + name: 'id', + type: 'Ulid!' + )] + #[GQL\Arg( + name: 'input', + type: 'ProductUpdateInput!' + )] + public function updateProduct(Ulid $id, ProductUpdateInput $input): Product + { + $product = $this->getProductById($id); + $category = $this->getProductCategoryById($input->categoryId); + + $input->build($product); + $product->setCategory($category); + + $this->entityManager->persist($product); + $this->entityManager->flush(); + + return $product; + } + + private function getProductById(Ulid $id): Product{ + $product = $this->productRepository->find($id); + if ($product === null) { + throw new UserError( + message: "Cannot find product with [id:$id]" + ); + } + return $product; + } + public function getUserById(Ulid $id): User { @@ -125,4 +163,14 @@ public function getUserById(Ulid $id): User } return $user; } + + + private function getProductCategoryById(Ulid $id): ProductCategory + { + $vType = $this->productCategoryRepository->find($id); + if (null == $vType) { + throw new UserError("Could not find Catalog type with [id:{$id}]"); + } + return $vType; + } } diff --git a/src/GraphQL/Catalog/Resolver/ClientProductResolver.php b/src/GraphQL/Catalog/Resolver/ClientProductResolver.php index 7adbd99..b615891 100644 --- a/src/GraphQL/Catalog/Resolver/ClientProductResolver.php +++ b/src/GraphQL/Catalog/Resolver/ClientProductResolver.php @@ -4,11 +4,13 @@ use App\Entity\Account\User; use App\Entity\Catalog\Product; +use App\Entity\Catalog\ProductCategory; use App\Entity\Catalog\UserProduct; use App\GraphQL\Catalog\Input\ProductCreationInput; use App\GraphQL\Catalog\Input\ProductUpdateInput; use App\GraphQL\Catalog\Type\ProductConnection; use App\GraphQL\Catalog\Type\ProductEdge; +use App\Repository\Catalog\ProductCategoryRepository; use App\Repository\Catalog\ProductRepository; use App\Repository\Catalog\UserProductRepository; use App\Util\Doctrine\QueryBuilderHelper; @@ -33,6 +35,7 @@ class ClientProductResolver { public function __construct( + private ProductCategoryRepository $productCategoryRepository, private UserProductRepository $productRepository, private EntityManagerInterface $entityManager, private Security $security, @@ -114,8 +117,11 @@ public function createNewProduct(ProductCreationInput $input): Product throw new UserError("Permission Denied: You may not perform this operation"); } + $category = $this->getProductCategoryById($input->categoryId); + $product = new UserProduct(); $input->build($product); + $product->setCategory($category); $product->setOwner($user); $this->entityManager->persist($product); @@ -138,7 +144,10 @@ public function createNewProduct(ProductCreationInput $input): Product public function updateProduct(Ulid $id, ProductUpdateInput $input): Product { $product = $this->getProductById($id); + $category = $this->getProductCategoryById($input->categoryId); + $input->build($product); + $product->setCategory($category); $this->entityManager->persist($product); $this->entityManager->flush(); @@ -172,4 +181,15 @@ private function getProductById(Ulid $id): Product{ } return $product; } + + + private function getProductCategoryById(Ulid $id): ProductCategory + { + $vType = $this->productCategoryRepository->find($id); + if (null == $vType) { + throw new UserError("Could not find Catalog type with [id:{$id}]"); + } + return $vType; + } + } diff --git a/src/GraphQL/Catalog/Resolver/DefaultProductCategoryResolver.php b/src/GraphQL/Catalog/Resolver/DefaultProductCategoryResolver.php new file mode 100644 index 0000000..08f6b46 --- /dev/null +++ b/src/GraphQL/Catalog/Resolver/DefaultProductCategoryResolver.php @@ -0,0 +1,90 @@ +getProductCategoryById($id); + } + + #[GQL\Query(name: "get_product_category_list")] + public function getProductCategoryConnection( + ?int $first, + ?String $after, + ?String $filter, + ?String $sort, + ): ProductCategoryConnection { + + + $cb = new ConnectionBuilder( + null, + fn ($edges, PageInfoInterface $pageInfo) => new ProductCategoryConnection($edges, $pageInfo), + fn (string $coursor, ProductCategory $productCategory, int $index) => new ProductCategoryEdge($coursor, $productCategory) + ); + + $qb = $this->productCategoryRepository->createQueryBuilder('productCategory'); + QueryBuilderHelper::applyCriteria($qb, $filter, 'productCategory'); + + $total = fn () => (int) (clone $qb)->select('COUNT(productCategory.id)')->getQuery()->getSingleScalarResult(); + $paginator = new Paginator(function (?int $offset, ?int $limit) use ($qb) { + return $qb + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getQuery() + ->getResult(); + }, false, $cb); + + return $paginator->auto(new Argument(['first' => $first, 'after' => $after]), $total); + } + + + + + private function getProductCategoryById(Ulid $id): ProductCategory + { + $vType = $this->productCategoryRepository->find($id); + if (null == $vType) { + throw new UserError("Could not find Product type with [id:{$id}]"); + } + return $vType; + } +} diff --git a/src/GraphQL/Catalog/Type/ProductCategoryConnection.php b/src/GraphQL/Catalog/Type/ProductCategoryConnection.php new file mode 100644 index 0000000..e3c238b --- /dev/null +++ b/src/GraphQL/Catalog/Type/ProductCategoryConnection.php @@ -0,0 +1,11 @@ +security->isGranted('view', $shipment)) { - throw new UserError( - message: "Permision Denied: You may not view this resource" - ); - } - - - + // if (!$this->security->isGranted('view', $shipment)) { + // throw new UserError( + // message: "Permision Denied: You may not view this resource" + // ); + // } return $shipment; } - #[GQL\Query(name: "get_shipment_list")] - #[GQL\Access("isGranted('ROLE_USER')")] + + #[GQL\Query(name: "get_load_list")] + // #[GQL\Access("isGranted('ROLE_USER')")] public function getShipmentConnection( ?int $first, ?String $after, diff --git a/src/GraphQL/Vehicle/Input/VehicleTypeCreationInput.php b/src/GraphQL/Vehicle/Input/VehicleTypeCreationInput.php new file mode 100644 index 0000000..a2fb629 --- /dev/null +++ b/src/GraphQL/Vehicle/Input/VehicleTypeCreationInput.php @@ -0,0 +1,8 @@ +getVehicleTypeById($id); + } + + #[GQL\Query(name: "get_vehicle_type_list")] + public function getVehicleTypeConnection( + ?int $first, + ?String $after, + ?String $filter, + ?String $sort, + ): VehicleTypeConnection { + + + $cb = new ConnectionBuilder( + null, + fn ($edges, PageInfoInterface $pageInfo) => new VehicleTypeConnection($edges, $pageInfo), + fn (string $coursor, VehicleType $vehicleType, int $index) => new VehicleTypeEdge($coursor, $vehicleType) + ); + + $qb = $this->vehicleTypeRepository->createQueryBuilder('vehicleType'); + QueryBuilderHelper::applyCriteria($qb, $filter, 'vehicleType'); + + $total = fn () => (int) (clone $qb)->select('COUNT(vehicleType.id)')->getQuery()->getSingleScalarResult(); + $paginator = new Paginator(function (?int $offset, ?int $limit) use ($qb) { + return $qb + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getQuery() + ->getResult(); + }, false, $cb); + + return $paginator->auto(new Argument(['first' => $first, 'after' => $after]), $total); + } + + + #[GQL\Mutation()] + public function createNewVehicleType(VehicleTypeCreationInput $input): VehicleType + { + $vehicleType = new VehicleType(); + + $vehicleType + ->setCode($input->code ?? $this->codeGenerator->generateCode(length: 8)) + ->setShortName($input->shortName) + ->setName($input->name) + ->setIconImage($input->iconImage) + ->setPrimaryImage($input->primaryImage) + ->setCoverImage($input->coverImage) + ->setClientNote($input->clientNote) + ->setDriverNote($input->driverNote) + ->setDescription($input->description); + + $this->entityManager->persist($vehicleType); + $this->entityManager->flush(); + + return $vehicleType; + } + + + + + #[GQL\Mutation()] + #[GQL\Arg( + name: 'id', + type: 'Ulid!' + )] + #[GQL\Arg( + name: 'input', + type: 'VehicleTypeUpdateInput!' + )] + public function updateVehicleType(Ulid $id, VehicleTypeUpdateInput $input): VehicleType + { + $vehicleType = $this->getVehicleTypeById($id); + + $vehicleType + ->setCode($input->code ?? $this->codeGenerator->generateCode(length: 8)) + ->setShortName($input->shortName) + ->setName($input->name) + ->setIconImage($input->iconImage) + ->setPrimaryImage($input->primaryImage) + ->setCoverImage($input->coverImage) + ->setClientNote($input->clientNote) + ->setDriverNote($input->driverNote) + ->setDescription($input->description); + + $this->entityManager->persist($vehicleType); + $this->entityManager->flush(); + + return $vehicleType; + } + + + #[GQL\Mutation()] + #[GQL\Arg( + name: 'id', + type: 'Ulid!' + )] + public function deleteVehicleType(Ulid $id): VehicleType{ + $vehicleType = $this->getVehicleTypeById($id); + $this->entityManager->remove($vehicleType); + $this->entityManager->flush(); + return $vehicleType; + } + + + + private function getVehicleTypeById(Ulid $id): VehicleType + { + $vType = $this->vehicleTypeRepository->find($id); + if (null == $vType) { + throw new UserError("Could not find Vehicle type with [id:{$id}]"); + } + return $vType; + } +} diff --git a/src/GraphQL/Vehicle/Resolver/DefaultVehicleTypeResolver.php b/src/GraphQL/Vehicle/Resolver/DefaultVehicleTypeResolver.php new file mode 100644 index 0000000..08aebf0 --- /dev/null +++ b/src/GraphQL/Vehicle/Resolver/DefaultVehicleTypeResolver.php @@ -0,0 +1,92 @@ +getVehicleTypeById($id); + } + + #[GQL\Query(name: "get_vehicle_type_list")] + public function getVehicleTypeConnection( + ?int $first, + ?String $after, + ?String $filter, + ?String $sort, + ): VehicleTypeConnection { + + + $cb = new ConnectionBuilder( + null, + fn ($edges, PageInfoInterface $pageInfo) => new VehicleTypeConnection($edges, $pageInfo), + fn (string $coursor, VehicleType $vehicleType, int $index) => new VehicleTypeEdge($coursor, $vehicleType) + ); + + $qb = $this->vehicleTypeRepository->createQueryBuilder('vehicleType'); + QueryBuilderHelper::applyCriteria($qb, $filter, 'vehicleType'); + + $total = fn () => (int) (clone $qb)->select('COUNT(vehicleType.id)')->getQuery()->getSingleScalarResult(); + $paginator = new Paginator(function (?int $offset, ?int $limit) use ($qb) { + return $qb + ->setFirstResult($offset) + ->setMaxResults($limit) + ->getQuery() + ->getResult(); + }, false, $cb); + + return $paginator->auto(new Argument(['first' => $first, 'after' => $after]), $total); + } + + + + + private function getVehicleTypeById(Ulid $id): VehicleType + { + $vType = $this->vehicleTypeRepository->find($id); + if (null == $vType) { + throw new UserError("Could not find Vehicle type with [id:{$id}]"); + } + return $vType; + } +} diff --git a/src/GraphQL/Vehicle/Type/VehicleTypeConnection.php b/src/GraphQL/Vehicle/Type/VehicleTypeConnection.php new file mode 100644 index 0000000..d5b364a --- /dev/null +++ b/src/GraphQL/Vehicle/Type/VehicleTypeConnection.php @@ -0,0 +1,11 @@ + + * + * @method ProductCategory|null find($id, $lockMode = null, $lockVersion = null) + * @method ProductCategory|null findOneBy(array $criteria, array $orderBy = null) + * @method ProductCategory[] findAll() + * @method ProductCategory[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + */ +class ProductCategoryRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, ProductCategory::class); + } + +// /** +// * @return ProductCategory[] Returns an array of ProductCategory objects +// */ +// public function findByExampleField($value): array +// { +// return $this->createQueryBuilder('p') +// ->andWhere('p.exampleField = :val') +// ->setParameter('val', $value) +// ->orderBy('p.id', 'ASC') +// ->setMaxResults(10) +// ->getQuery() +// ->getResult() +// ; +// } + +// public function findOneBySomeField($value): ?ProductCategory +// { +// return $this->createQueryBuilder('p') +// ->andWhere('p.exampleField = :val') +// ->setParameter('val', $value) +// ->getQuery() +// ->getOneOrNullResult() +// ; +// } +} diff --git a/src/Service/File/Uploader.php b/src/Service/File/Uploader.php new file mode 100644 index 0000000..7dbe1cb --- /dev/null +++ b/src/Service/File/Uploader.php @@ -0,0 +1,183 @@ +parameters = $parameters; + $this->assetsHelper = $assetsHelper; + $this->httpHelper = $httpHelper; + $this->slugger = $slugger; + + + + + // /** @AssetExtension */ + // $assetsHelper = $container->get('twig.extension.assets'); + // $this->assetsHelper = $assetsHelper; + // /** @var HttpFoundationExtension */ + // $httpHelper = $container->get('twig.extension.http_foundation'); + // $this->httpHelper = $httpHelper; + } + + + + + public function upload(UploadedFile $file, string $path = '', ?string $newName = null): string + { + + + + $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME); + + if (null === $newName) { + // this is needed to safely include the file name as part of the URL + $safeFilename = $this->slugger->slug($originalFilename); + $newName = $safeFilename . '-' . uniqid() . '.' . $file->guessExtension(); + } + + // $publicDir = $this->parameters->get('http.public_dir'); + $absoluteUploadDir = '';//$this->parameters->get('file.upload.dir'); + $uploadDir = $absoluteUploadDir; + + // $this->assetsHelper- + + $uploadDir = ($uploadDir?? '') . '/' . $path; + + $filePath = $uploadDir . '/' .$newName; + $filePath = preg_replace(['~/+~','~^/|/$~'],['/',''],$filePath); + + + $this->defaultStorage->write($filePath,$file->getContent()); + + // $this->filesystem->publicUrl(); + + + return $filePath; + + // $newFile = $file->move($uploadDir, $newName); + // $newFileFullPath = $newFile->getPathname(); + + // $relativePath = $this->getRelativePath($absoluteUploadDir, $newFileFullPath); + + // $relativePath = preg_replace('~(\\\\)+~u', '/', $relativePath); + + // // return $relativePath; + + // $rpath = $this->assetsHelper->getAssetUrl($relativePath); + // return $rpath; + // return $this->httpHelper->generateAbsoluteUrl($rpath); + } + + + + function getRelativeUrl(string $path): string{ + return $this->urlGenerator->generate('app_file_read',[ 'path' => $path]); + } + + function getAbsoluteUrl(string $path): string{ + $relativeUrl = $this->getRelativeUrl($path); + return $this->httpHelper->generateAbsoluteUrl($relativeUrl); + } + + + + protected function getRelativePath(string $original, string $file): string + { + // $file1 = '/path/to/file1.txt'; + // $file2 = '/path/to/subdirectory/file2.txt'; + + $dir1 = dirname(realpath($original)); + $dir2 = dirname(realpath($file)); + + // Get the common ancestor directory + $commonDir = ''; + for ($i = 0; $i < min(strlen($dir1), strlen($dir2)); $i++) { + if ($dir1[$i] !== $dir2[$i]) { + break; + } + // if($i !== 0) + $commonDir .= $dir1[$i]; + } + + // Construct the relative path of file2 with respect to file1 + $relativePath = substr($file, strlen($commonDir) + 1); + + return $relativePath; + + } + + + + + public function remove(string $url) + { + + + $publicURL = $this->httpHelper->generateAbsoluteUrl($this->assetsHelper->getAssetUrl('/')); + + + + + $ihost = parse_url($publicURL, PHP_URL_HOST); + $iport = parse_url($publicURL, PHP_URL_PORT); + $ipath = parse_url($publicURL, PHP_URL_PATH); + + $host = parse_url($url, PHP_URL_HOST); + $port = parse_url($url, PHP_URL_PORT); + $path = parse_url($url, PHP_URL_PATH); + + + if (($ihost == $host && $iport == $port) || !$host) { + + + $publicDir = $this->parameters->get('public_dir'); + + + $lpath = $publicDir . '/' . $path; + + + if (file_exists($lpath)) + unlink($lpath); + // else + // throw new \RuntimeException("Could not find target file \"{$lpath}\""); + + + } + + + } + +} \ No newline at end of file diff --git a/src/Service/File/UploaderInterface.php b/src/Service/File/UploaderInterface.php new file mode 100644 index 0000000..3f16858 --- /dev/null +++ b/src/Service/File/UploaderInterface.php @@ -0,0 +1,18 @@ +