VichUploader : MediaObject is not uploadable - symfony

I try to upload file throught a REST API with API Plateform
I followed the doc, but I got :
"The class \"App\\Entity\\MediaObject\" is not uploadable. If you use attributes to configure VichUploaderBundle, you probably just forgot to add `#[Vich\\Uploadable]` on top of your entity. If you don't use attributes, check that the configuration files are in the right place. In both cases, clearing the cache can also solve the issue.",
I'am using :
"api-platform/core": "^3.0",
"vich/uploader-bundle": "^2.0"
My config :
# api/config/packages/vich_uploader.yaml
vich_uploader:
db_driver: orm
metadata:
type: attribute
mappings:
media_object:
uri_prefix: /media
upload_destination: '%kernel.project_dir%/public/media'
namer: Vich\UploaderBundle\Naming\OrignameNamer
My entity :
<?php
// api/src/Entity/MediaObject.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\Controller\CreateMediaObjectAction;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
#[Vich\Uploadable]
#[ORM\Entity]
#[ApiResource(
normalizationContext: ['groups' => ['media_object:read']],
types: ['https://schema.org/MediaObject'],
operations: [
new Get(),
new GetCollection(),
new Post(
controller: CreateMediaObjectAction::class,
deserialize: false,
validationContext: ['groups' => ['Default', 'media_object_create']],
openapiContext: [
'requestBody' => [
'content' => [
'multipart/form-data' => [
'schema' => [
'type' => 'object',
'properties' => [
'file' => [
'type' => 'string',
'format' => 'binary'
]
]
]
]
]
]
]
)
]
)]
class MediaObject
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
private ?int $id = null;
#[ApiProperty(types: ['https://schema.org/contentUrl'])]
#[Groups(['media_object:read'])]
public ?string $contentUrl = null;
#[Vich\UploadableField(mapping: "media_object", fileNameProperty: "filePath")]
#[Assert\NotNull(groups: ['media_object_create'])]
public ?File $file = null;
#[ORM\Column(nullable: true)]
public ?string $filePath = null;
public function getId(): ?int
{
return $this->id;
}
}

In my case this resolved the problem:
composer require doctrine/annotations

Related

File fixture with Alice

Is there a way to have a fixture with a file, with hautelook/alice-bundle ?
I'm trying to do :
App\Entity\MediaObject:
media_object_1:
file: '<file("./fixtures/files", "./public/media", true)>'
But this is not working, because the file function return a string, and not the file itself
<?php
namespace App\Entity;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use App\Controller\CreateMediaObjectAction;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
#[Vich\Uploadable]
#[ORM\Entity]
#[ApiResource(
normalizationContext: ['groups' => ['media_object:read']],
types: ['https://schema.org/MediaObject'],
operations: [
new Get(),
new GetCollection(),
new Post(
controller: CreateMediaObjectAction::class,
deserialize: false,
validationContext: ['groups' => ['Default', 'media_object_create']],
openapiContext: [
'requestBody' => [
'content' => [
'multipart/form-data' => [
'schema' => [
'type' => 'object',
'properties' => [
'file' => [
'type' => 'string',
'format' => 'binary'
]
]
]
]
]
]
]
),
new Delete()
]
)]
class MediaObject
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
#[Groups(['media_object:read'])]
private ?int $id = null;
#[ApiProperty(types: ['https://schema.org/contentUrl'])]
#[Groups(['media_object:read'])]
public ?string $contentUrl = null;
#[Vich\UploadableField(mapping: "media_object", fileNameProperty: "filePath")]
#[Assert\NotNull(groups: ['media_object_create'])]
public ?File $file = null;
#[ORM\Column(nullable: true)]
public ?string $filePath = null;
public function getId(): ?int
{
return $this->id;
}
}
When I launch the fixture command, i got :
In HydrationExceptionFactory.php line 67:
Invalid value given for the property "file" of the object "media_object_1" (class: App\Entity\MediaObject).
In PropertyAccessor.php line 213:
Expected argument of type "?Symfony\Component\HttpFoundation\File\File", "string" given at property path "file".
In PropertyAccessor.php line 530:
Cannot assign string to property App\Entity\MediaObject::$file of type ?Symfony\Component\HttpFoundation\File\File

Connect Woltlab with Symfony

Hello I would like to link my forum (forum software: Woltlab) with symfony 6....
I am currently trying to do so like this:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
class DashboardController extends AbstractController
{
#[Route('/', name: 'app_dashboard')]
public function index(): Response
{
require_once('/home/maybemc-main/htdocs/maybemc.net/global.php');
$username = wcf\system\WCF::getUser()->mcName;
$id = wcf\system\WCF::getUser()->userID;
$avatar = wcf\system\WCF::getUserProfileHandler()->getAvatar()->getUrl(35);
if (!wcf\system\WCF::getSession()->getPermission('levi.perms.canSeePanel')){
header('HTTP/1.0 403 Forbidden');
die('Du hast darauf keine Berechtigung!');
}
$client = new Client();
$response = $client->get('http://**.***.***.***:8080/teamchat/messages');
$TCList = json_decode($response->getBody(), true);
return $this->render('dashboard/index.html.twig', [
'username' => $username,
'id' => $id,
'avatar' => $avatar,
'controller_name' => 'DashboardController',
'TCList' => $TCList
]);
}
}
unfortunately I get the error "Class "App\Controller\wcf\system\WCF" not found"
Do any of you have any idea why this is not working?
I also tried to add also the global.php to the service.yaml like this:
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
- '/home/maybemc-main/htdocs/maybemc.net/global.php'

Unable to generate a URL for the named route "admin_app_sonatauseruser_create" after renaming SonataUserUser entity

My application worked fine until I decided to rename SonataUserUser to User and SonataUserUserGroup to group.
This is how my user entity looks like
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sonata\UserBundle\Entity\BaseUser;
/**
* #ORM\Entity
* #ORM\Table(name="users")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
protected $id;
.....
public function __construct()
{
parent::__construct();
}
public function __toString()
{
return $this->getFirstName() === null ? 'New' : $this->getFullname();
}
}
App\Admin\UserAdmin
declare(strict_types=1);
namespace App\Admin;
use FOS\UserBundle\Model\UserManagerInterface;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Form\Type\ModelType;
use Sonata\AdminBundle\Show\ShowMapper;
use Sonata\Form\Type\DatePickerType;
use Sonata\UserBundle\Form\Type\SecurityRolesType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\LocaleType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TimezoneType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Sonata\UserBundle\Admin\Model\UserAdmin as BaseUserAdmin;
class UserAdmin extends BaseUserAdmin
{
protected $translationDomain = 'SonataBundle';
/**
* {#inheritdoc}
*/
protected function configureShowFields(ShowMapper $showMapper): void
{
$showMapper
->with('General')
->add('username')
->add('email')
->end()
->with('Groups')
->add('groups')
->end()
->with('Profile')
->add('dateOfBirth')
->add('firstname')
->add('lastname')
->add('website')
->add('biography')
->add('gender')
->add('locale')
->add('timezone')
->add('phone')
->end()
;
}
/**
* {#inheritdoc}
*/
protected function configureFormFields(FormMapper $formMapper): void
{
// define group zoning
$formMapper
->tab('Details')
->with('Profile', ['class' => 'col-md-6'])->end()
->with('General', ['class' => 'col-md-6'])->end()
->with('Social', ['class' => 'col-md-6'])->end()
->end();
$now = new \DateTime();
$genderOptions = [
'choices' => \call_user_func([$this->getUserManager()->getClass(), 'getGenderList']),
'required' => true,
'translation_domain' => $this->getTranslationDomain(),
];
$formMapper
->tab('Details')
->with('General')
->add('username')
->add('email')
->add('plainPassword', PasswordType::class, [
'required' => (!$this->getSubject() || null === $this->getSubject()->getId()),
'label' => 'Password',
'help' => 'Updating this field will change your password.'
])
->end()
->with('Profile')
->add('firstname', null, ['required' => false])
->add('lastname', null, ['required' => false])
->add('dateOfBirth', DatePickerType::class, [
'required' => false,
])
->add('gender', ChoiceType::class, $genderOptions)
->add('locale', LocaleType::class, ['required' => false])
->add('timezone', TimezoneType::class, ['required' => false])
->add('phone', null, ['required' => false])
->end()
->end();
}
}
config/routes/sonata_admin.yaml
admin_area:
resource: "#SonataAdminBundle/Resources/config/routing/sonata_admin.xml"
prefix: /admin
_sonata_admin:
resource: .
type: sonata_admin
prefix: /admin
config/packages/sonata_user
sonata_user:
security_acl: false
manager_type: orm
class:
user: App\Entity\User
group: App\Entity\Group
mailer: sonata.user.mailer.default
impersonating:
route: sonata_admin_dashboard
table:
user_group: "users_groups"
The error I get is An exception has been thrown during the rendering of a template ("Unable to generate a URL for the named route "admin_app_sonatausergroup_create" as such route does not exist."). in in vendor/sonata-project/admin-bundle/src/Resources/views/Block/block_admin_list.html.twig (line 28).
I'd appreciate any form of help
What does php bin/console debug:router return? You could find the route name that is being used I would expect. Example output from one that I have in development:
dashboard ANY ANY ANY /account/dashboard
home ANY ANY ANY /
app_register ANY ANY ANY /register
app_login ANY ANY ANY /login
app_logout ANY ANY ANY /logout

Sylius Grid EntityFilter - sort or use repository

I added a large entity filter to one of my Sylius grid configurations. I haven't found any configuration options besides class name and from the looks of it, option values are just ordered by ID. Is there a way to use a repository method or at least provide sort field? Do I need to use a custom filter for this?
You can define what repository method to use on your YAML file and what arguments you want to send to that method:
sylius_grid:
grids:
app_user: # Your grid name
driver:
name: doctrine/orm
options:
class: "%app.model.user%"
repository:
method: myCustomMethod
arguments:
id: resource.id
sorting:
name: asc
limits: [10, 25, 50, 100]
Check the Sylius Grid Bundle documentation for more information: Configuration Reference
Here's how to define a new type :
final class CustomFilterType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'shop',
EntityType::class,
[
'class' => Shop::class,
'label' => false,
'multiple' => true, //if you need multiple selection
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('s');
// define your query builder here
},
'choice_label' => function ($shop) { /** #var $shop Shop */
return $shop->getName();
},
]
);
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix(): string
{
return 'sylius_grid_filter_entity_multiple';
}
}
Then in your services.yaml :
app.grid_filter.custom_filter:
class: Sylius\Component\Grid\Filter\SelectFilter
tags: [{
name: 'sylius.grid_filter',
type: 'custom_type',
form_type: App\Form\Grid\Filter\CustomFilterType
}]
And finally, in your grid definition:
filters:
shops:
type: custom_type
label: app.ui.shops

Sylius EntityFilter choice from a part of resources

I used a Sylius 1.0.0-beta1 and ported EntityFilter from dev-master due to lack of this functionality in last stable version. Everything works fine but is there any way of choosing not from all resources but only from part of them?
I need to make a filter based on Taxonomies. I have a few taxons which are city names and all of them have parent taxon called City (code: city). So I want to display in that filter all children of city taxon.
My grid configuration is shown below:
sylius_grid:
grids:
smartbyte_admin_products_by_event_archetype:
...
filters:
...
taxon:
type: app_entity
options:
fields: [taxon.id]
class: "%sylius.model.taxon.class%"
city:
type: app_taxon
The first filter from configuration works and filters fine, except it takes all taxons, but I need to show only some.
I tried also make my own filter (the second one) but I get a text field instead of entity field in filter. Following the docs I created custom one. Here is my try:
<?php
namespace SyliusExtensionBundle\Form\Type\Filter;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class TaxonFilterType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('city', EntityType::class, array(
'class' => 'Sylius\Component\Core\Model\Taxon',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('t')
->leftJoin('t.parent', 'taxon')
->where("taxon.code = 'city'");
},
'label' => 'Miasto',
'required' => false
));
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'label' => false,
'placeholder' => 'sylius.ui.all',
])
->setDefined('fields')
->setAllowedTypes('fields', 'array')
;
}
/**
* {#inheritdoc}
*/
public function getName()
{
return 'sylius_grid_filter_taxon';
}
}
Service configuration:
services:
sylius.grid_filter.entity:
class: SyliusExtensionBundle\Grid\Filter\EntityFilter
tags:
- { name: sylius.grid_filter, type: app_entity, form-type: SyliusExtensionBundle\Form\Type\Filter\EntityFilterType }
- { name: sylius.grid_filter, type: app_taxon, form-type: SyliusExtensionBundle\Form\Type\Filter\EntityFilterType }
sylius.form.type.grid_filter.entity:
class: SyliusExtensionBundle\Form\Type\Filter\EntityFilterType
tags:
- { name: form.type, alias: sylius_grid_filter_entity }
app.form.type.grid_filter.taxon:
class: SyliusExtensionBundle\Form\Type\Filter\TaxonFilterType
tags:
- { name: form.type, alias: sylius_grid_filter_taxon }
And lastly filter templates:
sylius_grid:
templates:
filter:
app_entity: "SyliusExtensionBundle:Grid/Filter:entity.html.twig"
app_taxon: "SyliusExtensionBundle:Grid/Filter:entity.html.twig"
Please guide my how can I restrict EntityFilter or how to make the custom filter work. I spent many hours on this subject and cannot see whereis the error.
Current effect below:
EDIT:
Current TaxonFilterType according to Paweł Jędrzejewski tips. Still doesn't work and dont detect fields option in configuration.
<?php
/**
* Created by PhpStorm.
* User: Krzysztof Wędrowicz krzysztof#wedrowicz.me
* Date: 23.01.17
* Time: 14:56
*/
namespace SyliusExtensionBundle\Form\Type\Filter;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class TaxonFilterType extends AbstractType {
public function getParent()
{
return EntityType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'label' => false,
'placeholder' => 'sylius.ui.all',
'class' => 'Sylius\Component\Core\Model\Taxon',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('t')
->leftJoin('t.parent', 'taxon')
->where("taxon.code = 'city'")
;
},
'required' => false
])
->setDefined('fields')
->setAllowedTypes('fields', 'array')
;
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'sylius_grid_filter_city';
}
}
Currently this is not possible via configuration. I will add it to the backlog, but not sure when it can be implemented. That being said, your custom filter is a good idea. You should do a small change and it should work: The form type should have EntityType::class in getParent() instead of using the buildForm method. And the custom query builder should be configured in configureOptions method, then it will render a proper field. Here is full code that should work:
<?php
namespace AcmeExtension\Form\Type\Filter;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class CityFilterType extends AbstractType
{
public function getParent()
{
return EntityType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'label' => false,
'placeholder' => 'sylius.ui.all',
'class' => 'Sylius\Component\Core\Model\Taxon',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('t')
->leftJoin('t.parent', 'taxon')
->where("taxon.code = 'city'")
;
},
'required' => false
])
->setDefined('fields')
->setAllowedTypes('fields', 'array')
;
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'sylius_grid_filter_city';
}
}

Resources