Jump to content

All Activity

This stream auto-updates     

  1. Yesterday
  2. Bonsoir, Ben non, pas besoin d'une référence à la valeur d'une rubrique. En mode modèle, vous sélectionnez le bouton, puis dans l'inspecteur, Masquer l'objet avec une formule du style Obtenir (ModeFenêtre <> 1) pour masquer le bouton sauf en mode recherche, votre 1er message, ou Obtenir (ModeFenêtre > 0) pour masquer le bouton quand vous passez en mode recherche, votre deuxième message. MasquerBouton.fmp12.zip
  3. Bonsoir, J'ai recommencé avec un seul planning mais je n'y arrive pas. Je joins mon fichier, peux-tu me dire ce qui ne va pas ? Merci d'avance, MG 07_Planning Absences & Astreintes.fmp12
  4. L’un d’entre-vous aurait-il une solution pour ce problème ? merci d’avance.
  5. Bonjour à tous j'ai un script qui marche tres bien sur client. Je prends une photo que je stock et je la transfert via l'API DROPBOX ( merci d'ailleurs de m'avoir aider l'autre jour ;-) ) Mon soucis est que parfois ma connexion est lente et je me demande s'il y a pas moyen de faire exécuter le script par mon serveur qui lui est en RJ45 contrairement à mon ipad qui lui est en WIFI mais qui bouge dans la journée donc qui à des perte de qualité wifi. un avis la dessus svp ?
  6. Bonjour, Je suis confronté à une difficulté de rédaction de script. J'ai conçu une base assez complexe pour gérer les inscriptions de personnes à mes stages de formation. Il y a 4 tables qui dialoguent entre elles. J'ai un modèle d'attestation de stage généré en automatique, que j'envoie ensuite manuellement par mail. Je souhaite simplifier ma procédure en créant un script qui : - transforme l'attestation en PDF - génère un mail en allant prendre l'email de la personne - envoie le mail (dont le texte est saisi au préalable dans une rubrique) avec l'attestation PDF en PJ Je sais que c'est faisable, mais je n'arrive plus à rédiger le script. Quelqu'un a cela en stock ? Merci d'avance ! Pour infos, je travaille sur la version 12.
  7. Bonjour et merci d'avoir pris le temps de me répondre. Sauf erreur de ma part, Inspecteur -> Masquer objet quand... est sous condition de la valeur d'une rubrique. Non ? Ou alors je ne sais pas comment m'y prendre pour masquer le bouton lorsque je passe en mode recherche. C'est pour cela que je pensais que l'on pouvais le faire via un script. Si tu as une piste, je suis preneur. Par avance, merci François
  8. Bonjour, Pas tant un script qu'un paramétrage de l'objet. Inspecteur -> Masquer l'objet quand…
  9. Bonjour, Comment puis-je faire pour créer un publipostage à partir d'une table FileMaker ? Je suis assez newbie et j'aimerais pouvoir créer des invitations pour une liste d'événements/enregistrements. Merci de votre aide précieuse. Bonne journée, Abécé
  10. Bonjour, Est-il possible de réaliser un script pour afficher un bouton uniquement en mode recherche ? Si oui, quelle est la marche à suivre ? Par avance merci pour vos réponse. François
  11. OK merci, j'essaye et te tiens informé
  12. sergebo

    bouton et image SVG

    Bonjour Messieurs bonne fêtes de Pâques J'ai fais un programme avec des boutons dont j'ai importé des dessins SVG je recommence un programme et j'ai plus mes dessins. Y a t'il un autre moyen de de tous les rentrés un à un Salutations
  13. Bonjour il y a des éléments qui fonctionnent quand 17 donc il faut tout refaire en 16 le programme car aucune importation vers la 16 n'est possible.
  14. Donc, il ne te faut qu'un calendrier par personne dans lequel tu indiques pour chaque jour les heures d'absences et les heures d'astreintes. Et c'est tout.
  15. Pour chaque personne je calcule les jours et heures d'absences (planning absences) et les jours et heures d'astreinte (planning astreintes) Cela permet de mettre une personne en astreinte (permanence agence par exemple) en ayant sous les yeux ses disponibilités (planning absences) Souvent, l'astreinte ne dure que quelques heures
  16. Bonjour, Je ne comprend pas ce que tu cherches à faire, le mieux que tu me décrives par écrit ton besoin. J'ai surtout besoin que tu me définisses précisément ce que tu entends par astreinte : des heures dans une journée ou l'occupation d'une journée ou encore une période comme les absences.
  17. En ce qui concerne le Menu, ce n'est qu'une image provisoire pour une solution que je réalise pour mon frère. En fait, il faut voir chaque ligne comme un lien vers le module (un sous-menu) qui comprendra les liens vers les tables et modèles de ce module. Dans mon menu principal, il y a déjà des liens vers de modèles formulaires, listes et impressions (le modèle impression sert également pour l'export en pdf). Ce n'est qu'une ébauche Ce que j'ai déjà réalisé, ce sont les modules Contacts, Courrier, Produits et Facturation. Facturation étant plus complexe à réaliser que Devis, il me permettra de créer plus facilement ce dernier ainsi que Bon de livraison. Historique et Tâches sont complémentaires. L'un représente ce qui est fait (Historique) et l'autre (Tâches) ce qui reste à faire. Par exemple, pour traiter un client à 100%, il faut (1) le contacter ou être contacté, (2) faire un devis et suivre ce devis, (3) Obtenir une commande du client, vérifier le stock, voire faire une commande aux fournisseurs et réceptionner les marchandises, (4) Faire la livraison, (5) faire la facture et la suivre jusqu'au payement. Le dépassement de l'échéance amenant à la création d'un rappel. Chaque tâches correspond à 20% du travail à effectuer (puisqu'il y a 5 tâches). Dès que la première tâche est effectué, elle entraine la création des 4 autres qui s'affichent dans un tableau de bord sous la forme de voyants rouges devant passer au vert. Le passage au vert crée une ligne dans l'historique du client qui possèdera en outre un voyant orange suivi du pourcentage réalisé pour signaler que le traitement n'est pas terminé.
  18. Bonjour tout le monde, Le nouveau site de la FM Conférence est en ligne : tout beau, tout neuf pour l'édition 2019 (ça rime !) Nous vous retrouvons du mercredi 16 au vendredi 18 octobre 2019 au Novotel Poitiers Site du Futuroscope, à deux pas du parc donc. La phase d'appel à sujets a commencé, suivez ce lien si vous souhaitez devenir un·e super intervenant·e de la FMConf : https://www.fmconf.com/#appel-a-sujets Les programmes de la journée de formation Design UI/UX et des topos/sessions seront disponibles en juin, en même temps que l'ouverture des inscriptions. N'hésitez pas à laisser un commentaire sous cette publication si vous avez des questions. Le forum est fait pour ça. 🙂 Je vous souhaite une très (très très) belle journée ensoleillée.
  19. Merci pour cette réponse, Puimoisson04. Tu n'es pas un rabat-joie. J'ai toujours été convaincu qu'il y en avait plus dans deux bêtes têtes que dans une seule. L'avantage de réinventer l'eau tiède c'est d'obtenir un autre regard moins "dans les normes". Ce que j'entends par "données temporaires" et non "liens temporaires", c'est que si le lien entre deux tables Produits et Factures est bien permanent (par exemple les rubriques Produit et Article) les données des rubriques (la pain n'est pas du boudin), elles, peuvent changer, donc elles sont bien temporaires. D'où l'intérêt du copier-coller dans des rubriques multivaluées qui sauvegarderont d'une manière définitive les résultats changeant des données résultants de rubriques de calculs et autres. Dans l'exemple : On voit les colonne PV M2 HT, PV Colis HT, M2, Sous-total HT qui sont tous des calculs, mais ce n'est qu'une apparence. En réalité, hormis le formatage (nombre décimal ou devise) ce ne sont que des nombres issus du travail de la ligne supérieure qui, bien entendu, change en fonction du contenu de l'Article à traiter. Tu dis que les rubriques multivaluées sont difficiles à traiter. En fait ce sont des rubriques comme les autres sauf qu'elles possèdent un numéro Article[1, 2, etc]. Comme ces numéros ne sont qu'une variable. On peut faire appel à un script pour faire référence à une partie bien précise de la rubrique multivaluée. Article[1, 2, etc] peut devenir Article[Facturation::FLigne] Ce n'est pas si compliqué ,en somme, sauf si on est réfractaire aux scripts. L'avantage des rubriques multivaluées comme ici (10 lignes et 8 rubriques), c'est surtout de n'avoir à définir que 8 rubriques au lieu de 80. Je ne vois pas d'intérêt à créer 4 tables quand 2 suffisent. Le tout est de trouver une solution pérenne qui fonctionne. La mienne fonctionne. Je fais le copier-coller à travers un script que j'exécute grâce au bouton Copier-coller dans la ligne après avoir sélectionner le numéro de la ligne. Ce serait critiquable, bien entendu, si je le faisais entièrement manuellement. Aucune fonction n'est méprisable (le copier-coller) puisqu'elle a été créée pour être utilisée. C'est pareil pour les rubriques multivaluées, méprisées à tort. "La fonction crée l'organe" et la rubrique multivaluée est née. Elle aura un bel avenir si on l'utilise, sinon on sera condamné à utiliser des tables supplémentaires 😜 L'idée que je me fais d'une facture, c'est qu'elle doit être archivée telle qu'elle a été rédigée. D'où l'intérêt de l'usage de rubriques, multivaluées ou pas, qui ne font pas appel aux données d'une autre table autrement que pour la rédaction. Que ce passe-t-il pour la facture archivée si un contact change d'adresse ou si un article change de prix ? Le facture archivée doit rester inchangée. Puimoisson04, je crois deviner à travers tes propos que tu adhères au projet collectif Solution pour entreprise. Je me trompe ? Si tu es partant, comment pourrions nous articuler ce projet dans le forum afin de motiver les membres de ce forum à y participer ? J'aime bien l'idée de mon menu qui permet d'envisager l'ensemble des tables et des modèles à créer. Chacun pourrait apporter sa pierre à l'édifice à travers un module de sa propre création. Bien entendu les discussions seront âpres (chacun voit midi à sa porte), mais on devrait bien finir par s'entendre, car nous sommes tous raisonnables et démocrates. Pour vos copies d'écran utilisez https://www.zupimages.net/ C'est anonyme et gratuit
  20. Importing data in a FileMaker database from a “flat file” Importing data can be easy when doing it table after table, with well structured data; but what about importing a “flat file”, where data destined to be put in different tables are mixed? Let’s take a simple FileMaker database, where companies are linked to multiple contacts. Here is a simple “company” record, linked to a contact in a portalIn order to have this kind of layouts, the relationship between the companies and the contacts is set up so that the foreign key IdCompany in the Contacts table is linked to the primary key IdCompany in the Companies table. Relationship between companies and contacts in the FileMaker graphWe now need to import in this database an Excel file structured like the following one: 1 column with data from the company, the 2 following ones with data from the contactIn this file, data from the companies AND from the contacts have been written on the same lines; however, we need to separate these data in our relational database. It could still be possible to import the file table by table; but in that case, it would also create duplicate companies (when the same company is linked to different contacts), and the link between the companies and the contacts would be lost. A solution to that would be to create a new table then, only used for the import, that would have the exact same fields as in the original Excel flat file. A simple import (File > Import Records > File… ) can then be used. Normal import processWe can now create a new point of view in our relationships graph, using an occurrence based on this import table. As we plan to create companies and contacts records from this point of view, we will create a new global text field in the current “Import” table (that we will call “GlobalUniqueText” here); this field will be reset each time that we will handle a new record. On the other end, in both the Company and Contact tables, we will create a “Creation” field; this field will only be used for the creation by link. The links between the Import table and the 2 tables where records will be created have to be set between the GlobalUniqueText field and the Creation field, and the creation by link has to be checked. For each record, a new random, unique UUID value will be set into the GlobalUniqueText field; by doing this, the link between the Import table and the 2 other tables will be reset. When values will be set in the 2 other tables, the records will then automatically be created, thanks to the checked option to create records by link. left : The new “import” point of view | right : “Allow creation of records in this table via this relationship”The script used to create data from the Import table in the 2 other tables can now be created. The detail of this process is described in the comments of the script: Script used to distribute data from the “flat file” import table into the tables used in the databaseIn the end, the companies and contacts records are created, and the link between these new records is conserved. This method can be applied to a greater scale, with a lot of different columns going to a lot of different tables in you FileMaker database, but the principle stays the same: create your temporary import table that matches to your Excel flat file, and re-process, adapt and distribute your data, field by field, in your own tables. Leave a comment below if you have any question! Importing data in a FileMaker file from a “flat file” was originally published in Lesterius on Medium, where people are continuing the conversation by highlighting and responding to this story. Afficher la totalité du billet
  21. Bonjour, Je vais jouer les rabat-joie, attention, vous êtes sur une pente glissante. Le diable se cachant dans les détails, il y a plusieurs éléments qui risquent de vous poser des problèmes. - Je ne sais pas ce que vous entendez par liens "temporaire" ? Quelque soit la structure adoptée, vous devez travailler avec des identifiants uniques pour chaque enregistrement d'une table et des liens permanents entre ces identifiants (c'est le principe même de ce type de base de données). - Comme déjà dit, au moins pour les devis et les factures, il vous faut deux tables, une pour les devis et factures eux-mêmes et pour les lignes de ce devis ou facture, toute autre structure se révèlera vite ingérable. - Sauf cas très particulier (a priori absent d'une simple solution facturation), éviter les rubriques multivaluées difficiles à gérer (les liens entre tables sont là pour s'en passer). - Pour définir les valeurs d'une table à partir d'une autre table (et bon nombre d'autres "d'opérations" du "mécanisme" devis/facturation), il existe des solutions plus évoluées et plus "légères" que les simples copier/coller. - … Bref, à moins que vous ne vouliez réinventer l'eau tiède, vous gagnerez probablement du temps (et de l'efficacité/sûreté) en prenant le temps d'assimiler quelques principes de base avec un tutoriel (voir le cqfd par exemple, bien suffisant pour ces éléments de base). Le forum sera là si vous avez des difficultés particulières. Et pour répondre plus précisément, dans votre liste des tables, pour le seul aspect devis/factures, il vous faudra au minimum des tables Contacts, Devis, LignesDeDevis, Facture, LignesDeFacture, Produits. Perso., je commencerai par mettre en place ce premier "chantier", auquel se grefferont ensuite les autres éléments.
  22. Bonjour, Je reviens sur ce fichier. Je l'ai adapté à ma base pour qu'apparaissent l'un sous l'autre pour chaque personne deux plannings (absences et astreintes). Tout se passe bien pour les absences et grâce à ton aide je peux afficher les heures effectuées par jour. Mais je n'arrive pas à faire de même pour les astreintes. Je n'arrive d'ailleurs pas à afficher le mois complet pour les astreintes. Comme je ne vois pas l'erreur, je me permets de te joindre mon fichier en espérant que tu pourras m'aider encore. Merci d'avance, MJG 07_Planning Absences & Astreintes.fmp12
  23. Merci, Apophis, pour ta réponse. En fait, c'est justement en pensant à utiliser une 3ème table que j'ai compris qu'il n'y avait aucun lien entre les colonnes d'une ligne de rubriques multivaluées. Il n'y a qu'un seul lien qui compte, c'est celui qui unit deux tables, et celui-ci est temporaire. Voici la solution que j'ai adopté : En dehors des colonnes de rubriques multivaluées, j'ai crée autant de rubriques simple de travail qui elles sont temporaires. Et je copie-colle chaque ligne de résultat dans les colonnes de rubriques multivaluées grâce à un script très simple piloté par une liste de valeurs (1, 2, 3, 4, etc). Voici le script pour la colonne Article : J'aime bien cette solution parce qu'elle a l'avantage de stocker de manière définitive les données d'une facture. Autre avantage : les données sont permanentes et ne dépendent pas d'une modification des prix ou du coefficient. Ce qui est fondamental pour l'archivage des factures. J'ai encore du boulot, voici les tables et les modèles à réaliser. D'autres s'y rajouteront sans doute. Qu'en penses-tu, Apophis ? Je réaliserais bien le même projet, mais simplifié, pour servir de modèle à ceux qui ont besoin d'une solution pour entreprise. Je signale que je ne suis pas un professionnel et que je fais ça bénévolement pour meubler le temps de ma retraite. Ceux qui veulent se joindre à moi pour le réaliser sont le bienvenus.
  24. Last week
  25. Bonjour Il faut plutôt utiliser un troisième table ( ligne de facture ) et la mettre dans la facture par une table externe.
  26. Lesterius recently published the myFMApiLibrary for PHP. The myFMApiLibrary for PHP is a REST client library for PHP that allows you to easily interact with the FileMaker Data API and integrate it faster. But how do you use it? In this article I will show you how I use it with Symfony 3.4, a popular Web Application framework based on a set of PHP Components. Feel free to improve it. Prerequisites This article assumes that you already have experience with Symfony. Before using the DataApi from FileMaker, make sure that your FileMaker Server has a proper SSL certificate installed. First you need to get the library using composer: composer require myfmbutler/myfmapilibrary-for-php You will also need JMS serializer library (follow documentation found here) and doctrine annotations to be able to link FileMaker fields with your PHP properties: composer require jms/serializer composer require doctrine/doctrine-bundle Then create 4 parameters in parameters.yml file: database_api_url, database_name, database_user and database_password. Create services Now that everything is fine, we’ll create 2 services in services.yml: One to set the myFMAPI library The other one to set-up the Event Subscriber. The first one needed is used to set-up the myFMAPI library: Lesterius\FileMakerApi\DataApi: arguments: ['%database_api_url%','%database_name%', null, null, true] The second one is used to set-up the connection to the DataApi to be able to use our first service: AppBundle\EventSubscriber\RequestEventSubscriber: arguments: ['@Lesterius\FileMakerApi\DataApi', '%database_user%', '%database_password%'] Here follows the class RequestEventSubscriber.php that must be put in src/AppBundle/EventSubscriber repository: <?php namespace AppBundle\EventSubscriber; use Lesterius\FileMakerApi\DataApi; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; class RequestEventSubscriber implements EventSubscriberInterface { /** * @var string */ private $apiUser; /** * @var string */ private $apiPassword; /** * @var DataApi */ private $dataApi; public function __construct(DataApi $dataApi, string $apiUser, string $apiPassword) { $this->apiUser = $apiUser; $this->apiPassword = $apiPassword; $this->dataApi = $dataApi; } /** * Returns an array of event names this subscriber wants to listen to. * * The array keys are event names and the value can be: * * * The method name to call (priority defaults to 0) * * An array composed of the method name to call and the priority * * An array of arrays composed of the method names to call and respective * priorities, or 0 if unset * * For instance: * * * array('eventName' => 'methodName') * * array('eventName' => array('methodName', $priority)) * * array('eventName' => array(array('methodName1', $priority), array('methodName2'))) * * @return array The event names to listen to */ public static function getSubscribedEvents() { return [ KernelEvents::REQUEST => ['apiLogin'] ]; } /** * @param GetResponseEvent $event * * @throws \AppBundle\Service\FileMakerApi\Exception\Exception */ public function apiLogin(GetResponseEvent $event) { if (is_null($this->dataApi->getApiToken())) { $this->dataApi->login($this->apiUser, $this->apiPassword); } } } Create entities With the old FileMaker Php library I used to create a table with the field names and the property names. In Symfony, I can use annotations to link fields with properties. An example of using annotationsUsually you need a lot of entities. I think it is best to make an abstract class for all of them. In this class, I create methods to manage the internal FileMaker id and to get the field names found in FileMaker. Here follows my AbstractEntity.php in src/AppBundle/Entity: <?php namespace AppBundle\Entity; use Doctrine\Common\Annotations\AnnotationReader; use JMS\Serializer\Annotation as Serializer; use Symfony\Component\Serializer\Normalizer\DataUriNormalizer; /** * Class AbstractEntity * * @package AppBundle\Entity */ abstract class AbstractEntity { /** * @Serializer\SerializedName("recordId") * @Serializer\Type("integer") * @Serializer\Groups({"internal"}) */ public $idRecordFileMaker; /** * @Serializer\SerializedName("modId") * @Serializer\Type("integer") * @Serializer\Groups({"internal"}) */ public $idModificationFileMaker; const SEPARATOR = "\r"; /** * @return int */ public function getInternalFmId() { return $this->idRecordFileMaker; } /** * @param int $idRecordFileMaker */ public function setInternalFmId($idRecordFileMaker) { $this->idRecordFileMaker = $idRecordFileMaker; } /** * Get the name of Annotation Name with the property name * * @param $name * @return mixed * @throws \Doctrine\Common\Annotations\AnnotationException * @throws \ReflectionException */ public static function getSerializedNameByPropertyName($name) { $reflectionClass = new \ReflectionClass(get_called_class()); $property = $reflectionClass->getProperty($name); $annotationReader = new AnnotationReader(); $classAnnotations = $annotationReader->getPropertyAnnotation( $property, 'JMS\Serializer\Annotation\SerializedName' ); return $classAnnotations->name; } } Now in my entity, I’ll need to use: use Doctrine\ORM\Mapping as ORM; use JMS\Serializer\Annotation as Serializer; Every class that extends the AbstractEntity Class will need an “IdNameClass” property. The name of the property must start with “id”, followed by the name of the class in camel case, otherwise it will not work. As an example if I have Class Attendee, I’ll need a property with the name $idAttendee. Next, I’ll put my FileMaker field names in “Serializer\SerializedName” annotations. In “Serializer\Type” we store the data type. Here‘s the types you can find: int string Datetime (with UTC format) boolean In “Serializer\Groups” you define the actions that can be done on the field: create update internal excluded default These groups are managed in the AbstractRepository class. The “default” group is set if you didn’t define it. The group will be used when needed, in a “create” case to insert some data you choose not to update, or in an “internal” case where you only need to retrieve data (i.e. modification timestamps). A example of using Types and GroupsCreating Repositories You need to create a repository for your entity. Like entities, I made a AbstractRepository to simulate a database call, similar to what I did for Doctrine. For my own reading comfort I prefer writing all my database functions in my repositories files. An example of repository with a script call and an upload to container instructionA simple example of findByA complexe example of findBy with OMITHere follows my AbstractRepository.php in src/AppBundle/Repository: <?php namespace AppBundle\Repository; use JMS\Serializer\SerializationContext; use JMS\Serializer\SerializerBuilder; use Lesterius\FileMakerApi\DataApi; use Psr\Http\Message\ResponseInterface; abstract class AbstractRepository { const SORT_ASC = 'ascend'; const SORT_DESC = 'descend'; const BIG_RANGE_VALUE = '10000'; const OMIT = 'omit'; protected $em; protected $entityName; protected $layout; protected $serializer; /** * AbstractRepository constructor * * @param DataApi $em * @param $entityName */ public function __construct(DataApi $em, $entityName, $layout) { $this->em = $em; $this->entityName = $entityName; $this->layout = $layout; } /** * Get entity name * * @return mixed */ protected function getEntityName() { return $this->entityName; } /** * Hydrate a list of Objects * * @param array $data * * @return array * @throws \Exception */ protected function hydrateListObjects(array $data) { $list_objects = []; foreach ($data as $record) { $list_objects[] = $this->hydrateObject($record); } return $list_objects; } /** * @param array $data * * @return object * @throws \Exception */ protected function hydrateObject(array $data) { $data = $this->prepareDataForObject($data); if (is_null($this->serializer)) { $this->serializer = SerializerBuilder::create()->build(); } //-- $object = $this->serializer->deserialize(json_encode($data), $this->getEntityName(), 'json'); return $object; } /** * * @param array $data * * @return array * @throws \Exception */ private function prepareDataForObject(array $data) { $result = []; $result['recordId'] = (isset($data['recordId']) ? $data['recordId'] : null); $result['modId'] = (isset($data['modId']) ? $data['modId'] : null); if (isset($data['fieldData'])) { $result = array_merge($result, $data['fieldData']); if (isset($data['portalData']) && !empty($data['portalData'])) { $result = array_merge($result, $data['portalData']); } }else { $result = array_merge($result, $data); } return $result; } /** * Search by Array * * @param array $criterions * @param array $sortArray * * @param null $offset * @param null $range * @param null $portal * * @return array|Object * @throws \Exception */ public function findBy(array $criterions = [], array $sortArray = [], $offset = null, $range = null, $portal = []) { $sort = null; $preparedQuery = $this->prepareFindCriterions($criterions); if (!empty($sortArray)) { foreach ($sortArray as $fieldName => $sortOrder) { $sort[] = ['fieldName' => $fieldName, 'sortOrder' => $sortOrder]; } } if (is_null($range)) { $range = self::BIG_RANGE_VALUE; } $results = $this->em->findRecords($this->layout, $preparedQuery, $sort, $offset, $range, $portal); $return = $this->hydrateListObjects($results); return $return; } /** * Find All records * * @return array * @throws \Exception */ public function findAll() { $results = $this->em->getRecords($this->layout); $return = $this->hydrateListObjects($results); return $return; } /** * Search by ID * * @return Object|array * @throws \Exception */ public function find($idObject) { $propertyName = 'id'.str_replace('AppBundle\Entity\\', '', $this->entityName); $annotationName = call_user_func($this->entityName.'::getSerializedNameByPropertyName', $propertyName); $criterions = $this->prepareFindCriterions([$annotationName => $idObject]); $results = $this->em->findRecords($this->layout, $criterions); $return = $this->hydrateListObjects($results); if (isset($return[0])) { return $return[0]; } return null; } /** * * Create objet * * @param $object * * @return object * * @throws \Exception */ public function create($object) { if ($object instanceof $this->entityName) { $serializer = SerializerBuilder::create()->build(); $data = $serializer->serialize($object, 'json', SerializationContext::create()->setGroups(['Default', 'create'])); $data = json_decode($data, true); $recordId = $this->em->createRecord($this->layout, $data); if ($recordId instanceof ResponseInterface) { throw new \Exception('Error, creation fail : '.$recordId); } $results = $this->em->getRecord($this->layout, $recordId); $return = $this->hydrateObject($results); return $return; } throw new \Exception('Error, object is not a instance of the object repository'); } /** * Edit object * * @param $object * * @param array $scripts * @return object * * @throws \AppBundle\Service\FileMakerApi\Exception\Exception * @throws \Exception */ public function set($object, $scripts = []) { if ($object instanceof $this->entityName && !empty($object->{'getInternalFmId'}())) { $serializer = SerializerBuilder::create()->build(); $data = $serializer->serialize($object, 'json', SerializationContext::create()->setGroups(['Default', 'update'])); $data = json_decode($data, true); $modId = $this->em->editRecord($this->layout, $object->{'getInternalFmId'}(), $data, null, [], $scripts); if ($modId instanceof ResponseInterface) { throw new \Exception('Error, update fail : '.$object->{'getInternalFmId'}()); } $results = $this->em->getRecord($this->layout, $object->{'getInternalFmId'}()); $return = $this->hydrateObject($results); return $return; } throw new \Exception('Error, object is not a instance of the object repository'); } /** * @param $object * @param array $fileOption * @param int $repetition * @return object * @throws \AppBundle\Service\FileMakerApi\Exception\Exception * @throws \Exception */ public function setFile($object, $fileOption = [], $repetition = 1) { if ($object instanceof $this->entityName && !empty($object->{'getInternalFmId'}()) && !empty($fileOption)) { foreach ($fileOption as $fieldName => $filePath) { $modId = $this->em->uploadToContainer($this->layout, $object->{'getInternalFmId'}(), $fieldName, $repetition, $filePath); if ($modId instanceof ResponseInterface) { throw new \Exception('Error, update fail : '.$object->{'getInternalFmId'}()); } } $results = $this->em->getRecord($this->layout, $object->{'getInternalFmId'}()); $return = $this->hydrateObject($results); return $return; } } /** * @param array $criterions * * @return array */ private function prepareFindCriterions(array $criterions) { $preparedCriterions = []; foreach ($criterions as $index => $criterion) { if (is_array($criterion)) { $fields = []; foreach ($criterion as $field => $value) { $fields[] = ['fieldname' => $field, 'fieldvalue' => $value]; } $preparedCriterions[]['fields'] = $fields; } else { $fields[] = ['fieldname' => $index, 'fieldvalue' => $criterion]; } } if (empty($preparedCriterions) && !empty($criterions)) { $preparedCriterions[]['fields'] = $fields; } return $preparedCriterions; } /** * @return DataApi */ public function getEm(): DataApi { return $this->em; } /** * @param DataApi $em */ public function setEm(DataApi $em) { $this->em = $em; } /** * @return mixed */ public function getLayout() { return $this->layout; } /** * @param mixed $layout */ public function setLayout($layout) { $this->layout = $layout; } /** * @return mixed */ public function getSerializer() { return $this->serializer; } /** * @param mixed $serializer */ public function setSerializer($serializer) { $this->serializer = $serializer; } } How to use it? I created 2 functions in my BaseController.php: one to call the myFMApiLibrary-for-PHP service and connect to the database. one to close the connection (don’t forget this part!). Then in my controller, I can create my repository object and my object: An example of using with a creation, an upload to container and a script executionWhat about error messages? The error messages you could have should be explicit (and with their FileMaker error code). DataApi works the same way as another FileMaker Client. As an example, two users can’t edit the same record at the same time, and will throw an error. Conclusion Follow these steps, and you will be able to easily connect your Symfony to the FileMaker 17 DataAPI (with myFMApiLibrary for PHP), and significantly save your work time, which is good for you, but event better for your clients! What were your thoughts on this tutorial? Please let me know in the comments. Don’t forget to subscribe to follow our reviews and updates of this article once the FileMaker 18 DataAPI will be released. Some Tips If you choose “int” as “Serializer\Type” annotation, be sure the field is always filled. “Empty” is not an int or a boolean, change to “string” to avoid this. @Serializer\Type(“DateTime<’m/d/Y’, ‘Europe/Paris’>”) can be @Serializer\Type(“DateTime<’m/d/Y H:i:s’, ‘Europe/Paris’>”), for example. If you don’t put @Serializer annotation, the property won’t be linked to FileMaker. And please, don’t forget to set stricter privileges to your DataApi user for more security. How I integrated myFMApiLibrary for PHP with Symfony 3.4 was originally published in Lesterius on Medium, where people are continuing the conversation by highlighting and responding to this story. Afficher la totalité du billet
  27. Je vous remercie pour votre travail. cerait-il cependant possible de remplacer le bouton d’ajout (crayon), situé dans la TE PERSONNEL, par une case à cocher, histoire de savoir ce qui a déjà été ajouté et qui ne l’est pas encore. en tous les cas merci une fois encore pour votre aide. amicalement
  1. Load more activity
×
×
  • Create New...