From 517115ee3ce8898ffc72b770c4412d44dccead79 Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Fri, 7 Apr 2023 15:57:35 +0200 Subject: [PATCH] Initial commit --- .editorconfig | 804 ++++++++++++++++++ .gitattributes | 6 + .github/FUNDING.yml | 1 + .github/workflows/ci.yaml | 40 + .github/workflows/cs.yaml | 27 + .github/workflows/release.yaml | 16 + .gitignore | 6 + .php-cs-fixer.php | 70 ++ LICENSE.md | 8 + README.md | 50 ++ composer.json | 52 ++ phpunit.xml | 18 + src/HasHasManyWithInverseRelation.php | 16 + src/HasHasOneWithInverseRelation.php | 16 + src/HasManyWithInverseRelation.php | 24 + src/HasMorphManyWithInverseRelation.php | 33 + src/HasOneWithInverseRelation.php | 24 + src/MorphManyWithInverseRelation.php | 24 + src/WithInverseOneOrManyRelation.php | 65 ++ tests/Pest.php | 3 + tests/Stubs/HasManyWithInverse/ChildModel.php | 19 + .../Stubs/HasManyWithInverse/ParentModel.php | 26 + tests/Stubs/HasOneWithInverse/ChildModel.php | 19 + tests/Stubs/HasOneWithInverse/ParentModel.php | 26 + .../MorphManyWithInverse/CommentModel.php | 23 + .../Stubs/MorphManyWithInverse/PostModel.php | 26 + tests/Unit/HasManyWithInverseTest.php | 109 +++ tests/Unit/HasOneWithInverseTest.php | 92 ++ tests/Unit/MorphManyWithInverseTest.php | 116 +++ tests/bootstrap.php | 3 + 30 files changed, 1762 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/cs.yaml create mode 100644 .github/workflows/release.yaml create mode 100644 .gitignore create mode 100644 .php-cs-fixer.php create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 composer.json create mode 100644 phpunit.xml create mode 100644 src/HasHasManyWithInverseRelation.php create mode 100644 src/HasHasOneWithInverseRelation.php create mode 100644 src/HasManyWithInverseRelation.php create mode 100644 src/HasMorphManyWithInverseRelation.php create mode 100644 src/HasOneWithInverseRelation.php create mode 100644 src/MorphManyWithInverseRelation.php create mode 100644 src/WithInverseOneOrManyRelation.php create mode 100644 tests/Pest.php create mode 100644 tests/Stubs/HasManyWithInverse/ChildModel.php create mode 100644 tests/Stubs/HasManyWithInverse/ParentModel.php create mode 100644 tests/Stubs/HasOneWithInverse/ChildModel.php create mode 100644 tests/Stubs/HasOneWithInverse/ParentModel.php create mode 100644 tests/Stubs/MorphManyWithInverse/CommentModel.php create mode 100644 tests/Stubs/MorphManyWithInverse/PostModel.php create mode 100644 tests/Unit/HasManyWithInverseTest.php create mode 100644 tests/Unit/HasOneWithInverseTest.php create mode 100644 tests/Unit/MorphManyWithInverseTest.php create mode 100644 tests/bootstrap.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7dd1439 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,804 @@ +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +max_line_length = 175 +tab_width = 4 +trim_trailing_whitespace = true +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_visual_guides = none +ij_wrap_on_typing = false + +[*.blade.php] +ij_blade_keep_indents_on_empty_lines = false + +[*.css] +ij_css_align_closing_brace_with_properties = false +ij_css_blank_lines_around_nested_selector = 1 +ij_css_blank_lines_between_blocks = 1 +ij_css_block_comment_add_space = false +ij_css_brace_placement = end_of_line +ij_css_enforce_quotes_on_format = false +ij_css_hex_color_long_format = true +ij_css_hex_color_lower_case = true +ij_css_hex_color_short_format = false +ij_css_hex_color_upper_case = false +ij_css_keep_blank_lines_in_code = 2 +ij_css_keep_indents_on_empty_lines = false +ij_css_keep_single_line_blocks = false +ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_css_space_after_colon = true +ij_css_space_before_opening_brace = true +ij_css_use_double_quotes = true +ij_css_value_alignment = do_not_align + +[*.less] +ij_continuation_indent_size = 4 +ij_less_align_closing_brace_with_properties = false +ij_less_blank_lines_around_nested_selector = 1 +ij_less_blank_lines_between_blocks = 1 +ij_less_block_comment_add_space = false +ij_less_brace_placement = 0 +ij_less_enforce_quotes_on_format = false +ij_less_hex_color_long_format = false +ij_less_hex_color_lower_case = false +ij_less_hex_color_short_format = false +ij_less_hex_color_upper_case = false +ij_less_keep_blank_lines_in_code = 2 +ij_less_keep_indents_on_empty_lines = false +ij_less_keep_single_line_blocks = false +ij_less_line_comment_add_space = false +ij_less_line_comment_at_first_column = false +ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_less_space_after_colon = true +ij_less_space_before_opening_brace = true +ij_less_use_double_quotes = true +ij_less_value_alignment = 0 + +[*.sass] +indent_size = 2 +ij_sass_align_closing_brace_with_properties = false +ij_sass_blank_lines_around_nested_selector = 1 +ij_sass_blank_lines_between_blocks = 1 +ij_sass_brace_placement = 0 +ij_sass_enforce_quotes_on_format = false +ij_sass_hex_color_long_format = false +ij_sass_hex_color_lower_case = false +ij_sass_hex_color_short_format = false +ij_sass_hex_color_upper_case = false +ij_sass_keep_blank_lines_in_code = 2 +ij_sass_keep_indents_on_empty_lines = false +ij_sass_keep_single_line_blocks = false +ij_sass_line_comment_add_space = false +ij_sass_line_comment_at_first_column = false +ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_sass_space_after_colon = true +ij_sass_space_before_opening_brace = true +ij_sass_use_double_quotes = true +ij_sass_value_alignment = 0 + +[*.scss] +ij_scss_align_closing_brace_with_properties = false +ij_scss_blank_lines_around_nested_selector = 1 +ij_scss_blank_lines_between_blocks = 1 +ij_scss_block_comment_add_space = false +ij_scss_brace_placement = 0 +ij_scss_enforce_quotes_on_format = false +ij_scss_hex_color_long_format = false +ij_scss_hex_color_lower_case = false +ij_scss_hex_color_short_format = false +ij_scss_hex_color_upper_case = false +ij_scss_keep_blank_lines_in_code = 2 +ij_scss_keep_indents_on_empty_lines = false +ij_scss_keep_single_line_blocks = false +ij_scss_line_comment_add_space = false +ij_scss_line_comment_at_first_column = false +ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_scss_space_after_colon = true +ij_scss_space_before_opening_brace = true +ij_scss_use_double_quotes = true +ij_scss_value_alignment = 0 + +[*.twig] +ij_twig_keep_indents_on_empty_lines = false +ij_twig_spaces_inside_comments_delimiters = true +ij_twig_spaces_inside_delimiters = true +ij_twig_spaces_inside_variable_delimiters = true + +[*.vue] +ij_continuation_indent_size = 4 +ij_visual_guides = 175 +ij_vue_indent_children_of_top_level = template,script,style +ij_vue_interpolation_new_line_after_start_delimiter = false +ij_vue_interpolation_new_line_before_end_delimiter = false +ij_vue_interpolation_wrap = off +ij_vue_keep_indents_on_empty_lines = false +ij_vue_spaces_within_interpolation_expressions = true + +[.editorconfig] +ij_editorconfig_align_group_field_declarations = false +ij_editorconfig_space_after_colon = false +ij_editorconfig_space_after_comma = true +ij_editorconfig_space_before_colon = false +ij_editorconfig_space_before_comma = false +ij_editorconfig_spaces_around_assignment_operators = true + +[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}] +ij_xml_align_attributes = true +ij_xml_align_text = false +ij_xml_attribute_wrap = normal +ij_xml_block_comment_add_space = false +ij_xml_block_comment_at_first_column = true +ij_xml_keep_blank_lines = 2 +ij_xml_keep_indents_on_empty_lines = false +ij_xml_keep_line_breaks = true +ij_xml_keep_line_breaks_in_text = true +ij_xml_keep_whitespaces = false +ij_xml_keep_whitespaces_around_cdata = preserve +ij_xml_keep_whitespaces_inside_cdata = false +ij_xml_line_comment_at_first_column = true +ij_xml_space_after_tag_name = false +ij_xml_space_around_equals_in_attribute = false +ij_xml_space_inside_empty_tag = false +ij_xml_text_wrap = normal + +[{*.ats,*.cts,*.mts,*.ts}] +ij_continuation_indent_size = 4 +ij_visual_guides = 175 +ij_typescript_align_imports = false +ij_typescript_align_multiline_array_initializer_expression = false +ij_typescript_align_multiline_binary_operation = false +ij_typescript_align_multiline_chained_methods = false +ij_typescript_align_multiline_extends_list = false +ij_typescript_align_multiline_for = true +ij_typescript_align_multiline_parameters = true +ij_typescript_align_multiline_parameters_in_calls = false +ij_typescript_align_multiline_ternary_operation = false +ij_typescript_align_object_properties = 0 +ij_typescript_align_union_types = false +ij_typescript_align_var_statements = 0 +ij_typescript_array_initializer_new_line_after_left_brace = false +ij_typescript_array_initializer_right_brace_on_new_line = false +ij_typescript_array_initializer_wrap = off +ij_typescript_assignment_wrap = off +ij_typescript_binary_operation_sign_on_next_line = false +ij_typescript_binary_operation_wrap = off +ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_typescript_blank_lines_after_imports = 1 +ij_typescript_blank_lines_around_class = 1 +ij_typescript_blank_lines_around_field = 0 +ij_typescript_blank_lines_around_field_in_interface = 0 +ij_typescript_blank_lines_around_function = 1 +ij_typescript_blank_lines_around_method = 1 +ij_typescript_blank_lines_around_method_in_interface = 1 +ij_typescript_block_brace_style = end_of_line +ij_typescript_block_comment_add_space = false +ij_typescript_block_comment_at_first_column = true +ij_typescript_call_parameters_new_line_after_left_paren = false +ij_typescript_call_parameters_right_paren_on_new_line = false +ij_typescript_call_parameters_wrap = off +ij_typescript_catch_on_new_line = false +ij_typescript_chained_call_dot_on_new_line = true +ij_typescript_class_brace_style = end_of_line +ij_typescript_comma_on_new_line = false +ij_typescript_do_while_brace_force = never +ij_typescript_else_on_new_line = false +ij_typescript_enforce_trailing_comma = whenmultiline +ij_typescript_enum_constants_wrap = on_every_item +ij_typescript_extends_keyword_wrap = off +ij_typescript_extends_list_wrap = off +ij_typescript_field_prefix = _ +ij_typescript_file_name_style = relaxed +ij_typescript_finally_on_new_line = false +ij_typescript_for_brace_force = never +ij_typescript_for_statement_new_line_after_left_paren = false +ij_typescript_for_statement_right_paren_on_new_line = false +ij_typescript_for_statement_wrap = off +ij_typescript_force_quote_style = true +ij_typescript_force_semicolon_style = true +ij_typescript_function_expression_brace_style = end_of_line +ij_typescript_if_brace_force = never +ij_typescript_import_merge_members = global +ij_typescript_import_prefer_absolute_path = global +ij_typescript_import_sort_members = true +ij_typescript_import_sort_module_name = false +ij_typescript_import_use_node_resolution = true +ij_typescript_imports_wrap = on_every_item +ij_typescript_indent_case_from_switch = true +ij_typescript_indent_chained_calls = true +ij_typescript_indent_package_children = 0 +ij_typescript_jsdoc_include_types = false +ij_typescript_jsx_attribute_value = braces +ij_typescript_keep_blank_lines_in_code = 2 +ij_typescript_keep_first_column_comment = true +ij_typescript_keep_indents_on_empty_lines = false +ij_typescript_keep_line_breaks = true +ij_typescript_keep_simple_blocks_in_one_line = false +ij_typescript_keep_simple_methods_in_one_line = false +ij_typescript_line_comment_add_space = true +ij_typescript_line_comment_at_first_column = false +ij_typescript_method_brace_style = end_of_line +ij_typescript_method_call_chain_wrap = off +ij_typescript_method_parameters_new_line_after_left_paren = false +ij_typescript_method_parameters_right_paren_on_new_line = false +ij_typescript_method_parameters_wrap = off +ij_typescript_object_literal_wrap = on_every_item +ij_typescript_parentheses_expression_new_line_after_left_paren = false +ij_typescript_parentheses_expression_right_paren_on_new_line = false +ij_typescript_place_assignment_sign_on_next_line = false +ij_typescript_prefer_as_type_cast = false +ij_typescript_prefer_explicit_types_function_expression_returns = false +ij_typescript_prefer_explicit_types_function_returns = false +ij_typescript_prefer_explicit_types_vars_fields = false +ij_typescript_prefer_parameters_wrap = false +ij_typescript_reformat_c_style_comments = false +ij_typescript_space_after_colon = true +ij_typescript_space_after_comma = true +ij_typescript_space_after_dots_in_rest_parameter = false +ij_typescript_space_after_generator_mult = true +ij_typescript_space_after_property_colon = true +ij_typescript_space_after_quest = true +ij_typescript_space_after_type_colon = true +ij_typescript_space_after_unary_not = false +ij_typescript_space_before_async_arrow_lparen = true +ij_typescript_space_before_catch_keyword = true +ij_typescript_space_before_catch_left_brace = true +ij_typescript_space_before_catch_parentheses = true +ij_typescript_space_before_class_lbrace = true +ij_typescript_space_before_class_left_brace = true +ij_typescript_space_before_colon = true +ij_typescript_space_before_comma = false +ij_typescript_space_before_do_left_brace = true +ij_typescript_space_before_else_keyword = true +ij_typescript_space_before_else_left_brace = true +ij_typescript_space_before_finally_keyword = true +ij_typescript_space_before_finally_left_brace = true +ij_typescript_space_before_for_left_brace = true +ij_typescript_space_before_for_parentheses = true +ij_typescript_space_before_for_semicolon = false +ij_typescript_space_before_function_left_parenth = false +ij_typescript_space_before_generator_mult = false +ij_typescript_space_before_if_left_brace = true +ij_typescript_space_before_if_parentheses = true +ij_typescript_space_before_method_call_parentheses = false +ij_typescript_space_before_method_left_brace = true +ij_typescript_space_before_method_parentheses = false +ij_typescript_space_before_property_colon = false +ij_typescript_space_before_quest = true +ij_typescript_space_before_switch_left_brace = true +ij_typescript_space_before_switch_parentheses = true +ij_typescript_space_before_try_left_brace = true +ij_typescript_space_before_type_colon = false +ij_typescript_space_before_unary_not = false +ij_typescript_space_before_while_keyword = true +ij_typescript_space_before_while_left_brace = true +ij_typescript_space_before_while_parentheses = true +ij_typescript_spaces_around_additive_operators = true +ij_typescript_spaces_around_arrow_function_operator = true +ij_typescript_spaces_around_assignment_operators = true +ij_typescript_spaces_around_bitwise_operators = true +ij_typescript_spaces_around_equality_operators = true +ij_typescript_spaces_around_logical_operators = true +ij_typescript_spaces_around_multiplicative_operators = true +ij_typescript_spaces_around_relational_operators = true +ij_typescript_spaces_around_shift_operators = true +ij_typescript_spaces_around_unary_operator = false +ij_typescript_spaces_within_array_initializer_brackets = false +ij_typescript_spaces_within_brackets = false +ij_typescript_spaces_within_catch_parentheses = false +ij_typescript_spaces_within_for_parentheses = false +ij_typescript_spaces_within_if_parentheses = false +ij_typescript_spaces_within_imports = false +ij_typescript_spaces_within_interpolation_expressions = false +ij_typescript_spaces_within_method_call_parentheses = false +ij_typescript_spaces_within_method_parentheses = false +ij_typescript_spaces_within_object_literal_braces = false +ij_typescript_spaces_within_object_type_braces = false +ij_typescript_spaces_within_parentheses = false +ij_typescript_spaces_within_switch_parentheses = false +ij_typescript_spaces_within_type_assertion = false +ij_typescript_spaces_within_union_types = true +ij_typescript_spaces_within_while_parentheses = false +ij_typescript_special_else_if_treatment = true +ij_typescript_ternary_operation_signs_on_next_line = false +ij_typescript_ternary_operation_wrap = off +ij_typescript_union_types_wrap = on_every_item +ij_typescript_use_chained_calls_group_indents = false +ij_typescript_use_double_quotes = false +ij_typescript_use_explicit_js_extension = auto +ij_typescript_use_path_mapping = always +ij_typescript_use_public_modifier = false +ij_typescript_use_semicolon_after_statement = true +ij_typescript_var_declaration_wrap = normal +ij_typescript_while_brace_force = never +ij_typescript_while_on_new_line = false +ij_typescript_wrap_comments = false + +[{*.bash,*.sh,*.zsh}] +indent_size = 2 +tab_width = 2 +ij_shell_binary_ops_start_line = false +ij_shell_keep_column_alignment_padding = false +ij_shell_minify_program = false +ij_shell_redirect_followed_by_space = false +ij_shell_switch_cases_indented = false +ij_shell_use_unix_line_separator = true + +[{*.cjs,*.js}] +ij_continuation_indent_size = 4 +ij_visual_guides = 175 +ij_javascript_align_imports = false +ij_javascript_align_multiline_array_initializer_expression = false +ij_javascript_align_multiline_binary_operation = false +ij_javascript_align_multiline_chained_methods = false +ij_javascript_align_multiline_extends_list = false +ij_javascript_align_multiline_for = true +ij_javascript_align_multiline_parameters = true +ij_javascript_align_multiline_parameters_in_calls = false +ij_javascript_align_multiline_ternary_operation = false +ij_javascript_align_object_properties = 1 +ij_javascript_align_union_types = false +ij_javascript_align_var_statements = 2 +ij_javascript_array_initializer_new_line_after_left_brace = false +ij_javascript_array_initializer_right_brace_on_new_line = false +ij_javascript_array_initializer_wrap = off +ij_javascript_assignment_wrap = off +ij_javascript_binary_operation_sign_on_next_line = false +ij_javascript_binary_operation_wrap = off +ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_javascript_blank_lines_after_imports = 1 +ij_javascript_blank_lines_around_class = 1 +ij_javascript_blank_lines_around_field = 0 +ij_javascript_blank_lines_around_function = 1 +ij_javascript_blank_lines_around_method = 1 +ij_javascript_block_brace_style = end_of_line +ij_javascript_block_comment_add_space = false +ij_javascript_block_comment_at_first_column = true +ij_javascript_call_parameters_new_line_after_left_paren = false +ij_javascript_call_parameters_right_paren_on_new_line = false +ij_javascript_call_parameters_wrap = off +ij_javascript_catch_on_new_line = false +ij_javascript_chained_call_dot_on_new_line = true +ij_javascript_class_brace_style = end_of_line +ij_javascript_comma_on_new_line = false +ij_javascript_do_while_brace_force = never +ij_javascript_else_on_new_line = false +ij_javascript_enforce_trailing_comma = whenmultiline +ij_javascript_extends_keyword_wrap = off +ij_javascript_extends_list_wrap = off +ij_javascript_field_prefix = _ +ij_javascript_file_name_style = relaxed +ij_javascript_finally_on_new_line = false +ij_javascript_for_brace_force = never +ij_javascript_for_statement_new_line_after_left_paren = false +ij_javascript_for_statement_right_paren_on_new_line = false +ij_javascript_for_statement_wrap = off +ij_javascript_force_quote_style = true +ij_javascript_force_semicolon_style = true +ij_javascript_function_expression_brace_style = end_of_line +ij_javascript_if_brace_force = never +ij_javascript_import_merge_members = global +ij_javascript_import_prefer_absolute_path = global +ij_javascript_import_sort_members = true +ij_javascript_import_sort_module_name = false +ij_javascript_import_use_node_resolution = true +ij_javascript_imports_wrap = on_every_item +ij_javascript_indent_case_from_switch = true +ij_javascript_indent_chained_calls = true +ij_javascript_indent_package_children = 0 +ij_javascript_jsx_attribute_value = braces +ij_javascript_keep_blank_lines_in_code = 2 +ij_javascript_keep_first_column_comment = true +ij_javascript_keep_indents_on_empty_lines = false +ij_javascript_keep_line_breaks = true +ij_javascript_keep_simple_blocks_in_one_line = false +ij_javascript_keep_simple_methods_in_one_line = false +ij_javascript_line_comment_add_space = true +ij_javascript_line_comment_at_first_column = false +ij_javascript_method_brace_style = end_of_line +ij_javascript_method_call_chain_wrap = off +ij_javascript_method_parameters_new_line_after_left_paren = false +ij_javascript_method_parameters_right_paren_on_new_line = false +ij_javascript_method_parameters_wrap = off +ij_javascript_object_literal_wrap = on_every_item +ij_javascript_parentheses_expression_new_line_after_left_paren = false +ij_javascript_parentheses_expression_right_paren_on_new_line = false +ij_javascript_place_assignment_sign_on_next_line = false +ij_javascript_prefer_as_type_cast = false +ij_javascript_prefer_explicit_types_function_expression_returns = false +ij_javascript_prefer_explicit_types_function_returns = false +ij_javascript_prefer_explicit_types_vars_fields = false +ij_javascript_prefer_parameters_wrap = false +ij_javascript_reformat_c_style_comments = false +ij_javascript_space_after_colon = true +ij_javascript_space_after_comma = true +ij_javascript_space_after_dots_in_rest_parameter = false +ij_javascript_space_after_generator_mult = true +ij_javascript_space_after_property_colon = true +ij_javascript_space_after_quest = true +ij_javascript_space_after_type_colon = true +ij_javascript_space_after_unary_not = false +ij_javascript_space_before_async_arrow_lparen = true +ij_javascript_space_before_catch_keyword = true +ij_javascript_space_before_catch_left_brace = true +ij_javascript_space_before_catch_parentheses = true +ij_javascript_space_before_class_lbrace = true +ij_javascript_space_before_class_left_brace = true +ij_javascript_space_before_colon = true +ij_javascript_space_before_comma = false +ij_javascript_space_before_do_left_brace = true +ij_javascript_space_before_else_keyword = true +ij_javascript_space_before_else_left_brace = true +ij_javascript_space_before_finally_keyword = true +ij_javascript_space_before_finally_left_brace = true +ij_javascript_space_before_for_left_brace = true +ij_javascript_space_before_for_parentheses = true +ij_javascript_space_before_for_semicolon = false +ij_javascript_space_before_function_left_parenth = false +ij_javascript_space_before_generator_mult = false +ij_javascript_space_before_if_left_brace = true +ij_javascript_space_before_if_parentheses = true +ij_javascript_space_before_method_call_parentheses = false +ij_javascript_space_before_method_left_brace = true +ij_javascript_space_before_method_parentheses = false +ij_javascript_space_before_property_colon = false +ij_javascript_space_before_quest = true +ij_javascript_space_before_switch_left_brace = true +ij_javascript_space_before_switch_parentheses = true +ij_javascript_space_before_try_left_brace = true +ij_javascript_space_before_type_colon = false +ij_javascript_space_before_unary_not = false +ij_javascript_space_before_while_keyword = true +ij_javascript_space_before_while_left_brace = true +ij_javascript_space_before_while_parentheses = true +ij_javascript_spaces_around_additive_operators = true +ij_javascript_spaces_around_arrow_function_operator = true +ij_javascript_spaces_around_assignment_operators = true +ij_javascript_spaces_around_bitwise_operators = true +ij_javascript_spaces_around_equality_operators = true +ij_javascript_spaces_around_logical_operators = true +ij_javascript_spaces_around_multiplicative_operators = true +ij_javascript_spaces_around_relational_operators = true +ij_javascript_spaces_around_shift_operators = true +ij_javascript_spaces_around_unary_operator = false +ij_javascript_spaces_within_array_initializer_brackets = false +ij_javascript_spaces_within_brackets = false +ij_javascript_spaces_within_catch_parentheses = false +ij_javascript_spaces_within_for_parentheses = false +ij_javascript_spaces_within_if_parentheses = false +ij_javascript_spaces_within_imports = false +ij_javascript_spaces_within_interpolation_expressions = false +ij_javascript_spaces_within_method_call_parentheses = false +ij_javascript_spaces_within_method_parentheses = false +ij_javascript_spaces_within_object_literal_braces = false +ij_javascript_spaces_within_object_type_braces = false +ij_javascript_spaces_within_parentheses = false +ij_javascript_spaces_within_switch_parentheses = false +ij_javascript_spaces_within_type_assertion = false +ij_javascript_spaces_within_union_types = true +ij_javascript_spaces_within_while_parentheses = false +ij_javascript_special_else_if_treatment = true +ij_javascript_ternary_operation_signs_on_next_line = false +ij_javascript_ternary_operation_wrap = off +ij_javascript_union_types_wrap = on_every_item +ij_javascript_use_chained_calls_group_indents = false +ij_javascript_use_double_quotes = false +ij_javascript_use_explicit_js_extension = auto +ij_javascript_use_path_mapping = always +ij_javascript_use_public_modifier = false +ij_javascript_use_semicolon_after_statement = true +ij_javascript_var_declaration_wrap = normal +ij_javascript_while_brace_force = never +ij_javascript_while_on_new_line = false +ij_javascript_wrap_comments = false + +[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml,*.stub,.php_cs}] +max_line_length = 500 +ij_continuation_indent_size = 4 +ij_smart_tabs = true +ij_php_align_assignments = true +ij_php_align_class_constants = true +ij_php_align_group_field_declarations = true +ij_php_align_inline_comments = true +ij_php_align_key_value_pairs = true +ij_php_align_match_arm_bodies = true +ij_php_align_multiline_array_initializer_expression = true +ij_php_align_multiline_binary_operation = true +ij_php_align_multiline_chained_methods = true +ij_php_align_multiline_extends_list = true +ij_php_align_multiline_for = false +ij_php_align_multiline_parameters = false +ij_php_align_multiline_parameters_in_calls = false +ij_php_align_multiline_ternary_operation = true +ij_php_align_named_arguments = false +ij_php_align_phpdoc_comments = true +ij_php_align_phpdoc_param_names = true +ij_php_anonymous_brace_style = next_line +ij_php_api_weight = 28 +ij_php_array_initializer_new_line_after_left_brace = true +ij_php_array_initializer_right_brace_on_new_line = true +ij_php_array_initializer_wrap = on_every_item +ij_php_assignment_wrap = off +ij_php_attributes_wrap = off +ij_php_author_weight = 28 +ij_php_binary_operation_sign_on_next_line = false +ij_php_binary_operation_wrap = off +ij_php_blank_lines_after_class_header = 0 +ij_php_blank_lines_after_function = 1 +ij_php_blank_lines_after_imports = 1 +ij_php_blank_lines_after_opening_tag = 0 +ij_php_blank_lines_after_package = 1 +ij_php_blank_lines_around_class = 1 +ij_php_blank_lines_around_constants = 0 +ij_php_blank_lines_around_field = 0 +ij_php_blank_lines_around_method = 0 +ij_php_blank_lines_before_class_end = 0 +ij_php_blank_lines_before_imports = 1 +ij_php_blank_lines_before_method_body = 0 +ij_php_blank_lines_before_package = 1 +ij_php_blank_lines_before_return_statement = 0 +ij_php_blank_lines_between_imports = 0 +ij_php_block_brace_style = end_of_line +ij_php_call_parameters_new_line_after_left_paren = false +ij_php_call_parameters_right_paren_on_new_line = false +ij_php_call_parameters_wrap = normal +ij_php_catch_on_new_line = false +ij_php_category_weight = 28 +ij_php_class_brace_style = next_line +ij_php_comma_after_last_argument = true +ij_php_comma_after_last_array_element = true +ij_php_comma_after_last_closure_use_var = true +ij_php_comma_after_last_parameter = true +ij_php_concat_spaces = true +ij_php_copyright_weight = 28 +ij_php_deprecated_weight = 28 +ij_php_do_while_brace_force = always +ij_php_else_if_style = combine +ij_php_else_on_new_line = false +ij_php_example_weight = 28 +ij_php_extends_keyword_wrap = off +ij_php_extends_list_wrap = off +ij_php_fields_default_visibility = private +ij_php_filesource_weight = 28 +ij_php_finally_on_new_line = false +ij_php_for_brace_force = always +ij_php_for_statement_new_line_after_left_paren = true +ij_php_for_statement_right_paren_on_new_line = true +ij_php_for_statement_wrap = off +ij_php_force_empty_methods_in_one_line = false +ij_php_force_short_declaration_array_style = true +ij_php_getters_setters_naming_style = camel_case +ij_php_getters_setters_order_style = getters_first +ij_php_global_weight = 28 +ij_php_group_use_wrap = on_every_item +ij_php_if_brace_force = always +ij_php_if_lparen_on_next_line = false +ij_php_if_rparen_on_next_line = false +ij_php_ignore_weight = 28 +ij_php_import_sorting = by_length +ij_php_indent_break_from_case = true +ij_php_indent_case_from_switch = true +ij_php_indent_code_in_php_tags = false +ij_php_internal_weight = 28 +ij_php_keep_blank_lines_after_lbrace = 2 +ij_php_keep_blank_lines_before_right_brace = 1 +ij_php_keep_blank_lines_in_code = 2 +ij_php_keep_blank_lines_in_declarations = 2 +ij_php_keep_control_statement_in_one_line = false +ij_php_keep_first_column_comment = true +ij_php_keep_indents_on_empty_lines = false +ij_php_keep_line_breaks = true +ij_php_keep_rparen_and_lbrace_on_one_line = true +ij_php_keep_simple_classes_in_one_line = false +ij_php_keep_simple_methods_in_one_line = false +ij_php_lambda_brace_style = end_of_line +ij_php_license_weight = 28 +ij_php_line_comment_add_space = false +ij_php_line_comment_at_first_column = true +ij_php_link_weight = 28 +ij_php_lower_case_boolean_const = true +ij_php_lower_case_keywords = true +ij_php_lower_case_null_const = true +ij_php_method_brace_style = next_line +ij_php_method_call_chain_wrap = off +ij_php_method_parameters_new_line_after_left_paren = true +ij_php_method_parameters_right_paren_on_new_line = true +ij_php_method_parameters_wrap = on_every_item +ij_php_method_weight = 28 +ij_php_modifier_list_wrap = false +ij_php_multiline_chained_calls_semicolon_on_new_line = false +ij_php_namespace_brace_style = 1 +ij_php_new_line_after_php_opening_tag = true +ij_php_null_type_position = in_the_end +ij_php_package_weight = 28 +ij_php_param_weight = 0 +ij_php_parameters_attributes_wrap = off +ij_php_parentheses_expression_new_line_after_left_paren = true +ij_php_parentheses_expression_right_paren_on_new_line = true +ij_php_phpdoc_blank_line_before_tags = false +ij_php_phpdoc_blank_lines_around_parameters = true +ij_php_phpdoc_keep_blank_lines = true +ij_php_phpdoc_param_spaces_between_name_and_description = 1 +ij_php_phpdoc_param_spaces_between_tag_and_type = 1 +ij_php_phpdoc_param_spaces_between_type_and_name = 1 +ij_php_phpdoc_use_fqcn = true +ij_php_phpdoc_wrap_long_lines = true +ij_php_place_assignment_sign_on_next_line = false +ij_php_place_parens_for_constructor = 0 +ij_php_property_read_weight = 28 +ij_php_property_weight = 28 +ij_php_property_write_weight = 28 +ij_php_return_type_on_new_line = false +ij_php_return_weight = 2 +ij_php_see_weight = 28 +ij_php_since_weight = 28 +ij_php_sort_phpdoc_elements = true +ij_php_space_after_colon = true +ij_php_space_after_colon_in_enum_backed_type = true +ij_php_space_after_colon_in_named_argument = true +ij_php_space_after_colon_in_return_type = true +ij_php_space_after_comma = true +ij_php_space_after_for_semicolon = true +ij_php_space_after_quest = true +ij_php_space_after_type_cast = false +ij_php_space_after_unary_not = false +ij_php_space_before_array_initializer_left_brace = false +ij_php_space_before_catch_keyword = true +ij_php_space_before_catch_left_brace = true +ij_php_space_before_catch_parentheses = true +ij_php_space_before_class_left_brace = true +ij_php_space_before_closure_left_parenthesis = true +ij_php_space_before_colon = true +ij_php_space_before_colon_in_enum_backed_type = false +ij_php_space_before_colon_in_named_argument = false +ij_php_space_before_colon_in_return_type = false +ij_php_space_before_comma = false +ij_php_space_before_do_left_brace = true +ij_php_space_before_else_keyword = true +ij_php_space_before_else_left_brace = true +ij_php_space_before_finally_keyword = true +ij_php_space_before_finally_left_brace = true +ij_php_space_before_for_left_brace = true +ij_php_space_before_for_parentheses = true +ij_php_space_before_for_semicolon = false +ij_php_space_before_if_left_brace = true +ij_php_space_before_if_parentheses = true +ij_php_space_before_method_call_parentheses = false +ij_php_space_before_method_left_brace = true +ij_php_space_before_method_parentheses = false +ij_php_space_before_quest = true +ij_php_space_before_short_closure_left_parenthesis = true +ij_php_space_before_switch_left_brace = true +ij_php_space_before_switch_parentheses = true +ij_php_space_before_try_left_brace = true +ij_php_space_before_unary_not = false +ij_php_space_before_while_keyword = true +ij_php_space_before_while_left_brace = true +ij_php_space_before_while_parentheses = true +ij_php_space_between_ternary_quest_and_colon = false +ij_php_spaces_around_additive_operators = true +ij_php_spaces_around_arrow = false +ij_php_spaces_around_assignment_in_declare = false +ij_php_spaces_around_assignment_operators = true +ij_php_spaces_around_bitwise_operators = true +ij_php_spaces_around_equality_operators = true +ij_php_spaces_around_logical_operators = true +ij_php_spaces_around_multiplicative_operators = true +ij_php_spaces_around_null_coalesce_operator = true +ij_php_spaces_around_pipe_in_union_type = false +ij_php_spaces_around_relational_operators = true +ij_php_spaces_around_shift_operators = true +ij_php_spaces_around_unary_operator = false +ij_php_spaces_around_var_within_brackets = false +ij_php_spaces_within_array_initializer_braces = false +ij_php_spaces_within_brackets = false +ij_php_spaces_within_catch_parentheses = false +ij_php_spaces_within_for_parentheses = false +ij_php_spaces_within_if_parentheses = false +ij_php_spaces_within_method_call_parentheses = false +ij_php_spaces_within_method_parentheses = false +ij_php_spaces_within_parentheses = false +ij_php_spaces_within_short_echo_tags = true +ij_php_spaces_within_switch_parentheses = false +ij_php_spaces_within_while_parentheses = false +ij_php_special_else_if_treatment = true +ij_php_subpackage_weight = 28 +ij_php_ternary_operation_signs_on_next_line = false +ij_php_ternary_operation_wrap = off +ij_php_throws_weight = 1 +ij_php_todo_weight = 28 +ij_php_treat_multiline_arrays_and_lambdas_multiline = false +ij_php_unknown_tag_weight = 28 +ij_php_upper_case_boolean_const = false +ij_php_upper_case_null_const = false +ij_php_uses_weight = 28 +ij_php_var_weight = 28 +ij_php_variable_naming_style = camel_case +ij_php_version_weight = 28 +ij_php_while_brace_force = always +ij_php_while_on_new_line = false + +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}] +ij_json_array_wrapping = split_into_lines +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_keep_trailing_comma = false +ij_json_object_wrapping = split_into_lines +ij_json_property_alignment = do_not_align +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = false +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false + +[{*.htm,*.html,*.html.bin,*.ng,*.sht,*.shtm,*.shtml}] +ij_continuation_indent_size = 4 +ij_visual_guides = 175 +ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 +ij_html_align_attributes = true +ij_html_align_text = false +ij_html_attribute_wrap = normal +ij_html_block_comment_add_space = false +ij_html_block_comment_at_first_column = true +ij_html_do_not_align_children_of_min_lines = 0 +ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p +ij_html_do_not_indent_children_of_tags = none +ij_html_enforce_quotes = true +ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var +ij_html_keep_blank_lines = 2 +ij_html_keep_indents_on_empty_lines = false +ij_html_keep_line_breaks = true +ij_html_keep_line_breaks_in_text = true +ij_html_keep_whitespaces = false +ij_html_keep_whitespaces_inside = span,pre,textarea +ij_html_line_comment_at_first_column = true +ij_html_new_line_after_last_attribute = never +ij_html_new_line_before_first_attribute = never +ij_html_quote_style = double +ij_html_remove_new_line_before_tags = br +ij_html_space_after_tag_name = false +ij_html_space_around_equality_in_attribute = false +ij_html_space_inside_empty_tag = true +ij_html_text_wrap = normal + +[{*.markdown,*.md}] +ij_markdown_force_one_space_after_blockquote_symbol = true +ij_markdown_force_one_space_after_header_symbol = true +ij_markdown_force_one_space_after_list_bullet = true +ij_markdown_force_one_space_between_words = true +ij_markdown_insert_quote_arrows_on_wrap = true +ij_markdown_keep_indents_on_empty_lines = false +ij_markdown_keep_line_breaks_inside_text_blocks = true +ij_markdown_max_lines_around_block_elements = 1 +ij_markdown_max_lines_around_header = 1 +ij_markdown_max_lines_between_paragraphs = 1 +ij_markdown_min_lines_around_block_elements = 1 +ij_markdown_min_lines_around_header = 1 +ij_markdown_min_lines_between_paragraphs = 1 +ij_markdown_wrap_text_if_long = true +ij_markdown_wrap_text_inside_blockquotes = true + +[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}] +ij_toml_keep_indents_on_empty_lines = false + +[{*.yaml,*.yml}] +indent_size = 2 +ij_yaml_align_values_properties = do_not_align +ij_yaml_autoinsert_sequence_marker = true +ij_yaml_block_mapping_on_new_line = false +ij_yaml_indent_sequence_value = true +ij_yaml_keep_indents_on_empty_lines = false +ij_yaml_keep_line_breaks = true +ij_yaml_sequence_on_new_line = false +ij_yaml_space_before_colon = false +ij_yaml_spaces_within_braces = true +ij_yaml_spaces_within_brackets = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e9c756a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +/.github export-ignore +/tests export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.php-cs-fixer.php export-ignore +/phpunit.xml export-ignore diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..449285f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: stayallive diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..7d595c4 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,40 @@ +name: CI + +on: + pull_request: + push: + branches: + - master + - develop + - release/** + +jobs: + phpunit: + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + COMPOSER_NO_INTERACTION: 1 + + strategy: + fail-fast: false + matrix: + php: [ "8.2", "8.1" ] + + name: phpunit (PHP:${{ matrix.php }}) + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + tools: composer:v2 + + - name: Install Composer dependencies + run: composer install --no-interaction --prefer-dist --no-progress + + - name: Run phpunit + run: composer test:ci diff --git a/.github/workflows/cs.yaml b/.github/workflows/cs.yaml new file mode 100644 index 0000000..13159ab --- /dev/null +++ b/.github/workflows/cs.yaml @@ -0,0 +1,27 @@ +name: Code style + +on: + pull_request: + push: + branches: + - master + - develop + +jobs: + php-cs-fixer: + name: PHP-CS-Fixer + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + + - name: Install dependencies + run: composer update --no-progress --no-interaction --prefer-dist + + - name: Run script + run: composer phpcs:ci diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..10a74b1 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,16 @@ +name: Release + +on: + push: + tags: + - "v*.*.*" + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Create GitHub release + uses: softprops/action-gh-release@v1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8fcd68d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.lock +/.idea +/vendor +/.phpunit.cache +/.php-cs-fixer.cache +/.phpunit.result.cache diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..70e2b2f --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,70 @@ +in(__DIR__ . '/src') + ->in(__DIR__ . '/tests') + ->name('*.php') + ->ignoreDotFiles(true) + ->ignoreVCS(true); + +$config = new PhpCsFixer\Config; + +$config + ->setRules([ + '@Symfony' => true, + + 'yoda_style' => false, + 'phpdoc_order' => true, + 'new_with_braces' => false, + 'short_scalar_cast' => true, + 'phpdoc_to_comment' => false, + 'single_line_throw' => false, + 'single_blank_line_at_eof' => true, + 'no_superfluous_phpdoc_tags' => false, + 'linebreak_after_opening_tag' => true, + 'class_attributes_separation' => false, + 'not_operator_with_successor_space' => false, + 'single_trait_insert_per_statement' => false, + 'nullable_type_declaration_for_default_null_value' => true, + + 'concat_space' => [ + 'spacing' => 'one', + ], + 'binary_operator_spaces' => [ + 'operators' => [ + '|' => null, + '=' => 'align_single_space', + '=>' => 'align_single_space', + ], + ], + 'array_syntax' => [ + 'syntax' => 'short', + ], + 'ordered_imports' => [ + 'sort_algorithm' => 'length', + ], + 'cast_spaces' => [ + 'space' => 'none', + ], + 'align_multiline_comment' => [ + 'comment_type' => 'phpdocs_like', + ], + 'phpdoc_align' => [ + 'align' => 'vertical', + ], + 'increment_style' => [ + 'style' => 'post', + ], + 'phpdoc_no_alias_tag' => [ + 'replacements' => [ + 'type' => 'var', + 'link' => 'see', + ], + ], + 'no_extra_blank_lines' => [ + 'tokens' => [], + ], + ]) + ->setFinder($finder); + +return $config; diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..a7905bf --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2022 Alex Bouma + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6318b76 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# Laravel Inverse Relations + +[![Latest Version](https://img.shields.io/github/release/stayallive/laravel-inverse-relations.svg?style=flat-square)](https://github.com/stayallive/laravel-inverse-relations/releases) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) +[![Build Status](https://img.shields.io/github/workflow/status/stayallive/laravel-inverse-relations/CI/master.svg?style=flat-square)](https://github.com/stayallive/laravel-inverse-relations/actions/workflows/ci.yaml) +[![Total Downloads](https://img.shields.io/packagist/dt/stayallive/laravel-inverse-relations.svg?style=flat-square)](https://packagist.org/packages/stayallive/laravel-inverse-relations) + +Inverse relations for Laravel Eloquent models. + +[Jonathan Reinink](https://github.com/reinink) wrote a great blog post about [optimizing circular relationships in Laravel](https://reinink.ca/articles/optimizing-circular-relationships-in-laravel). This [package](https://github.com/archtechx/laravel-hasmanywithinverse) ran with that idea and implemented it for the `hasMany` relation. This package tries to improve on that by implementing it for the `hasOne` and `morphMany` relations too. + +## Installation + +```bash +composer require stayallive/laravel-inverse-relations +``` + +## Usage + +Adding the `HasHasManyWithInverseRelation`, `HasHasOneWithInverseRelation` and/or `HasMorphManyWithInverseRelation` trait will provide you with the helper methods to setup the inverse relations. + +```php +getKeyName(); + } +} +``` + +## Security Vulnerabilities + +If you discover a security vulnerability within this package, please send an e-mail to Alex Bouma at `alex+security@bouma.me`. All security vulnerabilities will be swiftly addressed. + +## License + +This package is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..448ab46 --- /dev/null +++ b/composer.json @@ -0,0 +1,52 @@ +{ + "name": "stayallive/laravel-inverse-relations", + "type": "library", + "description": "HasMany, HasOne and MorphMany Eloquent relations with inverse improvements.", + "keywords": [ + "laravel", + "eloquent", + "relations" + ], + "homepage": "https://github.com/stayallive/laravel-inverse-relations", + "license": "MIT", + "authors": [ + { + "name": "Alex Bouma", + "email": "alex@bouma.me" + } + ], + "require": { + "php": "^8.1", + "laravel/framework": "^9.0|^10" + }, + "autoload": { + "psr-4": { + "Stayallive\\Laravel\\Eloquent\\Relations\\": "src/" + } + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.16", + "orchestra/testbench": "^8.0", + "pestphp/pest": "^2.4", + "phpunit/phpunit": "^10.0" + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "scripts": { + "test": "vendor/bin/pest --stop-on-failure", + "test:ci": "vendor/bin/pest", + "phpcs": "vendor/bin/php-cs-fixer fix", + "phpcs:ci": "vendor/bin/php-cs-fixer fix --dry-run --diff" + }, + "config": { + "sort-packages": true, + "preferred-install": "dist", + "optimize-autoloader": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..767e229 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + + + + diff --git a/src/HasHasManyWithInverseRelation.php b/src/HasHasManyWithInverseRelation.php new file mode 100644 index 0000000..016d029 --- /dev/null +++ b/src/HasHasManyWithInverseRelation.php @@ -0,0 +1,16 @@ +newRelatedInstance($related); + $localKey = $localKey ?: $this->getKeyName(); + $foreignKey = $foreignKey ?: $this->getForeignKey(); + + return new HasManyWithInverseRelation($instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey, $inverse); + } +} diff --git a/src/HasHasOneWithInverseRelation.php b/src/HasHasOneWithInverseRelation.php new file mode 100644 index 0000000..ed8be2f --- /dev/null +++ b/src/HasHasOneWithInverseRelation.php @@ -0,0 +1,16 @@ +newRelatedInstance($related); + $localKey = $localKey ?: $this->getKeyName(); + $foreignKey = $foreignKey ?: $this->getForeignKey(); + + return new HasOneWithInverseRelation($instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey, $inverse); + } +} diff --git a/src/HasManyWithInverseRelation.php b/src/HasManyWithInverseRelation.php new file mode 100644 index 0000000..6230b63 --- /dev/null +++ b/src/HasManyWithInverseRelation.php @@ -0,0 +1,24 @@ + + */ +class HasManyWithInverseRelation extends HasMany +{ + use WithInverseOneOrManyRelation; + + public function __construct(Builder $query, Model $parent, string $foreignKey, string $localKey, string $relationToParent) + { + $this->relationToParent = $relationToParent; + + parent::__construct($query, $parent, $foreignKey, $localKey); + } +} diff --git a/src/HasMorphManyWithInverseRelation.php b/src/HasMorphManyWithInverseRelation.php new file mode 100644 index 0000000..448a33e --- /dev/null +++ b/src/HasMorphManyWithInverseRelation.php @@ -0,0 +1,33 @@ +newRelatedInstance($related); + + // Here we will gather up the morph type and ID for the relationship so that we + // can properly query the intermediate table of a relation. Finally, we will + // get the table and create the relationship instances for the developers. + [$type, $id] = $this->getMorphs($name, $type, $id); + + $table = $instance->getTable(); + + $localKey = $localKey ?: $this->getKeyName(); + + return new MorphManyWithInverseRelation($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $localKey, $name); + } +} diff --git a/src/HasOneWithInverseRelation.php b/src/HasOneWithInverseRelation.php new file mode 100644 index 0000000..8efceef --- /dev/null +++ b/src/HasOneWithInverseRelation.php @@ -0,0 +1,24 @@ + + */ +class HasOneWithInverseRelation extends HasOne +{ + use WithInverseOneOrManyRelation; + + public function __construct(Builder $query, Model $parent, string $foreignKey, string $localKey, string $relationToParent) + { + $this->relationToParent = $relationToParent; + + parent::__construct($query, $parent, $foreignKey, $localKey); + } +} diff --git a/src/MorphManyWithInverseRelation.php b/src/MorphManyWithInverseRelation.php new file mode 100644 index 0000000..2339c63 --- /dev/null +++ b/src/MorphManyWithInverseRelation.php @@ -0,0 +1,24 @@ + + */ +class MorphManyWithInverseRelation extends MorphMany +{ + use WithInverseOneOrManyRelation; + + public function __construct(Builder $query, Model $parent, $type, $id, $localKey, string $relationToParent) + { + $this->relationToParent = $relationToParent; + + parent::__construct($query, $parent, $type, $id, $localKey); + } +} diff --git a/src/WithInverseOneOrManyRelation.php b/src/WithInverseOneOrManyRelation.php new file mode 100644 index 0000000..400ad1f --- /dev/null +++ b/src/WithInverseOneOrManyRelation.php @@ -0,0 +1,65 @@ +related->newInstance($attributes), function (Model $instance) { + $this->setForeignAttributesForCreate($instance); + + $instance->setRelation($this->relationToParent, $this->getParent()); + + $instance->save(); + }); + } + + public function getResults() + { + /** @var \Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model $resultOrResults */ + $resultOrResults = parent::getResults(); + + if ($resultOrResults instanceof Model) { + $resultOrResults->setRelation($this->relationToParent, $this->getParent()); + } elseif ($resultOrResults instanceof Collection) { + $resultOrResults->each(function (Model $model) { + $model->setRelation($this->relationToParent, $this->getParent()); + }); + } else { + throw_unless($resultOrResults === null, new \RuntimeException('Unexpected result value encountered.')); + } + + return $resultOrResults; + } + + protected function matchOneOrMany(array $models, Collection $results, $relation, $type): array + { + $result = parent::matchOneOrMany($models, $results, $relation, $type); + + /** @var \Illuminate\Database\Eloquent\Model $model */ + foreach ($result as $model) { + if ($model->relationLoaded($relation)) { + /** @var \Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model $relatedModelOrModels */ + $relatedModelOrModels = $model->getRelation($relation); + + if ($relatedModelOrModels instanceof Model) { + $relatedModelOrModels->setRelation($this->relationToParent, $model); + } elseif ($relatedModelOrModels instanceof Collection) { + $relatedModelOrModels->each(function (Model $relatedModel) use ($model) { + $relatedModel->setRelation($this->relationToParent, $model); + }); + } else { + throw_unless($relatedModelOrModels === null, new \RuntimeException('Unexpected relation value encountered.')); + } + } + } + + return $result; + } +} diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..df42408 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,3 @@ +in('Unit'); diff --git a/tests/Stubs/HasManyWithInverse/ChildModel.php b/tests/Stubs/HasManyWithInverse/ChildModel.php new file mode 100644 index 0000000..e9735b7 --- /dev/null +++ b/tests/Stubs/HasManyWithInverse/ChildModel.php @@ -0,0 +1,19 @@ +belongsTo(ParentModel::class, 'parent_id'); + } +} diff --git a/tests/Stubs/HasManyWithInverse/ParentModel.php b/tests/Stubs/HasManyWithInverse/ParentModel.php new file mode 100644 index 0000000..4bd0a70 --- /dev/null +++ b/tests/Stubs/HasManyWithInverse/ParentModel.php @@ -0,0 +1,26 @@ +hasManyWithInverse(ChildModel::class, 'parent', 'parent_id'); + } +} diff --git a/tests/Stubs/HasOneWithInverse/ChildModel.php b/tests/Stubs/HasOneWithInverse/ChildModel.php new file mode 100644 index 0000000..ac0a4eb --- /dev/null +++ b/tests/Stubs/HasOneWithInverse/ChildModel.php @@ -0,0 +1,19 @@ +belongsTo(ParentModel::class, 'parent_id'); + } +} diff --git a/tests/Stubs/HasOneWithInverse/ParentModel.php b/tests/Stubs/HasOneWithInverse/ParentModel.php new file mode 100644 index 0000000..cbd9a4b --- /dev/null +++ b/tests/Stubs/HasOneWithInverse/ParentModel.php @@ -0,0 +1,26 @@ +hasOneWithInverse(ChildModel::class, 'parent', 'parent_id'); + } +} diff --git a/tests/Stubs/MorphManyWithInverse/CommentModel.php b/tests/Stubs/MorphManyWithInverse/CommentModel.php new file mode 100644 index 0000000..c0db584 --- /dev/null +++ b/tests/Stubs/MorphManyWithInverse/CommentModel.php @@ -0,0 +1,23 @@ +morphTo(); + } +} diff --git a/tests/Stubs/MorphManyWithInverse/PostModel.php b/tests/Stubs/MorphManyWithInverse/PostModel.php new file mode 100644 index 0000000..408af08 --- /dev/null +++ b/tests/Stubs/MorphManyWithInverse/PostModel.php @@ -0,0 +1,26 @@ +morphManyWithInverse(CommentModel::class, 'commentable'); + } +} diff --git a/tests/Unit/HasManyWithInverseTest.php b/tests/Unit/HasManyWithInverseTest.php new file mode 100644 index 0000000..21464e0 --- /dev/null +++ b/tests/Unit/HasManyWithInverseTest.php @@ -0,0 +1,109 @@ +bigIncrements('id'); + }); + + Schema::dropIfExists('test_hasmanywithinverse_children'); + Schema::create('test_hasmanywithinverse_children', function (Blueprint $table) { + $table->bigIncrements('id'); + + $table->unsignedBigInteger('parent_id'); + }); +}); + +test('children have the parent relationship automatically set when being created', function () { + /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + /** @var \Tests\Stubs\HasManyWithInverse\ChildModel $child */ + $child = $parent->children()->create([]); + + expect($child->relationLoaded('parent'))->toBeTrue(); + expect($child->getRelations()['parent']->id)->toBe($parent->id); +}); + +test('children have the parent relationship automatically set when being created using create many', function () { + /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + /** @var \Tests\Stubs\HasManyWithInverse\ChildModel $child1 */ + /** @var \Tests\Stubs\HasManyWithInverse\ChildModel $child2 */ + [$child1, $child2] = $parent->children()->createMany([[], []]); + + expect($child1->relationLoaded('parent'))->toBeTrue(); + expect($child1->getRelations()['parent']->id)->toBe($parent->id); + + expect($child2->relationLoaded('parent'))->toBeTrue(); + expect($child2->getRelations()['parent']->id)->toBe($parent->id); +}); + +test('children have the parent relationship automatically set in creating event', function () { + $parentId = null; + + /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::creating(function (ChildModel $child) use (&$parentId) { + if ($child->relationLoaded('parent')) { + $parentId = $child->getRelations()['parent']->id; + } + }); + + $parent->children()->create([]); + + expect($parentId)->toBe($parent->id); +}); + +test('children have the parent relationship automatically set in saving event', function () { + $parentId = null; + + /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::saving(function (ChildModel $child) use (&$parentId) { + if ($child->relationLoaded('parent')) { + $parentId = $child->getRelations()['parent']->id; + } + }); + + $parent->children()->create([]); + + expect($parentId)->toBe($parent->id); +}); + +test('when creating, the children have the parent relationship automatically set when being resolved', function () { + /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::create(['parent_id' => $parent->id]); + + /** @var \Tests\Stubs\HasManyWithInverse\ChildModel $child */ + $child = $parent->children->first(); + + expect($child->relationLoaded('parent'))->toBeTrue(); + expect($child->getRelations()['parent']->id)->toBe($parent->id); +}); + +test('when creating, the children have the parent relationship automatically set when being eager loaded', function () { + /** @var \Tests\Stubs\HasManyWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::create(['parent_id' => $parent->id]); + + // Load the parent from the database and eager load the relation + $parent = $parent->fresh('children'); + + /** @var \Tests\Stubs\HasManyWithInverse\ChildModel $child */ + $child = $parent->children->first(); + + expect($child->relationLoaded('parent'))->toBeTrue(); + expect($child->getRelations()['parent']->id)->toBe($parent->id); +}); diff --git a/tests/Unit/HasOneWithInverseTest.php b/tests/Unit/HasOneWithInverseTest.php new file mode 100644 index 0000000..c2dc7b1 --- /dev/null +++ b/tests/Unit/HasOneWithInverseTest.php @@ -0,0 +1,92 @@ +bigIncrements('id'); + }); + + Schema::dropIfExists('test_hasonewithinverse_children'); + Schema::create('test_hasonewithinverse_children', function (Blueprint $table) { + $table->bigIncrements('id'); + + $table->unsignedBigInteger('parent_id'); + }); +}); + +test('child has the parent relationship automatically set when being created', function () { + /** @var \Tests\Stubs\HasOneWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + /** @var \Tests\Stubs\HasOneWithInverse\ChildModel $child */ + $child = $parent->child()->create([]); + + expect($child->relationLoaded('parent'))->toBeTrue(); + expect($child->getRelations()['parent']->id)->toBe($parent->id); +}); + +test('child has the parent relationship automatically set in creating event', function () { + $parentId = null; + + /** @var \Tests\Stubs\HasOneWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::creating(function (ChildModel $child) use (&$parentId) { + if ($child->relationLoaded('parent')) { + $parentId = $child->getRelations()['parent']->id; + } + }); + + $parent->child()->create([]); + + expect($parentId)->toBe($parent->id); +}); + +test('child has the parent relationship automatically set in saving event', function () { + $parentId = null; + + /** @var \Tests\Stubs\HasOneWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::saving(function (ChildModel $child) use (&$parentId) { + if ($child->relationLoaded('parent')) { + $parentId = $child->getRelations()['parent']->id; + } + }); + + $parent->child()->create([]); + + expect($parentId)->toBe($parent->id); +}); + +test('when creating, the child has the parent relationship automatically set when being resolved', function () { + /** @var \Tests\Stubs\HasOneWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::create(['parent_id' => $parent->id]); + + $child = $parent->child; + + expect($child->relationLoaded('parent'))->toBeTrue(); + expect($child->getRelations()['parent']->id)->toBe($parent->id); +}); + +test('when creating, the child has the parent relationship automatically set when being eager loaded', function () { + /** @var \Tests\Stubs\HasOneWithInverse\ParentModel $parent */ + $parent = ParentModel::create([]); + + ChildModel::create(['parent_id' => $parent->id]); + + // Load the parent from the database and eager load the relation + $parent = $parent->fresh('child'); + + $child = $parent->child; + + expect($child->relationLoaded('parent'))->toBeTrue(); + expect($child->getRelations()['parent']->id)->toBe($parent->id); +}); diff --git a/tests/Unit/MorphManyWithInverseTest.php b/tests/Unit/MorphManyWithInverseTest.php new file mode 100644 index 0000000..cdd2823 --- /dev/null +++ b/tests/Unit/MorphManyWithInverseTest.php @@ -0,0 +1,116 @@ +bigIncrements('id'); + }); + + Schema::dropIfExists('test_morphmanywithinverse_comments'); + Schema::create('test_morphmanywithinverse_comments', function (Blueprint $table) { + $table->bigIncrements('id'); + + $table->unsignedBigInteger('commentable_id'); + $table->string('commentable_type'); + }); +}); + +test('children have the parent relationship automatically set when being created', function () { + /** @var \Tests\Stubs\MorphManyWithInverse\PostModel $parent */ + $parent = PostModel::create([]); + + /** @var \Tests\Stubs\MorphManyWithInverse\CommentModel $child */ + $child = $parent->comments()->create([]); + + expect($child->relationLoaded('commentable'))->toBeTrue(); + expect($child->getRelations()['commentable']->id)->toBe($parent->id); +}); + +test('children have the parent relationship automatically set when being created using create many', function () { + /** @var \Tests\Stubs\MorphManyWithInverse\PostModel $parent */ + $parent = PostModel::create([]); + + /** @var \Tests\Stubs\MorphManyWithInverse\CommentModel $child1 */ + /** @var \Tests\Stubs\MorphManyWithInverse\CommentModel $child2 */ + [$child1, $child2] = $parent->comments()->createMany([[], []]); + + expect($child1->relationLoaded('commentable'))->toBeTrue(); + expect($child1->getRelations()['commentable']->id)->toBe($parent->id); + + expect($child2->relationLoaded('commentable'))->toBeTrue(); + expect($child2->getRelations()['commentable']->id)->toBe($parent->id); +}); + +test('children have the parent relationship automatically set in creating event', function () { + $parentId = null; + + /** @var \Tests\Stubs\MorphManyWithInverse\PostModel $parent */ + $parent = PostModel::create([]); + + CommentModel::creating(function (CommentModel $child) use (&$parentId) { + if ($child->relationLoaded('commentable')) { + $parentId = $child->getRelations()['commentable']->id; + } + }); + + $parent->comments()->create([]); + + expect($parentId)->toBe($parent->id); +}); + +test('children have the parent relationship automatically set in saving event', function () { + $parentId = null; + + /** @var \Tests\Stubs\MorphManyWithInverse\PostModel $parent */ + $parent = PostModel::create([]); + + CommentModel::saving(function (CommentModel $child) use (&$parentId) { + if ($child->relationLoaded('commentable')) { + $parentId = $child->getRelations()['commentable']->id; + } + }); + + $parent->comments()->create([]); + + expect($parentId)->toBe($parent->id); +}); + +test('when creating, the children have the parent relationship automatically set when being resolved', function () { + /** @var \Tests\Stubs\MorphManyWithInverse\PostModel $parent */ + $parent = PostModel::create([]); + + CommentModel::create([ + 'commentable_id' => $parent->id, + 'commentable_type' => PostModel::class, + ]); + + /** @var \Tests\Stubs\MorphManyWithInverse\CommentModel $child */ + $child = $parent->comments->first(); + + expect($child->relationLoaded('commentable'))->toBeTrue(); + expect($child->getRelations()['commentable']->id)->toBe($parent->id); +}); + +test('when creating, the children have the parent relationship automatically set when being eager loaded', function () { + /** @var \Tests\Stubs\MorphManyWithInverse\PostModel $parent */ + $parent = PostModel::create([]); + + CommentModel::create([ + 'commentable_id' => $parent->id, + 'commentable_type' => PostModel::class, + ]); + + // Load the parent from the database and eager load the relation + $parent = $parent->fresh('comments'); + + /** @var \Tests\Stubs\MorphManyWithInverse\CommentModel $child */ + $child = $parent->comments->first(); + + expect($child->relationLoaded('commentable'))->toBeTrue(); + expect($child->getRelations()['commentable']->id)->toBe($parent->id); +}); diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..d21c14d --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,3 @@ +