Giter Site home page Giter Site logo

riverwaysoft / php-converter Goto Github PK

View Code? Open in Web Editor NEW
8.0 1.0 2.0 3.32 MB

Generates TypeScript & Dart out of your PHP DTO classes.

License: MIT License

PHP 91.65% TypeScript 5.72% Dart 1.66% Go 0.09% Shell 0.14% Dockerfile 0.58% Makefile 0.17%
php code-converter dart typescript

php-converter's Introduction

php-converter Latest Version on Packagist Tests PHPStan Total Downloads

Screen Shot 2022-10-07 at 09 04 35

Generates TypeScript & Dart out of your PHP DTO classes.

Why?

Statically typed languages like TypeScript or Dart are great because they allow catching bugs without even running your code. But unless there are well-defined contracts between the API and consumer apps, you may find yourself frequently adjusting outdated typings whenever the API changes. This library generates types for you, enabling you to move faster and encounter fewer bugs.

Requirements

PHP 8.0 or above

Quick start

  1. Installation
composer require riverwaysoft/php-converter --dev

If the installation leads to dependency conflicts, consider using the standalone Phar version of the package.

  1. Mark a few classes with the #[Dto] annotation to convert them into TypeScript or Dart.
use Riverwaysoft\PhpConverter\Filter\Attributes\Dto;

#[Dto]
class UserOutput
{
    public string $id;
    public int $age;
    public ?UserOutput $bestFriend;
    /** @var UserOutput[] */
    public array $friends;
}
  1. Run the CLI command to generate TypeScript
vendor/bin/php-converter --from=/path/to/project/src --to=.

This will generate a file generated.ts with the following content:

type UserOutput = {
  id: string;
  age: number;
  bestFriend: UserOutput | null;
  friends: UserOutput[];
}

Features

  • Supports all PHP data types including union types, nullable types, and enums.
  • Supports PHP DocBlock types, e.g., User[], int[][]|null, and generics thanks to phpstan/phpdoc-parser
  • Custom type resolvers (for instance, for DateTimeImmutable).
  • Generate a single output file or multiple files (1 type per file).
  • Option to override the generation logic.
  • Flexible class filters with the option to use your own filters.
  • Generate API client from Symfony or API Platform code.

Customization

If you'd like to customize the conversion process, you need to copy the config script to your project folder:

cp vendor/riverwaysoft/php-converter/bin/default-config.php config/ts-config.php

Now you can customize this config and run the php-converter using the following script:

vendor/bin/php-converter --from=/path/to/project/src --to=. --config=config/ts-config.php

Documentation

php-converter's People

Contributors

konekod avatar kubk avatar mitalcoi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

konekod emawork

php-converter's Issues

Dart code generation improvements

  1. Generate fromJSON + mappers:
class UserOutput {
  final String id;
  final Profile? profile;
  final FullName name

  UserOutput({
    required this.id,
    required this.name,
    this.profile,
  })
  
  factory UserOutput.fromJson(Map<String, dynamic> json) {
    return UserOutput(
      id: json['id'],
      name: FullName.fromJson(json['name']),
      profile: json['profile'] != null ? Profile.fromJson(json['profile']) : null,
  }
}
  1. Investigate freezed: https://pub.dev/packages/freezed

Build PHAR executable

  • Provide an option to build a PHAR executable. This executable will be used by frontend / mobile team without pulling backend

Built-in script to check if generated file is up-to-date

Currently the following bash can be used:

#!/bin/bash

set -e

GENERATED_FILE=generated.dart
PREV_GENERATED_FILE=current-generated.dart

cp $GENERATED_FILE $PREV_GENERATED_FILE
bin/php-converter.phar --from=./src --to=./ --config=./config/php-converter/dart-config.php

if diff -q $PREV_GENERATED_FILE $GENERATED_FILE; then
  echo "DTO ok"
  rm $PREV_GENERATED_FILE
else
  echo "Dto mismatch"
  rm $PREV_GENERATED_FILE
  exit 1
fi

Array support

Make a fallback to doc block for array types

  • Entity[]

Generate clickable @see links to the method implementation

Example:

/** @see FoodHierarchyController */
export const apiFoodHierarchyGet = (): Promise<FoodHierarchyNodeOutput[]> => {
  return axios
    .get<FoodHierarchyNodeOutput[]>(`/api/food_hierarchy`)
    .then((response) => response.data);
}

Such links only clickable in PHP files so they won't work in JS. But, we can still generate class and method so it's possible to go to the method by copying & globally searching the copied string:

/**
 * @see JobSheetMessagesApiController::createMessage
 */

Support ApiPlatform Input converting

  • Enums should be transformed into { key: { value: Enum } }
  • DateTimeImmutable/DateTime should be converted to string as usual
  • Doctrine ORM Embeddables should be typed manually inside dto-converter's config
  • Nested inputs should be supported

Replace kebab case / snake case with custom implementations

There is no need to use vendor package for simple things like kebab case / snake case conversion. The task is to remove jawira/case-converter from project and rewrite KebabCaseFileNameGenerator and SnakeCaseFileNameGenerator to use custom preg_replace_callback. Unit tests are required.

ApiResource generator improvements

  • add optional filters query parameter that is going to work in GET requests
  • for GET requests the result should be wrapped with CollectionResponse the same it is wrapped for dart OldEnum

Class filters

  • Allow to skip class by using PHPDoc / PHP Attribute
  • Allow to include only classes with specific PHPDoc / PHP Attribute

Nullable types

class User
{
    public int $id;

    public string $name;

    public ?string $address;
}

Should be transformed to this

export type User = {
    int: number;
    name: string;
    address: string | null;
}

Provide an option to use TypeScript union types instead of Enum

At the moment dto-converter converts PHP enums to TS enums:

<?php

use MyCLabs\Enum\Enum;

class ColorEnum extends Enum
{
    private const RED = 0;
    private const GREEN = 1;
    private const BLUE = 2;
}

This will be converted to:

enum ColorEnum {
  RED = 0;
  GREEN = 1;
  BLUE = 2;
}

But it also makes sense to provide an option to convert PHP Enum to TypeScript union type if someone prefers union types over enums:

type ColorEnum = 0 | 1 | 2;

// or

type Gender = 'male' | 'female' | 'unkown';

This library already can generate union types but only when a specific condition is met: https://github.com/riverwaysoft/dto-converter/blob/8c35d6cafde77fac392ef702ee8dcf97c3d46ce1/src/Language/TypeScript/TypeScriptGenerator.php#L48

The task for PR:

  1. Add a bool flag to TypeScriptGenerator's constructor. Something like preferUnionTypeOverEnum: https://github.com/riverwaysoft/dto-converter/blob/master/src/Language/TypeScript/TypeScriptGenerator.php#L21

It should be false by default.

  1. If this flag is set to true - make an early return true from this function: https://github.com/riverwaysoft/dto-converter/blob/master/src/Language/TypeScript/TypeScriptGenerator.php#L61

  2. Write a test for this feature. Please add it to EndToEndTest.php: https://github.com/riverwaysoft/dto-converter/blob/master/tests/EndToEndTest.php

Split generated output into different files

It should be possible to split the generated output (TypeScript or Dart) into different files. For example one class / enum per file with correct imports. To handle imports topological sort should be used.

Investigate idea of generating types based on PHPStan's evaluation

For example having this code it'd nice to generate types based on PHPStan's type output:

  #[Route('/items', name: 'items_index', methods:['get'] )]
    public function index(ManagerRegistry $doctrine): JsonResponse
    {
        $products = $doctrine
            ->getRepository(Proassist::class)
            ->findAll();
   
        $data = [];
   
        foreach ($products as $product) {
           $data[] = [
               'id' => $product->getId(),
               'name' => $product->getName(),
               'description' => $product->getDescription(),
           ];
        }
   
        return $this->json($data);
    }

PHPStan should known that the type of $data is array<{id: ..., 'name': ..., 'description': ...}>

PHPStan under the hood talk: https://www.youtube.com/watch?v=85Aq2rWpGQE

Example projects (appeared randomly in GitHub search):

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.